2017-02-16 8 views
0

У меня есть список примерно 400 тыс. IP (хранится в pandas DataFrame df_IP) для геолокации с использованием базы данных maxming geoIP. Я использую версию City, и я извлекаю город, длину волны, долготу и код графства (департамент во Франции), потому что некоторые города имеют одно и то же имя, но находятся в самых разных местах.Ускорьте данные. Loc()

Вот мой рабочий код:

import geoip2.database 
import pandas as pd 

reader = geoip2.database.Reader('path/to/GeoLite2-City.mmdb') 
results = pd.DataFrame(columns=('IP', 
           'city', 
           'latitude', 
           'longitude', 
           'dept_code')) 

for i, IP in enumerate(df_IP["IP"]): 
    try : 
     response = reader.city(IP) 
     results.loc[i] = [IP,response.city.name,response.location.latitude,response.location.longitude,response.subdivisions.most_specific.iso_code] 
    except Exception as e: 
     print ("error with line {}, IP {}: {}").format(i,df_IP["IP"][i],e) 

Он хорошо работает, но она становится все медленнее и медленнее на каждом цикле. Если я нахожу это на 1000 первых IP, я беру 4.7s, поэтому весь 400k займет около 30 минут, но он работает почти 4 часа.

Единственное, что может замедлить со временем IMO, это заполнение Dataframe results: какие у меня альтернативы, которые не используют .loc и могут быть быстрее? В конце концов, мне все равно нужен один и тот же файл.

Мне также будет интересно узнать, почему loc настолько медленный на больших кадрах данных.

+0

вы не задумывались об использовании одного из pandas' итераторов (например, 'iterrows()') перебрать ваши строки и использовать 'применить 'с помощью функции вашего читателя создать один новый столбец со строкой, в которой есть все ваши геоданные? Затем вы можете разбить строки для создания отдельных столбцов для всех ваших геоданных. Не уверен, что это будет быстрее, но при итерации над фреймворком данных обычно лучше использовать что-то вроде 'iterrows()'. – Khris

+0

У меня была аналогичная проблема в прошлом, когда 'loc' был очень медленным, когда в цикле for. Я обнаружил, что могу обойти проблему, создав данные для нового столбца в виде отдельного списка, а затем переназначаю его в этой форме. Это потребовало большего количества строк кода и было немного уродливым, но имело гораздо лучшую производительность, чем 'loc'. Возможно, стоит подумать, можете ли вы применить это. – oliversm

+0

@oliversm вы можете уточнить? Я не понимаю вашего трюка. – CoMartel

ответ

0

У меня была такая же проблема, и как @oliversm предлагает мне создать список, а затем добавить его в исходный набор данных. Вот что код будет выглядеть следующим образом:

....

results_list=[] 

for i, IP in enumerate(df_IP["IP"]): 
    try : 
     response = reader.city(IP) 
    results_list.append(response.city.name,response.location.latitude,response.location.longitude,response.subdivisions.most_specific.iso_code) 
    except Exception as e: 
     print ("error with line {}, IP {}: {}").format(i,df_IP["IP"][i],e) 

results_array=np.asarray(results_list) #list to array to add to the dataframe as a new column 

results['results_column']=pd.Series(results_array,index=results.index) 
0

я столкнулась с подобной ситуацией, как LOC причинял среду выполнения, чтобы взорвать для меня. После многочасовой игры я нашел простое решение, которое было очень быстрым. Используйте set_value вместо loc.

Вот как будет выглядеть пример кода: вы можете настроить его для своего использования. Предположим, что ваш dataframe подобен этому

Index 'A' 'B' 'Label' 
23  0 1 Y 
45  3 2 N 

self.data.set_value(45,'Label,'NA') 

Это установит значение столбца «LABEL» как NA для второго ряда.

Подробнее о set_value можно прочитать по ссылке ниже:

http://pandas.pydata.org/pandas-docs/version/0.17/generated/pandas.DataFrame.set_value.html

Смежные вопросы