2017-07-24 1 views
2

Während ich nach einer Alternative zur SAS-Sortierung suchte, entschied ich mich für Python 2.6 (beide auf demselben Unix-Server). Das Sortieren einer engen 500-ml-Zeilen-Tabelle dauert 20 Minuten in SAS. I exportiert 20% der Tabelle (100mln Zeilen) in eine CSV-Datei, die wie folgt aussieht:Python: CSV in die Liste lesen ist nicht schneller als CSV zu diktieren mit Schlüsselcheck?

X|||465097434|912364420|0.00|0.00|0.00|0.00|1.00|01FEB2016|X|0|0 
X|||465097434|912364420|0.00|0.00|0.00|0.00|0.00|02FEB2016|X|0|0 
X|||465097434|912364420|0.00|0.00|0.00|0.00|2.00|03FEB2016|X|0|0 
X|||465097434|912364421|0.00|0.00|0.00|0.00|3.00|04FEB2016|X|0|0 
X|||465097434|912364421|0.00|0.00|0.00|0.00|6.00|05FEB2016|X|0|0 
X|||965097411|912364455|0.00|0.00|0.00|0.00|4.00|04FEB2016|X|0|0 
X|||965097411|912364455|0.00|0.00|0.00|0.00|1.00|05FEB2016|X|0|0 

Das Ziel ist es, sortieren von 5. und 11. Spalten. Zuerst schaute ich, wie schnell Python die Datei mit dem Code zu lesen:

from __future__ import print_function 
import csv 
import time 
linesRead=0 
with open ('/path/to/file/CSV_FILE.csv','r') as dailyFile: 
    allLines=csv.DictReader(dailyFile, delimiter='|') 
    startTime=time.time() 
    for row in allLines: 
     linesRead += 1 
     if (linesRead) % 1000000 == 0: 
      print(linesRead, ": ", time.time()-startTime, " sec.") 
      startTime=time.time() 

Und die Ergebnisse sind, dass es 6 Sekunden dauert jeden mln Zeilen zu lesen.

1000000 : 6.6301009655 sec. 
2000000 : 6.33900094032 sec. 
3000000 : 6.26246404648 sec. 
4000000 : 6.56919789314 sec. 
5000000 : 6.17433309555 sec. 
... 
98000000 : 6.61627292633 sec. 
99000000 : 7.14683485031 sec. 
100000000 : 7.08069109917 sec. 

So erweiterte ich den Code es Wörterbuch zu laden (key = Spalte 5 (Kontokennung)) und Wert ist eine Liste von Listen (Linien) für dieses Konto. Diese ist, wo ich erkennen, dass Ladelisten in ein Wörterbuch verlangsamen, während Wörterbuch wächst (ganz logisch, da es eine wachsende Anzahl von Tasten zu überprüfen):

import csv 
import time 
myDictionary = {} 
linesRead=0 
with open ('/path/to/file/CSV_FILE.csv','r') as dailyFile: 
    allLines=csv.DictReader(dailyFile, delimiter='|') 
    startTime=time.time() 
    for row in allLines: 
     accountID=row['account_id'].strip('\'') 
     linesRead += 1 
     if accountID in myDictionary: 
      myDictionary[accountID].append([row['date'].strip('\''), row['balance1'], row['balance2'], row['balance3']]) 
     else: 
      myDictionary[accountID]=[] 
     if (linesRead) % 1000000 == 0: 
      print(linesRead, ": ", time.time()-startTime, " sec.") 
      startTime=time.time() 

Und die Zeiten sind:

