Nocas
Nocas

Reputation: 397

Haversine Distance between consecutive rows for each Customer

My question kind of builds on this one Fast Haversine Approximation (Python/Pandas)

Basically, that question asks how to compute the Haversine Distance. Mine is how do I calculate the Haversine Distance between consecutive rows for each Customer.

My dataset looks something like this dummy one (let's pretend those are real coordinates):

  Customer  Lat Lon
    A        1  2
    A        1  2
    B        3  2
    B        4  2

So here, I would get nothing in the first row, 0 in the second row, nothing again on the third because a new customer started and whatever the distance in km is between (3,2) and (4,2) in the fourth.

This works without the constraint of the customers:

def haversine(lat1, lon1, lat2, lon2, to_radians=True):
    if to_radians:
        lat1, lon1, lat2, lon2 = np.radians([lat1, lon1, lat2, lon2])

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

    return 6367 * 2 * np.arcsin(np.sqrt(a))

df=data_full
df['dist'] = \
    haversine(df.Lon.shift(), df.Lat.shift(),
             df.loc[1:, 'Lon'], df.loc[1:, 'Lat'])

But I can't tweak it to restart with each new customer. I've tried this:

 def haversine(lat1, lon1, lat2, lon2, to_radians=True):
    if to_radians:
        lat1, lon1, lat2, lon2 = np.radians([lat1, lon1, lat2, lon2])

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

    return 6367 * 2 * np.arcsin(np.sqrt(a))

df=data_full
df['dist'] = \
    df.groupby('Customer_id')['Lat','Lon'].apply(lambda df: haversine(df.Lon.shift(), df.Lat.shift(),
             df.loc[1:, 'Lon'], df.loc[1:, 'Lat']))

Upvotes: 2

Views: 586

Answers (1)

Code Different
Code Different

Reputation: 93141

I'll reuse the vectorized haversine_np function from derricw's answer:

def haversine_np(lon1, lat1, lon2, lat2):
    """
    Calculate the great circle distance between two points
    on the earth (specified in decimal degrees)

    All args must be of equal length.    

    """
    lon1, lat1, lon2, lat2 = map(np.radians, [lon1, lat1, lon2, lat2])

    dlon = lon2 - lon1
    dlat = lat2 - lat1

    a = np.sin(dlat/2.0)**2 + np.cos(lat1) * np.cos(lat2) * np.sin(dlon/2.0)**2

    c = 2 * np.arcsin(np.sqrt(a))
    km = 6367 * c
    return km

def distance(x):
    y = x.shift()
    return haversine_np(x['Lat'], x['Lon'], y['Lat'], y['Lon']).fillna(0)

df['Distance'] = df.groupby('Customer').apply(distance).reset_index(level=0, drop=True)

Result:

  Customer  Lat  Lon    Distance
0        A    1    2    0.000000
1        A    1    2    0.000000
2        B    3    2    0.000000
3        B    4    2  111.057417

Upvotes: 3

Related Questions