webentwicklung-frage-antwort-db.com.de

Lesen und stornieren Sie die Datenpakete Stück für Stück aus einer CSV-Datei und kopieren Sie sie in eine neue CSV-Datei

Angenommen, ich habe es mit einer sehr großen CSV-Datei zu tun. So kann ich die Datenmenge nur für Datenmenge in den Speicher einlesen. Der erwartete Fluss von Ereignissen sollte wie folgt aussehen:

1) Lesen Sie mit Hilfe von Pandas einen Datenblock (z. B. 10 Zeilen) aus der csv.

2) Kehren Sie die Reihenfolge der Daten um

3) Kopieren Sie jede Zeile in eine neue CSV-Datei. Jeder Chunk (10 Zeilen) ist also in csv von Anfang an in umgekehrter Reihenfolge geschrieben.

Am Ende sollte die CSV-Datei in umgekehrter Reihenfolge sein und dies sollte ohne Laden der gesamten Datei in den Arbeitsspeicher für Windows OS erfolgen.

Ich versuche eine Zeitserie zu prognostizieren. Ich brauche Daten, um vom alten bis zum neuesten Wert zu sein (älteste Eintrag in der ersten Zeile). Ich kann nicht die gesamte Datei in den Speicher laden. Ich suche nach einer Möglichkeit, jeden Block zu einem Zeitpunkt zu bearbeiten, wenn dies möglich ist.

Der Datensatz, den ich an train.csv des Rossmann-Datensatzes von kaggle ausprobiert habe. Sie können es aus diesem github repo bekommen 

Mein Versuch kopiert die Zeilen nicht ordnungsgemäß in die neue CSV-Datei.

Zeigen Sie unten meinen Code an:

import pandas as pd
import csv

def reverse():

    fields = ["Store","DayOfWeek","Date","Sales","Customers","Open","Promo","StateHoliday",
              "SchoolHoliday"]
    with open('processed_train.csv', mode='a') as stock_file:
        writer = csv.writer(stock_file,delimiter=',', quotechar='"', 
                                                quoting=csv.QUOTE_MINIMAL)
        writer.writerow(fields)

    for chunk in pd.read_csv("train.csv", chunksize=10):
        store_data = chunk.reindex(index=chunk.index[::-1])
        append_data_csv(store_data)

def append_data_csv(store_data):
    with open('processed_train.csv', mode='a') as store_file:
        writer = csv.writer(store_file,delimiter=',', quotechar='"',
                                           quoting=csv.QUOTE_MINIMAL)
        for index, row in store_data.iterrows():
            print(row)
            writer.writerow([row['Store'],row['DayOfWeek'],row['Date'],row['Sales'],
            row['Customers'],row['Open'],row['Promo'],
            row['StateHoliday'],row['SchoolHoliday']])

reverse()

Danke im Voraus

14
Suleka_28

Mit bash können Sie die gesamte Datei bis auf die erste Zeile ausrichten und dann umkehren und sie wie folgt speichern:

tail -n +2 train.csv  | tac > train_rev.csv

Wenn Sie den Header in der umgekehrten Datei behalten möchten, schreiben Sie ihn zuerst und hängen Sie dann den umgekehrten Inhalt an

head -1 train.csv > train_rev.csv; tail -n +2 train.csv  | tac >> train_rev.csv
3
gustavovelascoh

Dies tut genau das, was Sie anfordern, aber ohne Pandas. Es liest intest.csv Zeile für Zeile (anstatt die gesamte Datei in den RAM zu lesen). Die Verarbeitung erfolgt überwiegend über das Dateisystem mit einer Reihe von Chunk-Dateien, die am Ende in der Datei outtest.csv zusammengefasst werden. Wenn Sie die maxLines ändern, können Sie die Anzahl der produzierten Chunk-Dateien im Vergleich zu RAM optimieren (verbrauchte höhere Zahlen verbrauchen mehr RAM, erzeugen jedoch weniger Chunk-Dateien). Wenn Sie den CSV-Header in der ersten Zeile behalten möchten, setzen Sie keepHeader auf True. Wenn auf False gesetzt, wird die gesamte Datei einschließlich der ersten Zeile umgekehrt.

Für Tritte habe ich dies auf einem alten Raspberry Pi mit einem 128-GB-Flashlaufwerk mit einer 6-MB-CSV-Testdatei ausgeführt. Ich dachte, etwas wäre schief gelaufen, weil es fast sofort zurückgekehrt ist, also ist es auch auf langsamerer Hardware schnell. Es importiert nur eine Standard-Python-Bibliotheksfunktion (remove) und ist daher sehr portabel. Ein Vorteil dieses Codes besteht darin, dass keine Dateizeiger neu positioniert werden. Eine Einschränkung ist, dass CSV-Dateien mit Zeilenumbrüchen nicht funktionieren. Für diesen Anwendungsfall wären Pandas die beste Lösung, um die Brocken zu lesen.

from os import remove

def writechunk(fileCounter, reverseString):
    outFile = 'tmpfile' + str(fileCounter) + '.csv'
    with open(outFile, 'w') as outfp:
        outfp.write(reverseString)
    return

