От кадра данных pandas до кортежей (для модуля haversine)

У меня есть кадр данных pandas my_df со следующими столбцами:

id  lat1 lon1 lat2 lon2
1   45   0    41   3
2   40   1    42   4
3   42   2    37   1

В принципе, я хотел бы сделать следующее:

import haversine

haversine.haversine((45, 0), (41, 3)) # just to show syntax of haversine()
> 507.20410687342115

# what I'd like to do
my_df["dist"] = haversine.haversine((my_df["lat1"], my_df["lon1"]),(my_df["lat2"], my_df["lon2"]))

TypeError: невозможно преобразовать серию в ‹ class 'float' >

Используя это, я попробовал следующее:

my_df['dist'] = haversine.haversine(
        list(zip(*[my_df[['lat1','lon1']][c].values.tolist() for c in my_df[['lat1','lon1']]]))
        , 
        list(zip(*[my_df[['lat2','lon2']][c].values.tolist() for c in my_df[['lat2','lon2']]]))
        )

Файл "blabla\lib\site-packages\haversine__init__.py", строка 20, в haversine lat1, lng1 = point1

ValueError: слишком много значений для распаковки (ожидается 2)

Любая идея о том, что я делаю неправильно / как я могу добиться того, чего хочу?


person François M.    schedule 12.07.2017    source источник
comment
возможный обман: stackoverflow.com/ вопросы/25767596/   -  person EdChum    schedule 12.07.2017


Ответы (2)


Используйте apply с axis=1:

my_df["dist"] = my_df.apply(lambda row : haversine.haversine((row["lat1"], row["lon1"]),(row["lat2"], row["lon2"])), axis=1)

Чтобы вызвать функцию гаверсинуса для каждой строки, функция понимает скалярные значения, а не значения, подобные массивам, поэтому возникает ошибка. Вызывая apply с axis=1, вы выполняете итерацию по строкам, чтобы затем мы могли получить доступ к каждому значению столбца и передать их в той форме, которую ожидает метод.

Также я не знаю, в чем разница, но есть векторизованная версия формулы гаверсина

person EdChum    schedule 12.07.2017

Как насчет использования векторизованного подхода:

import pandas as pd

# vectorized haversine function
def haversine(lat1, lon1, lat2, lon2, to_radians=True, earth_radius=6371):
    """
    slightly modified version: of http://stackoverflow.com/a/29546836/2901002

    Calculate the great circle distance between two points
    on the earth (specified in decimal degrees or in radians)

    All (lat, lon) coordinates must have numeric dtypes and be of equal length.

    """
    if to_radians:
        lat1, lon1, lat2, lon2 = pd.np.radians([lat1, lon1, lat2, lon2])

    a = pd.np.sin((lat2-lat1)/2.0)**2 + \
        pd.np.cos(lat1) * pd.np.cos(lat2) * pd.np.sin((lon2-lon1)/2.0)**2

    return earth_radius * 2 * pd.np.arcsin(np.sqrt(a))

Демо:

In [38]: df
Out[38]:
   id  lat1  lon1  lat2  lon2
0   1    45     0    41     3
1   2    40     1    42     4
2   3    42     2    37     1

In [39]: df['dist'] = haversine(df.lat1, df.lon1, df.lat2, df.lon2)

In [40]: df
Out[40]:
   id  lat1  lon1  lat2  lon2        dist
0   1    45     0    41     3  507.204107
1   2    40     1    42     4  335.876312
2   3    42     2    37     1  562.543582
person MaxU    schedule 12.07.2017
comment
@fmalaussena, убедитесь, что вы не перезаписали np - псевдоним для numpy каким-то float64 именем переменной. Если вы не используете классический псевдоним numpy np, вы можете использовать либо numpy.radians, либо pd.np.radians - person MaxU; 13.07.2017