Lesen Sie zufällige Zeilen aus großer CSV-Datei in Python

Ich habe diese ziemlich große CSV-Datei (15 Gb) und ich muss ca. 1 Million zufällige Zeilen davon lesen. Soweit ich sehen und implementieren kann – das CSV-Dienstprogramm in Python erlaubt es nur, sequentiell in der Datei zu iterieren.

Es ist sehr Speicher verbrauchen, um die alle Datei in den Speicher zu lesen, um eine zufällige Auswahl zu verwenden und es ist sehr zeitaufwendig, um durch die ganze Datei zu gehen und einige Werte zu verwerfen und andere zu wählen, also ist es sowieso, irgendeine zufällige Zeile aus der CSV-Datei zu wählen und Lese nur diese Zeile?

Ich habe ohne Erfolg versucht:

import csv with open('linear_e_LAN2A_F_0_435keV.csv') as file: reader = csv.reader(file) print reader[someRandomInteger] 

Ein Beispiel der CSV-Datei:

 331.093,329.735 251.188,249.994 374.468,373.782 295.643,295.159 83.9058,0 380.709,116.221 352.238,351.891 183.809,182.615 257.277,201.302 61.4598,40.7106 

10 Solutions collect form web for “Lesen Sie zufällige Zeilen aus großer CSV-Datei in Python”

 import random filesize = 1500 #size of the really big file offset = random.randrange(filesize) f = open('really_big_file') f.seek(offset) #go to random position f.readline() # discard - bound to be partial line random_line = f.readline() # bingo! # extra to handle last/first line edge cases if len(random_line) == 0: # we have hit the end f.seek(0) random_line = f.readline() # so we'll grab the first line instead 

Wie @AndreBoos darauf hingewiesen hat, wird dieser Ansatz zu einer voreingenommenen Auswahl führen. Wenn Sie min und max Länge der Linie kennen, können Sie diese Vorspannung entfernen, indem Sie folgendes tun:

Nehmen wir an (in diesem Fall) haben wir min = 3 und max = 15

1) Finde die Länge (Lp) der vorherigen Zeile.

Dann, wenn Lp = 3 ist, ist die Linie am meisten voreingenommen gegen. Daher sollten wir es 100% der Zeit nehmen Wenn Lp = 15, ist die Linie am meisten voreingenommen auf. Wir sollten es nur 20% der Zeit nehmen, da es 5 * wahrscheinlicher ist.

Wir erreichen dies durch zufällig halten die Linie X% der Zeit, wo:

X = min / Lp

Wenn wir die Linie nicht halten, machen wir noch eine zufällige Auswahl, bis unsere Würfelrolle gut kommt. 🙂

Ich habe diese ziemlich große CSV-Datei (15 Gb) und ich muss ca. 1 Million zufällige Zeilen davon lesen

Angenommen, Sie brauchen nicht genau 1 Million Zeilen und kennen dann die Anzahl der Zeilen in Ihrer CSV-Datei im Voraus, können Sie Reservoir-Sampling verwenden , um Ihre zufällige Teilmenge abzurufen. Einfach durch Ihre Daten iterieren und für jede Zeile bestimmen die Chancen der Zeile ausgewählt werden. Auf diese Weise braucht man nur einen einzigen Pass Ihrer Daten.

Das funktioniert gut, wenn man die zufälligen Samples oft extrahieren muss, aber der eigentliche Datensatz ändert sich selten (da musst du nur die Anzahl der Einträge verfolgen, wenn sich der Datensatz ändert).

 chances_selected = desired_num_results / total_entries for line in csv.reader(file): if random() < chances_selected: result.append(line) 

Sie können eine Variation der probabilistischen Methode für die Auswahl einer zufälligen Zeile in einer Datei verwenden.

