CSV zeilenweise trennung und in mehre Dateien splitten

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
kidchino
User
Beiträge: 91
Registriert: Montag 17. November 2014, 14:18

Hey zusammen,

ich schon wieder :).
Ich habe nur eine Anfrage. Ich muss relativ kurzfristig eine CSV-Datei mit ca. 10.000 Zeilen splitten und zwar in 100 einzelen Dateien mit jeweils 100 Zeilen.
Ist das mit Python auch für mich als RIESEN Laie einfach zu realisieren?
Wenn es doch komplexer ist, suche ich erstmal weiter oder mache es notfalls per Hand, ich bin ja nicht so fix mit Python.
Was meint Ihr? Insbesondere BlackJack kann mich sicherlich gut einschätzen. :oops:

Viele Grüße
kid
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Eine viel einfachere Aufgabe wirst du nicht finden. Mehr als das Wissen aus einem Grundlagentutorial braucht es nicht. Lesen und Schreiben kannst du mittels csv-Modul. Willst du einfach nur in n gleichgroße Stücke teilen, dann reichen die einfachen Operationen auf Dateien. Sind dann vielleicht fünf Zeilen.
Das Leben ist wie ein Tennisball.
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@EyDu: für 5 Zeilen muß man aber schon recht advanced sein.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Das war jetzt nur eine grobe Schätzun ;-). Mit Basiskenntnissen mögen es auch 20 oder 30 Zeilen sein, es ging mir eher um die Größenordnung.
Das Leben ist wie ein Tennisball.
kidchino
User
Beiträge: 91
Registriert: Montag 17. November 2014, 14:18

Hi zusammen,

mag mir sagen ob die Richtung stimmt?

Code: Alles auswählen

# -*- coding: utf-8 -*-
import csv, os, sys

pfad = 'C:/Skripttesten/scripttest/test/test/paperidsohneadresse.csv' # relevanter Pfad mit Dateien

reader = csv.reader(open(pfad))       
for nr, row in enumerate(reader):
    liste = []
    i=0
    while i*181 < nr < (1+i)*181:
        liste.append (row)
        print(liste)
        einzeldatei = open('C:/Skripttesten/scripttest/test/Test.csv')  #öffne die gesamte Datei
    writer = csv.writer(einzeldatei)
    writer.writerows(liste)
    i=i+1
Ab PRINT läufts irgendwie in die falsche Richtung.
BTW: Es müssen doch nicht 100 Zeilen sondern 180 sein

VG
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@kidchino: weder row noch nr noch i ändern sich innerhalb der while-Schleife. Das ergib also keinen Sinn. Du hast doch schon nr aus der for-Schleife, Du mußt also nur schauen, wann die einzeldatei zu wechseln ist.
kidchino
User
Beiträge: 91
Registriert: Montag 17. November 2014, 14:18

Hey,

ich es komplex ;)

Code: Alles auswählen

# -*- coding: utf-8 -*-
import csv, os, sys

datei = 'C:/Skripttesten/scripttest/test/test/paperidsohneadresse.csv' # relevanter Pfad mit Dateien

reader = csv.reader(open(datei))
i=0
j=1
x=5*j
y=x-5
liste = []
for row in reader:
   i=i+1
   if y < i < x:
       #print(i)
       liste.append(row)
       einzeldatei = open('C:/Skripttesten/scripttest/test/Test.csv')  #öffne die gesamte Datei
       writer = csv.writer(einzeldatei)
       writer.writerows(liste)
    else:
        j=j+1


Die Idee müsste doch richtig sein. Er zählt von 0 bis 179. Dabei müsste er doch jede Zeile an die Liste hängen oder?
Jetzt müsste ich ja nur noch das "j" mit in den Namen bringen?
Lahm ist es auch, aber richtig?

LG
kidchino
User
Beiträge: 91
Registriert: Montag 17. November 2014, 14:18

Ach mist, es geht doch nicht.

So könnte man ja vielleicht die Dateinamen variieren:

Code: Alles auswählen

'C:/Skripttesten/scripttest/test/Test'+ str(j)+'.csv'
Und die Liste wird ja aktuell nicht geleert, d.h. sie muss in Zeile 13.
BlackJack

@kidchino: Warum lässt Du `nr` weg statt `i` was ja komlizierter ist mit dem manuellen hochzählen. Was soll `j`? Das wird hochgezählt, aber nirgends verwendet.

Überlege mal wie `liste` bei jedem Schleifendurchlauf aussieht und wie oft die Ausgabedatei neu geschrieben wird, und mit welchen Werten jeweils.
kidchino
User
Beiträge: 91
Registriert: Montag 17. November 2014, 14:18

@BlackJack:
BlackJack hat geschrieben:Überlege mal wie `liste` bei jedem Schleifendurchlauf aussieht und wie oft die Ausgabedatei neu geschrieben wird, und mit welchen Werten jeweils.
Meinstest Du das?
Und die Liste wird ja aktuell nicht geleert, d.h. sie muss in Zeile 13.

Ich hatte es so gedacht, dass j nach jedem 180er (bzw, 5er Schritt als ein Bsp) hochgezählt wird.

VG
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Du machst es dir viel zu kompliziert. Wenn du die Datei an festen Grenzen aufteilen willst, dann brauchst du das csv-Modul gar nicht. Die wenigen tausend Zeilen kannst du auch mit einem Rutsch mit readlines einlesen und dann mittels Slicing aufteilen.
Das Leben ist wie ein Tennisball.
BlackJack