def main():
    inFile = 'intest.csv'
    outFile = 'outtest.csv'
    # This is our chunk expressed in lines
    maxLines = 10
    # Is there a header line we want to keep at the top of the output file?
    keepHeader = True

    fileCounter = 0
    lineCounter = 0
    with open(inFile) as infp:
        reverseString = ''
        line = infp.readline()
        if (line and keepHeader):
            headerLine = line
            line = infp.readline()
        while (line):
            lineCounter += 1
            reverseString = line + reverseString
            if (lineCounter == maxLines):
                fileCounter += 1
                lineCounter = 0
                writechunk(fileCounter, reverseString)
                reverseString = ''
            line = infp.readline()
    # Write any leftovers to a chunk file
    if (lineCounter != 0):
        fileCounter += 1
        writechunk(fileCounter,reverseString)
    # Read the chunk files backwards and append each to the outFile
    with open(outFile, 'w') as outfp:
        if (keepHeader):
            outfp.write(headerLine)
        while (fileCounter > 0):
            chunkFile = 'tmpfile' + str(fileCounter) + '.csv'
            with open(chunkFile, 'r') as infp:
                outfp.write(infp.read())
            remove(chunkFile)
            fileCounter -= 1

if __== '__main__':
    main()
0
Mark Warburton

Wenn Sie über ausreichend Festplattenspeicher verfügen, können Sie Blöcke einlesen, umkehren und speichern. Nehmen Sie dann die gespeicherten Blöcke in umgekehrter Reihenfolge auf und schreiben Sie in eine neue CSV-Datei.

Im Folgenden finden Sie ein Beispiel für Pandas, bei dem auch Pickle (aus Leistungsgründen) und gzip (für Speichereffizienz) verwendet werden.

import pandas as pd, numpy as np

# create a dataframe for demonstration purposes
df = pd.DataFrame(np.arange(5*9).reshape((-1, 5)))
df.to_csv('file.csv', index=False)

# number of rows we want to chunk by
n = 3

# iterate chunks, output to pickle files
for idx, chunk in enumerate(pd.read_csv('file.csv', chunksize=n)):
    chunk.iloc[::-1].to_pickle(f'file_pkl_{idx:03}.pkl.gzip', compression='gzip')

# open file in amend mode and write chunks in reverse
# idx stores the index of the last pickle file written
with open('out.csv', 'a') as fout:
    for i in range(idx, -1, -1):
        chunk_pkl = pd.read_pickle(f'file_pkl_{i:03}.pkl.gzip', compression='gzip')
        chunk_pkl.to_csv(fout, index=False, header=False if i!=idx else True)

# read new file to check results
df_new = pd.read_csv('out.csv')

print(df_new)

    0   1   2   3   4
0  40  41  42  43  44
1  35  36  37  38  39
2  30  31  32  33  34
3  25  26  27  28  29
4  20  21  22  23  24
5  15  16  17  18  19
6  10  11  12  13  14
7   5   6   7   8   9
8   0   1   2   3   4
0
jpp

Ich würde nicht die Verwendung von pandas zum Analysieren oder Streamen von Dateien empfehlen, da Sie nur zusätzlichen Aufwand einführen. Am besten lesen Sie die Datei von unten nach oben. Nun, ein großer Teil dieses Codes kommt tatsächlich von hier , wo er eine Datei aufnimmt und die Umkehrung in einem Generator zurückgibt, von dem ich glaube, dass er das ist, was Sie wollen.

Was ich getan habe, habe ich es einfach mit Ihrer Datei train.csv aus dem bereitgestellten Link getestet und die Ergebnisse in einer neuen Datei ausgegeben.

import os

def reverse_readline(filename, buf_size=8192):
    """a generator that returns the lines of a file in reverse order"""
    with open(filename) as fh:
        segment = None
        offset = 0
        fh.seek(0, os.SEEK_END)
        file_size = remaining_size = fh.tell()
        while remaining_size > 0:
            offset = min(file_size, offset + buf_size)
            fh.seek(file_size - offset)
            buffer = fh.read(min(remaining_size, buf_size))
            remaining_size -= buf_size
            lines = buffer.split('\n')
            # the first line of the buffer is probably not a complete line so
            # we'll save it and append it to the last line of the next buffer
            # we read
            if segment is not None:
                # if the previous chunk starts right from the beginning of line
                # do not concact the segment to the last line of new chunk
                # instead, yield the segment first 
                if buffer[-1] != '\n':
                    lines[-1] += segment
                else:
                    yield segment
            segment = lines[0]
            for index in range(len(lines) - 1, 0, -1):
                if lines[index]:
                    yield lines[index]
        # Don't yield None if the file was empty
        if segment is not None:
            yield segment

reverse_gen = reverse_readline('train.csv')

with open('rev_train.csv','w') as f:
    for row in reverse_gen:
        f.write('{}\n'.format(row))

Es liest es im Grunde in umgekehrter Richtung, bis es eine neue Zeile findet und dann eine line aus der Datei von unten nach oben ergibt. Ein ziemlich interessanter Weg. 

0
BernardL