У меня огромный dataframe. Структура данных выглядит так:

df
ID  Annotation  X           Y
A   Boarding    767513.9918 9425956.2571
A   Alighting   767154.1396 9427584.0004
B   Boarding    767450.5277 9432627.9543
B   Alighting   767495.0101 9426797.1772
C   Boarding    767648.9507 9426442.5497
C   Alighting   767037.0309 9428878.9032
........

Данные X и Y использовали координаты UTM. Я хочу рассчитать расстояние между каждым посадочным талоном и посадкой. Мой вопрос тихо похож, но отличается от этого вопроса (Матрица расстояний в Python Pandas). Мой ожидаемый результат выглядит так:

result
ID  Anotation_1 X_1         Y_1         Anotation_2 X_2         Y_2      Dist
A   Boarding    767513.99   9425956.26  Alighting   767154.14   9427584.00  1667.05
B   Boarding    767450.53   9432627.95  Alighting   767495.01   9426797.18  5830.95
C   Boarding    767648.95   9426442.55  Alighting   767037.03   9428878.90  2512.02
    .......

Спасибо за вашу помощь.

0
Arief 27 Июн 2019 в 11:14

3 ответа

Лучший ответ

Одним из способов решения этой проблемы, предполагая, что ввод является чистым и правильным , было бы использование groupby:

df = df.groupby('ID').apply(lambda x: pd.Series(x.values[0:2,2:4].flatten()))  # (*)
df.columns=['X_1','Y_1','X_2','Y_2']
#df.reset_index()  # Uncomment if you want 'ID' as a column and not an Index

Что касается других столбцов в желаемом результате: Anotation_1 и Anotation_2 всегда постоянны, поэтому я не стал их включать. Столбец Dist - ну, вы можете вычислить его сейчас, учитывая новые столбцы, или вы можете изменить код выше, чтобы вычислять расстояние уже при обходе чисел в шаге (*) выше, тем самым изменяя наш код для чего-то вроде: (здесь используется фиктивный расчет расстояния, замените его на свой!)

def my_func(pdf):
    return pd.Series([pdf.values[0,2], pdf.values[0,3], pdf.values[1,2], pdf.values[1,3],
                      np.sqrt((pdf.values[0,2]-pdf.values[1,2])**2+(pdf.values[0,3]-pdf.values[1,3])**2)  # <= your distance calculation goes here...
                     ])
df = df.groupby('ID').apply(my_func)
df.columns=['X_1','Y_1','X_2','Y_2','Dist']
#df.reset_index()  # Uncomment if you want 'ID' as a column and not an Index

Обновление: если вы настаиваете на включении этих константных столбцов, вы можете просто добавить их позже, например так: ( но зачем вам это? Особенно если это большой DataFrame ... )

df['Annotation_1'] = 'Boarding'
df['Annotation_2'] = 'Alighting'
# And if you further insist on a specific ordering of the columns, you can go with:
df = df[['Annotation_1', 'X_1', 'Y_1', 'Annotation_2', 'X_2', 'Y_2', 'Dist']]
1
Yaniv 27 Июн 2019 в 09:19

Я бы развернул датафрейм:

result = df.pivot('ID', 'Annotation', ['X', 'Y'])

Получить

                      X                          Y              
Annotation    Alighting     Boarding     Alighting      Boarding
ID                                                              
A           767154.1396  767513.9918  9.427584e+06  9.425956e+06
B           767495.0101  767450.5277  9.426797e+06  9.432628e+06
C           767037.0309  767648.9507  9.428879e+06  9.426443e+06

Тогда я бы переименовал столбцы и переиндексировал:

ix = result.columns.to_frame()
result.columns = ix['Annotation'] + '_' + ix.iloc[:,0]
result = result.reindex(columns=['Alighting_X', 'Alighting_Y', 'Boarding_X', 'Boarding_Y'])

Получить:

    Alighting_X   Alighting_Y   Boarding_X    Boarding_Y
ID                                                      
A   767154.1396  9.427584e+06  767513.9918  9.425956e+06
B   767495.0101  9.426797e+06  767450.5277  9.432628e+06
C   767037.0309  9.428879e+06  767648.9507  9.426443e+06

Теперь легко вычислить расстояние:

result['Dist'] = np.sqrt((result.Alighting_X - result.Boarding_X)**2 + (result.Alighting_Y - result.Boarding_Y)**2)

Чтобы наконец получить:

    Alighting_X   Boarding_X   Alighting_Y    Boarding_Y         Dist
ID                                                                   
A   767154.1396  767513.9918  9.427584e+06  9.425956e+06  1667.045847
B   767495.0101  767450.5277  9.426797e+06  9.432628e+06  5830.946773
C   767037.0309  767648.9507  9.428879e+06  9.426443e+06  2512.023929
2
Serge Ballesta 27 Июн 2019 в 09:29