@EyDu: Das funktioniert aber nur unter der Voraussetzung das eine Zeile in der Textdatei auch genau einem Datensatz als CSV entspricht. Das trifft oft zu, aber halt nicht immer.
kidchino
User
Beiträge: 91
Registriert: Montag 17. November 2014, 14:18

Ich bekomme ich es nicht nicht :shock:

Code: Alles auswählen

# -*- coding: utf-8 -*-
import csv, os, sys

datei = 'C:/Skripttesten/scripttest/test/paperidsohneadresse.csv' # relevanter Pfad mit Dateien
i=1
x=180*i
y=x-180

liste = []
reader = csv.reader(open(datei, 'rb'))

for nr, row in enumerate(reader):
   print(nr)
Kein stück weiter als vor 12 std.
Kann mir jemand einen Tipp geben was nach der For-Schleife kommt (if, while)?
VG
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Nutze das ``csv``-Modul zum Einlesen der Daten in eine Liste. Anschließend nutze wie vorgeschlagen Slicing.

Hier mal am Beispiel von einfachen Buchstaben (in Python 3):

Code: Alles auswählen

import string
block_size = 3
for start in range(0, len(string.ascii_uppercase), block_size):
    print(string.ascii_uppercase[start:start+block_size])

>
ABC
DEF
GHI
JKL
MNO
PQR
STU
VWX
YZ
Anstelle der Buchstaben hast Du eben Datenzeilen und anstelle des ``prints`` musst Du eben jeweils eine neue CSV-Datei aus den Gruppen von Datenzeilen schreiben.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@Hyperion: so ein range-len-Konstrukt sieht wie ein Anti-Pattern aus. Besser man benutzt groupby, dann hat man gleich auch noch den Laufindex für den Dateinamen:

Code: Alles auswählen

from itertools import groupby, count
import string
block_size = 3
for nr, rows in groupby(string.lowercase, lambda _, w=count(): next(w)//block_size):
    print nr, list(rows)


>
0 ['a', 'b', 'c']
1 ['d', 'e', 'f']
2 ['g', 'h', 'i']
3 ['j', 'k', 'l']
4 ['m', 'n', 'o']
5 ['p', 'q', 'r']
6 ['s', 't', 'u']
7 ['v', 'w', 'x']
8 ['y', 'z']
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Eine andere Variante mit ``groupby()``:

Code: Alles auswählen

In [1]: import string; from operator import itemgetter; from itertools import groupby

In [2]: chars = ((i // 3, ch) for i, ch in enumerate(string.ascii_lowercase))

In [3]: for index, group in groupby(chars, key=itemgetter(0)):
   ...:     values = map(itemgetter(1), group)
   ...:     print(index, list(values))
   ...:
0 ['a', 'b', 'c']
1 ['d', 'e', 'f']
2 ['g', 'h', 'i']
3 ['j', 'k', 'l']
4 ['m', 'n', 'o']
5 ['p', 'q', 'r']
6 ['s', 't', 'u']
7 ['v', 'w', 'x']
8 ['y', 'z']
Sie ist einerseits etwas "gesprächiger", aber andererseits IMHO auch etwas verständlicher.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

@Sirius3: Ich hatte natürlich auch an ``groupby`` gedacht - aber für den OP ist das wohl etwas überfordernd. Als Anti-Pattern empfinde ich hier das ``len`` im ``range`` nicht - es geht im Zugriff ja schließlich um den Index und *nicht* (wie beim echten Anti Pattern) um den Zugriff auf *ein* Objekt.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Hyperion hat geschrieben:Als Anti-Pattern empfinde ich hier das ``len`` im ``range`` nicht - es geht im Zugriff ja schließlich um den Index und *nicht* (wie beim echten Anti Pattern) um den Zugriff auf *ein* Objekt.
Auch ich sehe das in diesem Zusammenhang nicht als Anti-Pattern. Man hat einen direkten Zugriff ohne Umwege. In der Regel sind Slices für diverse Objekttypen auch performanter implementiert als die Variante über das Iterator-Protokoll.

Andererseits kann der direkte Indexzugriff bzw Slicing hier bloß als Grundlagenwissen dienen. Einen ``csv.reader`` kann man nämlich nicht mit Indexzugriffen abfragen. Und an der Stelle ist die ``groupby``-Variante IMHO gar keine so schlechte Wahl. Auch wenn das kein wirklich eleganter Weg ist. Aber das sind die Alternativen ja auch nicht.
kidchino
User
Beiträge: 91
Registriert: Montag 17. November 2014, 14:18

Hi,
Hyperion hat geschrieben: aber für den OP ist das wohl etwas überfordernd.
ganz recht. ;)
Ich gebs auf.

VG und trotzdem Danke für die Hinweise und Erklärungen
kid
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Warum das? Du musst es doch nicht alles in wenige Zeilen pressen. Teile dir die Aufgabe doch in verschiedene Funktion auf. Einlesen der CSV-Datei, Zerteilen der Daten, Schreiben einer neuen CSV-Datei und dann fügst du das ganze noch zusammen. Du musst das nur Stück für Stück lösen, dann wird es auch ganz einfach.
Das Leben ist wie ein Tennisball.
Antworten