You can generate all pairs you want with pd.merge(how='cross')
:
>>> groups = df.groupby('Feature')
>>> pd.merge(groups.get_group('Car'), groups.get_group('Truck'), how='cross', suffixes=('', '_cmp'))
Id Feature Lat Long Id_cmp Feature_cmp Lat_cmp Long_cmp
0 9 Car 39.57613 46.87570 0 Truck 39.57713 46.87062
1 9 Car 39.57613 46.87570 1 Truck 39.57723 46.87004
2 9 Car 39.57613 46.87570 2 Truck 39.57671 46.87001
3 9 Car 39.57613 46.87570 3 Truck 39.57672 46.87066
4 9 Car 39.57613 46.87570 4 Truck 39.57697 46.87027
5 10 Car 39.57577 46.87572 0 Truck 39.57713 46.87062
6 10 Car 39.57577 46.87572 1 Truck 39.57723 46.87004
7 10 Car 39.57577 46.87572 2 Truck 39.57671 46.87001
8 10 Car 39.57577 46.87572 3 Truck 39.57672 46.87066
9 10 Car 39.57577 46.87572 4 Truck 39.57697 46.87027
10 11 Car 39.57595 46.87545 0 Truck 39.57713 46.87062
11 11 Car 39.57595 46.87545 1 Truck 39.57723 46.87004
12 11 Car 39.57595 46.87545 2 Truck 39.57671 46.87001
13 11 Car 39.57595 46.87545 3 Truck 39.57672 46.87066
14 11 Car 39.57595 46.87545 4 Truck 39.57697 46.87027
This allows to easily generate all comparisons we want to make:
>>> distances = {('Car', 'Truck'): 420, ('Truck', 'Van'): 655, ('Car', 'Van'): 425}
>>> all_cmp = pd.concat([pd.merge(groups.get_group(dist_from), groups.get_group(dist_to), how='cross', suffixes=('', '_cmp')) for dist_from, dist_to in distances])
>>> all_cmp.head()
Id Feature Lat Long Id_cmp Feature_cmp Lat_cmp Long_cmp
0 9 Car 39.57613 46.8757 0 Truck 39.57713 46.87062
1 9 Car 39.57613 46.8757 1 Truck 39.57723 46.87004
2 9 Car 39.57613 46.8757 2 Truck 39.57671 46.87001
3 9 Car 39.57613 46.8757 3 Truck 39.57672 46.87066
4 9 Car 39.57613 46.8757 4 Truck 39.57697 46.87027
>>> all_cmp.tail()
Id Feature Lat Long Id_cmp Feature_cmp Lat_cmp Long_cmp
7 10 Car 39.57577 46.87572 8 Van 39.57197 46.87528
8 11 Car 39.57595 46.87545 5 Van 39.57188 46.87489
9 11 Car 39.57595 46.87545 6 Van 39.57151 46.87482
10 11 Car 39.57595 46.87545 7 Van 39.57153 46.87520
11 11 Car 39.57595 46.87545 8 Van 39.57197 46.87528
We can easily compute the distances and we also need to align the threshold distances:
>>> dist = all_cmp.agg(lambda s: haversine(s['Lat'], s['Long'], s['Lat_cmp'], s['Long_cmp']), axis='columns')
>>> thresh = all_cmp[['Feature', 'Feature_cmp']].agg(lambda s: distances[tuple(s)], axis='columns')
And from there just compare, keep the lines you want, possibly aggregate:
>>> all_cmp[dist < thresh]
Id Feature Lat Long Id_cmp Feature_cmp Lat_cmp Long_cmp
0 0 Truck 39.57713 46.87062 5 Van 39.57188 46.87489
1 0 Truck 39.57713 46.87062 6 Van 39.57151 46.87482
3 0 Truck 39.57713 46.87062 8 Van 39.57197 46.87528
12 3 Truck 39.57672 46.87066 5 Van 39.57188 46.87489
13 3 Truck 39.57672 46.87066 6 Van 39.57151 46.87482
14 3 Truck 39.57672 46.87066 7 Van 39.57153 46.87520
15 3 Truck 39.57672 46.87066 8 Van 39.57197 46.87528
16 4 Truck 39.57697 46.87027 5 Van 39.57188 46.87489
17 4 Truck 39.57697 46.87027 6 Van 39.57151 46.87482
0 9 Car 39.57613 46.87570 5 Van 39.57188 46.87489
1 9 Car 39.57613 46.87570 6 Van 39.57151 46.87482
2 9 Car 39.57613 46.87570 7 Van 39.57153 46.87520
3 9 Car 39.57613 46.87570 8 Van 39.57197 46.87528
4 10 Car 39.57577 46.87572 5 Van 39.57188 46.87489
5 10 Car 39.57577 46.87572 6 Van 39.57151 46.87482
6 10 Car 39.57577 46.87572 7 Van 39.57153 46.87520
7 10 Car 39.57577 46.87572 8 Van 39.57197 46.87528
8 11 Car 39.57595 46.87545 5 Van 39.57188 46.87489
9 11 Car 39.57595 46.87545 6 Van 39.57151 46.87482
10 11 Car 39.57595 46.87545 7 Van 39.57153 46.87520
11 11 Car 39.57595 46.87545 8 Van 39.57197 46.87528
>>> close = all_cmp[dist < thresh].groupby('Id')['Id_cmp'].agg(list)
>>> close
Id
0 [5, 6, 8]
3 [5, 6, 7, 8]
4 [5, 6]
9 [5, 6, 7, 8]
10 [5, 6, 7, 8]
11 [5, 6, 7, 8]
Name: Id_cmp, dtype: object
>>> df.merge(close.rename('within dist').reset_index())
Id Feature Lat Long within dist
0 0 Truck 39.57713 46.87062 [5, 6, 8]
1 3 Truck 39.57672 46.87066 [5, 6, 7, 8]
2 4 Truck 39.57697 46.87027 [5, 6]
3 9 Car 39.57613 46.87570 [5, 6, 7, 8]
4 10 Car 39.57577 46.87572 [5, 6, 7, 8]
5 11 Car 39.57595 46.87545 [5, 6, 7, 8]