Anstatt nur eine einzige Nummer zu halten, die gewählt wird, kannst du einen Puffer der Größe C behalten. Für jede Zeilennummer, n , in der Datei mit N Zeilen, möchten Sie diese Zeile mit Wahrscheinlichkeit C/n (anstatt die ursprüngliche 1/n die Nummer ausgewählt ist, wählen Sie dann eine zufällige Position aus dem C- Längenpuffer zu vertreiben.

So funktioniert das:

 import random C = 2 fpath = 'somelines.txt' buffer = [] f = open(fpath, 'r') for line_num, line in enumerate(f): n = line_num + 1.0 r = random.random() if n <= C: buffer.append(line.strip()) elif r < C/n: loc = random.randint(0, C-1) buffer[loc] = line.strip() 

Dies erfordert einen einzigen Durchlauf durch die Datei (also ist es lineare Zeit) und gibt genau C Zeilen aus der Datei zurück. Jede Zeile hat die Wahrscheinlichkeit, dass C/N ausgewählt wird.

Um zu überprüfen, ob die oben genannten funktioniert, habe ich eine Datei mit 5 Zeilen mit a, b, c, d, e erstellt. Ich lief den Code 10.000 mal mit C = 2. Dies sollte über eine gleichmäßige Verteilung der 5 wählen 2 (so 10) mögliche Entscheidungen zu produzieren. Die Ergebnisse:

 a,b: 1046 b,c: 1018 b,e: 1014 a,c: 1003 c,d: 1002 d,e: 1000 c,e: 993 a,e: 992 a,d: 985 b,d: 947 

Eine weitere Lösung ist möglich, wenn man die Gesamtzahl der Zeilen kennt – 1 Million zufällige Zahlen generieren ( random.sample(xrange(n), 1000000) ) bis zur Gesamtzahl der Zeilen als Set, dann benutze:

 for i, line in enumerate(csvfile): if i in lines_to_grab: yield line 

Dies wird Ihnen genau 1 Million Zeilen in einer unvoreingenommenen Weise, aber Sie müssen die Anzahl der Zeilen vorher haben.

Wenn die Zeilen wirklich .csv Format und NICHT festes Feld sind, dann nein, gibt es nicht. Sie können einmal durch die Datei crawlen, Indizierung der Byte-Offsets für jede Zeile, dann, wenn später benötigt nur die Index-Set, aber es gibt keine Möglichkeit, a priori vorhersagen, die genaue Lage der Zeile-terminierenden \ n Zeichen für beliebige CSV-Dateien.

Wenn du zufällige Zeilen mehrmals packen willst (z. B. Mini-Batches für das maschinelle Lernen), und es macht dir nichts aus, durch die riesige Datei einmal zu scannen (ohne sie ins Gedächtnis zu laden), dann kannst du eine Liste von Zeilen in der Tat erstellen und Verwenden Sie, um schnell die Linien zu holen (basierend auf Maria Zverinas Antwort).

 # Overhead: # Read the line locations into memory once. (If the lines are long, # this should take substantially less memory than the file itself.) fname = 'big_file' s = [0] linelocs = [s.append(s[0]+len(n)) or s.pop(0) for n in open(fname)] f = open(fname) # Reopen the file. # Each subsequent iteration uses only the code below: # Grab a 1,000,000 line sample # I sorted these because I assume the seeks are faster that way. chosen = sorted(random.sample(linelocs, 1000000)) sampleLines = [] for offset in chosen: f.seek(offset) sampleLines.append(f.readline()) # Now we can randomize if need be. random.shuffle(sampleLines) 

Sie können die Datei mit festen Längenaufzeichnungen umschreiben und dann einen zufälligen Zugriff auf die Zwischendatei später durchführen:

 ifile = file.open("inputfile.csv") ofile = file.open("intermediatefile.csv",'w') for line in ifile: ofile.write(line.rstrip('\n').ljust(15)+'\n') 

Dann können Sie:

 import random ifile = file.open("intermediatefile.csv") lines = [] samples = random.sample(range(nlines)) for sample in samples: ifile.seek(sample) lines.append(ifile.readline()) 

Erfordert mehr Speicherplatz, und das erste Programm kann einige Zeit dauern, um zu laufen, aber es erlaubt unbegrenzten späteren zufälligen Zugriff auf Datensätze mit dem zweiten.

Wenn Sie diese Daten in einer sqlite3-Datenbank platzieren können, ist die Auswahl einer beliebigen Anzahl von zufälligen Zeilen trivial. Du musst keine Zeilen in der Datei vorlesen oder auflegen. Da sqlite Datendateien binär sind, werden Sie Datendatei 1/3 bis 1/2 kleiner als CSV Text.

Sie können ein Skript wie DIES verwenden , um die CSV-Datei zu importieren, oder besser noch, schreiben Sie einfach Ihre Daten an eine Datenbanktabelle an erster Stelle. SQLITE3 ist Teil der Python-Distribution.

Dann benutze diese Aussagen, um 1.000.000 zufällige Zeilen zu bekommen:

 mydb='csv.db' con=sqlite3.connect(mydb) with con: cur=con.cursor() cur.execute("SELECT * FROM csv ORDER BY RANDOM() LIMIT 1000000;") for row in cur.fetchall(): # now you have random rows... 
 # pass 1, count the number of rows in the file rowcount = sum(1 for line in file) # pass 2, select random lines file.seek(0) remaining = 1000000 for row in csv.reader(file): if random.randrange(rowcount) < remaining: print row remaining -= 1 rowcount -= 1 

Bei dieser Methode erzeugen wir eine Zufallszahl, deren Anzahl von Elementen gleich der Anzahl der zu lesenden Zeilen ist, wobei deren Bereich die Anzahl der in den Daten vorhandenen Zeilen ist. Es wird dann vom kleinsten zum größten sortiert und gespeichert.

Dann wird die csv-Datei Zeile für Zeile gelesen und ein line_counter ist vorhanden, um die Zeilennummer zu bezeichnen. Dieser line_counter wird dann mit dem ersten Element der sortierten Zufallszahlenliste überprüft und wenn sie gleich sind, dann wird diese Zeile in die neue CSV-Datei geschrieben und das erste Element aus der Liste entfernt und das vorherige zweite Element tritt an die Stelle des Zuerst und der Zyklus geht weiter.

 import random k=random.sample(xrange(No_of_rows_in_data),No_of_lines_to_be_read) Num=sorted(k) line_counter = 0 with open(input_file,'rb') as file_handle: reader = csv.reader(file_handle) with open(output_file,'wb') as outfile: a=csv.writer(outfile) for line in reader: line_counter += 1 if line_counter == Num[0]: a.writerow(line) Num.remove(Num[0]) if len(Num)==0: break 
  • N zufällige, zusammenhängende und nicht überlappende Teilsequenzen jeder Länge
  • Wie man eine Liste von zufälligen Integer-Vektor erstellt, deren Summe x ist
  • Was ist die Verwendung von numpy.random.seed () macht es einen Unterschied?
  • Generiere 'n' eindeutige Zufallszahlen innerhalb eines Bereichs [doppelte]
  • (Pseudo) Zufallszahlenerzeugung in Python ohne Verwendung von Modulen und Uhr
  • Random String Generation mit Großbuchstaben und Ziffern in Python
  • Schnellste Weg, um 1.000.000 + Zufallszahlen in Python zu generieren
  • Python- Wie kann ich Fragen, die ein A, B, C, D haben
  • Generieren Sie Zufallszahlen mit einer gegebenen (numerischen) Verteilung
  • Warum dieses python-programm funktioniert nicht
  • Gibt es eine zufällige Funktion in Python, die Variablen akzeptiert?
  • Python ist die beste Programmiersprache der Welt.