2016-07-06 7 views
0

Ich habe die Aufgabe: Ich sollte einige Daten in großer Datei finden und diese Daten zu einer Datei hinzufügen. Datei, wo ich Daten suche ist 22 million string und ich teile es mit chunksize. In einer anderen Datei habe ich Spalte mit 600 id of users und ich finde Informationen über jeden Benutzer in einer großen Datei. Die erste Ich teile Daten auf Intervall und nächste Suche Informationen über jeden Benutzer in all diesen Dateien. Ich benutze timer um zu wissen, wie viel Zeit es verbringen, um in Datei und durchschnittliche Zeit zu schreiben, um Informationen in df Größe 1 million string zu finden und in die Datei schreiben ist 1.7 sec. Und nach der Zählung aller Zeit des Programms bekomme ich 6 hours. (1.5 sec * 600 id * 22 interval). Ich möchte es schneller machen, aber ich weiß keinen Weg neben chunksize. füge ich meinen CodePandas: Wie man Algorithmus schneller macht

el = pd.read_csv('df2.csv', iterator=True, chunksize=1000000) 
buys = pd.read_excel('smartphone.xlsx') 
buys['date'] = pd.to_datetime(buys['date']) 
dates1 = buys['date'] 
ids1 = buys['id'] 
for i in el: 
    i['used_at'] = pd.to_datetime(i['used_at']) 
    df = i.sort_values(['ID', 'used_at']) 
    dates = df['used_at'] 
    ids = df['ID'] 
    urls = df['url'] 
    for i, (id, date, url, id1, date1) in enumerate(zip(ids, dates, urls, ids1, dates1)): 
     start = time.time() 
     df1 = df[(df['ID'] == ids1[i]) & (df['used_at'] < (dates1[i] + dateutil.relativedelta.relativedelta(days=5)).replace(hour=0, minute=0, second=0)) & (df['used_at'] > (dates1[i] - dateutil.relativedelta.relativedelta(months=1)).replace(day=1, hour=0, minute=0, second=0))] 
     df1 = DataFrame(df1) 
     if df1.empty: 
      continue 
     else: 
      with open('3.csv', 'a') as f: 
       df1.to_csv(f, header=False) 
       end = time.time() 
       print(end - start) 

Antwort

1

Es gibt einige Probleme in Ihrem Code

  1. zip nimmt Argumente, die

  2. dateutil.relativedelta kann nicht mit Pandas Timestamp kompatibel sein unterschiedlich lang sein kann. Mit Pandas 0.18.1 und Python 3.5, erhalte ich dieses:

    now = pd.Timestamp.now() 
    now 
    Out[46]: Timestamp('2016-07-06 15:32:44.266720') 
    now + dateutil.relativedelta.relativedelta(day=5) 
    Out[47]: Timestamp('2016-07-05 15:32:44.266720') 
    

    So ist es besser pd.Timedelta

    now + pd.Timedelta(5, 'D') 
    Out[48]: Timestamp('2016-07-11 15:32:44.266720') 
    

    zu verwenden, aber es ist etwas ungenau für Monate:

    now - pd.Timedelta(1, 'M') 
    Out[49]: Timestamp('2016-06-06 05:03:38.266720') 
    

Thi s ist eine Skizze des Codes. Ich habe nicht getestet und ich könnte mich irren, was du willst. Der entscheidende Teil besteht darin, die beiden Datenframes zusammenzuführen, anstatt Zeile für Zeile zu durchlaufen.

# 1) convert to datetime here 
# 2) optionally, you can select only relevant cols with e.g. usecols=['ID', 'used_at', 'url'] 
# 3) iterator is prob. superfluous 
el = pd.read_csv('df2.csv', chunksize=1000000, parse_dates=['used_at']) 

buys = pd.read_excel('smartphone.xlsx') 
buys['date'] = pd.to_datetime(buys['date']) 
# consider loading only relevant columns to buys 

# compute time intervals here (not in a loop!) 
buys['date_min'] = (buys['date'] - pd.TimeDelta(1, unit='M') 
buys['date_min'] = (buys['date'] + pd.TimeDelta(5, unit='D') 

# now replace (probably it needs to be done row by row) 
buys['date_min'] = buys['date_min'].apply(lambda x: x.replace(day=1, hour=0, minute=0, second=0)) 
buys['date_max'] = buys['date_max'].apply(lambda x: x.replace(day=1, hour=0, minute=0, second=0)) 

# not necessary 
# dates1 = buys['date'] 
# ids1 = buys['id'] 

for chunk in el: 
    # already converted to datetime 
    # i['used_at'] = pd.to_datetime(i['used_at']) 

    # defer sorting until later 
    # df = i.sort_values(['ID', 'used_at']) 

    # merge! 
    # (option how='inner' selects only rows that have the same id in both data frames; it's default) 
    merged = pd.merge(chunk, buys, left_on='ID', right_on='id', how='inner') 
    bool_idx = (merged['used_at'] < merged['date_max']) & (merged['used_at'] > merged['date_min']) 
    selected = merged.loc[bool_idx] 

    # probably don't need additional columns from buys, 
    # so either drop them or select the ones from chunk (beware of possible duplicates in names) 
    selected = selected[chunk.columns] 

    # sort now (possibly a smaller frame) 
    selected = selected.sort_values(['ID', 'used_at']) 

    if selected.empty: 
     continue 
    with open('3.csv', 'a') as f: 
     selected.to_csv(f, header=False) 

Hoffe, das hilft. Bitte überprüfen Sie den Code und passen Sie ihn Ihren Bedürfnissen an.

Bitte sehen Sie sich an, um die Optionen von merge zu verstehen.

+0

in dieser Zeichenfolge sollte nicht 'wählen = wählen Sie [chunk.columns]' und sollte 'wählen sein = ausgewählt [chunk.columns]'? – ldevyataykina

+0

In der Ausgabedatei bekomme ich 'id', das nicht in' kauft'. Es ist verbunden mit der Arbeit von 'merge'. Ich ändere es 'fusionierte = pd.merge (Buys, Brocken, left_on = 'id', right_on = 'ID')', weil es drehen 'KeyError' – ldevyataykina

+0

@ldevyataykina Ah, ja,' select' ein Tippfehler ist; sollte überall "ausgewählt" werden. Ich habe auch versehentlich "ID" und "ID" getauscht. (Die Antwort wurde aktualisiert.) Aber ich verstehe nicht, warum du 'id's bekommst, die nicht in' buy's sind - es sollte nicht passieren. Vielleicht versuche, 'how = 'inner' hinzuzufügen, um explizit zu verschmelzen. – ptrj

Verwandte Themen