1000000, ': ', 8.9685721397399902, ' sec.') 
(2000000, ': ', 10.344831943511963, ' sec.') 
(3000000, ': ', 11.637137889862061, ' sec.') 
(4000000, ': ', 13.024128913879395, ' sec.') 
(5000000, ': ', 13.508150815963745, ' sec.') 
(6000000, ': ', 14.94166088104248, ' sec.') 
(7000000, ': ', 16.307464122772217, ' sec.') 
(8000000, ': ', 17.130259990692139, ' sec.') 
(9000000, ': ', 17.54616379737854, ' sec.') 
(10000000, ': ', 20.254321813583374, ' sec.') 
... 
(39000000, ': ', 55.350741863250732, ' sec.') 
(40000000, ': ', 56.762171983718872, ' sec.') 
(41000000, ': ', 57.876702070236206, ' sec.') 
(42000000, ': ', 54.548398017883301, ' sec.') 
(43000000, ': ', 60.040227890014648, ' sec.') 

was bedeutet, dass es keine Chance gibt, 500mln Reihen in angemessener Zeit zu laden (die letzte Million von 500 Millionen würde 600 Sekunden laden). Meine Vermutung war, dass der langsamste Teil jeder Iteration wurde der Schlüssel Existenz im Wörterbuch Überprüfung:

if accountID in myDictionary: 

Also änderte ich Wörterbuch der Hoffnung, zur Liste so einfach Anfügen viel schneller sein wird:

with open ('/path/to/file/CSV_FILE.csv','r') as dailyFile: 
    allLines=csv.DictReader(dailyFile, delimiter='|') 
    startTime=time.time() 
    for row in allLines: 
     linesRead += 1 
     myList.append([row['account_id'].strip('\''), row['date'].strip('\''), row['balance1'], row['balance2'], row['balance3']]) 
     if (linesRead) % 1000000 == 0: 
      print(linesRead, ": ", time.time()-startTime, " sec.") 
      startTime=time.time() 

Leider gibt war überhaupt keine Leistungssteigerung:

1000000 : 9.15476489067 sec. 
2000000 : 10.3512279987 sec. 
3000000 : 12.2600080967 sec. 
4000000 : 13.5473120213 sec. 
5000000 : 14.8431830406 sec. 
6000000 : 16.5556428432 sec. 
7000000 : 17.6754620075 sec. 
8000000 : 19.1299819946 sec. 
9000000 : 19.7615978718 sec. 
10000000 : 22.5903761387 sec. 

Sollte nicht Liste Laden viel schneller th ein Ladewörterbuch mit Schlüsselprüfung bei der Eingabe?

Verwende ich Python, um diese Art von Daten zu verarbeiten? Zum Vergleich sortierte ich die Datei mit Unix-Befehl sort:

$ date ; sort -t'|' -k5,9 CSV_FILE.csv > delete.txt; date; 
Sun Jul 23 18:46:16 CEST 2017 
Sun Jul 23 19:06:53 CEST 2017 

Und es dauerte 20 Minuten, um den Job zu erledigen. In Python konnte ich die Daten nicht laden.

+0

Linux 'sort' ist wirklich schnell für die lexikographische Sortierung. Ich erwarte nicht, dass Sie schneller kommen können, außer durch leistungsfähigere Hardware. –

+0

Actual 'SAS' Sortierung hat 5 mal längere Datenmenge in der gleichen Zeit.Gleiche Größe (100mln) Datensatz 'SAS' in weniger als 2 Minuten sortiert –

Antwort

1

Ich schlage pandas vor, wie es schneller sein sollte. Dies würde der Code zum Lesen csv Datei sein:

import pandas as pd 
df = pd.read_csv('/path/to/file/CSV_FILE.csv', sep='|') 

Und es zu sortieren, die Sie verwenden können:

df.sort_values([4, 10], ascending=[True,True], inplace=True) 

Hinweis: erste Liste ist Spaltennamen und andere Argumente sind selbsterklärend.

+0

Danke, in der Tat' Pandas' ist ** viel schneller ** als CSV & List. Ich testet auf Windows Python 3.5.3 (keine Pandas auf dem Linux-Server) mit 67mln Zeilen und: Pandas-Importzeit: 55 sek. und Pandas Sortierzeit: 47sec. Während csv.DictReader und Ladeliste oder dict 10sec pro Million war. Interessant ist, dass war stabil 10sec/je mln Zeilen, nicht wie ursprünglich auf Linux und Python 2.6 verlangsamen. –