Eu gostaria de saber qual é a melhor solução para obter distâncias a partir da API do Google Maps distância para o meu trama de dados composto por coordenadas (origem e destino), que é de cerca de 75k linhas.
#Origin #Destination
1 (40.7127837, -74.0059413) (34.0522342, -118.2436849)
2 (41.8781136, -87.6297982) (29.7604267, -95.3698028)
3 (39.9525839, -75.1652215) (40.7127837, -74.0059413)
4 (41.8781136, -87.6297982) (34.0522342, -118.2436849)
5 (29.7604267, -95.3698028) (39.9525839, -75.1652215)
Até agora o meu código itera através da trama de dados e chama a API copiar o valor da distância para a nova coluna "distância".
df['distance'] = ""
for index, row in df.iterrows():
result = gmaps.distance_matrix(row['origin'], row['destination'], mode='driving')
status = result['rows'][0]['elements'][0]['status']
if status == "OK": # Handle "no result" exception
KM = int(result['rows'][0]['elements'][0]['distance']['value'] / 1000)
df['distance'].iloc[index] = KM
else:
df['distance'].iloc[index] = 0
df.to_csv('distance.csv')
Eu obter o resultado desejado, mas pelo que tenho a iteração leitura através trama de dados é bastante ineficiente e deve ser evitado. Demorou 20 secondes para 240 linhas, de modo que seria necessário 1h30 para fazer tudo trama de dados. Note-se que, uma vez feito, não há necessidade de mais re-run, apenas novos poucas novas linhas por mês (~ 500).
O que seria de nós a melhor solução aqui?
Edit: se alguém tem experiência com a API do Google distância e suas limitações qualquer dicas / melhores práticas é bem-vinda.
Tentei entender sobre quaisquer limitações sobre chamadas simultâneas aqui , mas eu não consegui encontrar nada. algumas sugestões
loops de Evitar
Sobre o seu código Prefiro pular para loops e utilização aplicam-se primeiro
def get_gmaps_distance(row):
result = gmaps.distance_matrix(row['origin'], row['destination'], mode='driving')
status = result['rows'][0]['elements'][0]['status']
if status == "OK":
KM = int(result['rows'][0]['elements'][0]['distance']['value'] / 1000)
else:
KM = 0
return KM
df["distance"] = df.apply(get_gmaps_distance, axis=1)
Dividir a sua trama de dados e uso de multiprocessamento
import multiprocessing as mp
def parallelize(fun, vec, cores=mp.cpu_count()):
with mp.Pool(cores) as p:
res = p.map(fun, vec)
return res
# split your dataframe in many chunks as the number of cores
df = np.array_split(df, mp.cpu_count())
# this use your functions for every chunck
def parallel_distance(x):
x["distance"] = x.apply(get_gmaps_distance, axis=1)
return x
df = parallelize(parallel_distance, df)
df = pd.concat(df, ignore_index=True, sort=False)
Não calcule duas vezes a mesma distância (save $$$)
No caso de ter duplicatas linha que você deve deixar cair alguns deles
grp = df.drop_duplicates(["origin", "destination"]).reset_index(drop=True)
Aqui eu não substituiu df
como ele possivelmente conter mais informações que você precisa e você pode mesclar os resultados a ele.
grp["distance"] = grp.apply(get_gmaps_distance, axis=1)
df = pd.merge(df, grp, how="left")
reduzir decimais
Você deve perguntar-lhe esta pergunta: eu realmente preciso para ser exato para o 7º decimal? Como um grau de latitude é de aproximadamente 111 km a 7ª casa decimal lhe dá uma precisão de até ~ um centímetro. Você começa a idéia deste quando menos-é-mais onde a redução decimais Eles melhoraram o modelo.
Conclusão
Se você pode, eventualmente, usar todos os métodos sugeridos você poderia obter algumas melhorias interessantes. Eu gostaria que você comentasse-los aqui como eu não tenho uma chave de API pessoal para tentar sozinho.