I have two tables - Dealers and Customers. For each of the customer location from the customer table, I need to find the closest located dealer from the dealer table.
I have a code that works but takes a few hours to run. I need help in optimizing my solution.
The dealer table has 25k+ rows and customer table has 200k+ rows. Both tables have 3 main columns: (DealerID, Lat, Long) and (CustomerID, Lat, Long). My output looks something like this:
CustomerID | Lat | Long | ClosestDealer | Distance |
---|---|---|---|---|
Customer1 | 61.61 | -149.58 | Dealer3 | 15.53 |
Customer2 | 42.37 | -72.52 | Dealer258 | 8.02 |
Customer3 | 42.42 | -72.1 | Dealer1076 | 32.92 |
Customer4 | 31.59 | -89.87 | Dealer32 | 3.85 |
Customer5 | 36.75 | -94.84 | Dealer726 | 7.90 |
My current Solution: Iterating through all the rows of data to find the min. distance will take too long. To optimize this, I have grouped the data in both tables based on the rounded down version of lat and long points and then added them together to arrive at my final group (see 'LatLongGroup' column below).
CustomerID | Lat | Long | LatGroup | LongGroup | LatLongGroup |
---|---|---|---|---|---|
Customer1 | 61.61 | -149.58 | 61 | -149 | -88 |
Customer2 | 42.37 | -72.52 | 42 | -72 | -30 |
Customer3 | 42.42 | -72.1 | 42 | -72 | -30 |
Customer4 | 31.59 | -89.87 | 31 | -89 | -58 |
Customer5 | 36.75 | -94.84 | 36 | -94 | -58 |
Both these tables are sorted based on the 'LatLongGroup' column. And I have a separate table called group which provides the starting and ending row number of each group for the dealer table. I then match the records in the dealer table which have the same 'Latlonggroup' as that of the customerID. This helps me narrow down the search for the closest dealer.
But sometimes the closest dealer might not fall within the same group so to avoid any pitfalls, I search not only the group that matches but one above and below too. View Currently Used Code
Please let me know what would be the best way to optimize this or is there an easier way to find closest dealers for a large dataset like this. Any direction is greatly appreciated. Thank you!
col_names = ["CustomerKey","DealerKey","Dist"]
df = pd.DataFrame(columns = col_names)
c = 0
for i in range(0,len(df_c)):
print(i)
row = {'CustomerKey':df_c.loc[i,'ZIPBRANDKEY'],'DealerKey':'','Dist':0}
df = df.append(row, ignore_index=True)
a = group[group['LatLongGroup'] == df_c.LatLongGroup[i]].index[0]
if(a-1 >= 0):
start = group.loc[a-1,'Start']
else:
start = group.loc[a,'Start']
if(a+1 < len(group)):
end = group.loc[a+1,'End']
else:
end = group.loc[a,'End']
t1 = 0
for j in range(start,end):
dist = round(geopy.distance.distance(df_c.Lat_long[i], df_s.Lat_long[j]).miles,2)
if(t1 == 0):
min_dist = dist
dealerkey = df_s.loc[j,'DEALER_BRAND_KEY']
t1 = 1
elif(dist < min_dist):
min_dist = dist
dealerkey = df_s.loc[j,'DEALER_BRAND_KEY']
df.loc[c,'DealerKey'] = dealerkey
df.loc[c,'Dist'] = min_dist
c = c+1
df.head()
For reference, the above mentioned group dataframe looks like this:
Group | Start | End |
---|---|---|
-138 | 0 | 7 |
-137 | 7 | 15 |
-136 | 15 | 53 |
-135 | 53 | 55 |
-88 | 55 | 78 |