2 CSV-Dateien kombinieren

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.
Antworten
fred1901
User
Beiträge: 3
Registriert: Mittwoch 13. April 2011, 11:10

Hallo Python Experte!
ich mache gerade mein Praktikum und habe erst seit kurzem angefangen Python zu lernen.
Letzte Woche hatte ich schön die erste Aufgabe von meinem Betreue bekommen und stehe einbißchen unter Druck und Stress.
Vielleicht könnte mir jemand helfen
Mein Problem ist folgendes.
Ich habe 2 CSV-Dateien "report1 und report2" (siehe unten)
und möchte mal ein Progamm schreiben, das Daten aus den 2 Dateien "report1 und report2" einliest und
in einem dritten Datei namens "report" (siehe unten)schreibt. Die Datei "report" soll wie im Anhang aussehen.

Ich habe schön ein Programm geschrieben, mit dem man aus dem Datei "report" die einzelnen Werten von "report1 und report2" einliest und
daraus den Mittelwert berechnet. Mein größte Problem ist jetzt wie mann aus den 2 Dateien "report1 und report2", die Datei "report" bekomme.

ich würde mich sehr freuen, wenn mir jemand helfe könnte, Da ich schon nächste Woche etwa an meinem Betreue präsentieren werde.

Danke im voraus und viele Grüße


Datei "report1.csv" (7 Zeilen und 2 Spalten)

name kmstand

Daniel 29
David 10
Sebastian 30
Jan 7
Lucas 120
Patrick 45


Datei "report2.csv" (8 Zeilen und 2 Spalten)

name kmstand

Daniel
David 24
Sebastian 10
Jan
Lucas 50
Patrick 20
Emil 40



Datei "report.csv" (3 Zeilen und 8 Spalten wobei die erste Zelle der ersten Spalten bzw Zeile frei ist)

Daniel David Sebastian Jan Lucas Patrick Emil

report1 29 10 30 7 120 45
report2 24 10 50 20 40
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hallo und willkommen im Forum!

Zeig mal den vorhandenen Code, damit lässt sich leichter arbeiten.

Sebastian
Das Leben ist wie ein Tennisball.
BlackJack

@fred1901: Die Aufgabe ist scheint mir nicht klar genug definiert zu sein. Du schreibst zum Beispiel bei Report 1 es wären sieben Zeilen, ich komme beim Zählen aber auf 8. Oder zählt die Leerzeile nach der "Titelzeile" nicht mit? Ist die in der Datei vorhanden? Was sind die Trennzeichen? Einzelne Leerzeichen? Wäre eher ungewöhnlich für das Dateiformat.

In der zweiten Datei sind nicht bei allen Namen auch Werte -- im Ergebnis tauchen dann aber welche auf!? Oder liegt das nur an der kaputten Formatierung!?
fred1901
User
Beiträge: 3
Registriert: Mittwoch 13. April 2011, 11:10

Hallo Leute und danke erst mal für Ihre schnelle Antwort.
Ich entschuldige mich, wenn ich nicht ganz klar war. Die Aufgabe wurde heute morgen umformuliert und ich hoffe jetzt etwa klarer zu sein.
++++++++++++++ Datei "report1"+++++++++++++++++
Die erste Spalte enthält folgende Einträge:
Daniel
Daniel
Daniel
Lucas
Lucas

Die zweite Spalte (String mit Zahlen, die durch leerzeichen getrennt sind) enthält folgende Einträge
"20 8 0"
"10 0 0"
"30 0 0"
"70 4 0"
"12 0 0"

++++++++++++++ Datei "report2"++++++++++++++++++++++++
Die erste Spalte enthält folgende Einträge:
David
Jan

Und die zweite Spalten folgende Einträge
"15 0 0"
"20 0 0"

Ich interessiere mich bei den String nur für die erste Zahlen ( z.B die Zahl 15 bei "15 0 0" soll eingelesen werden)
Es soll bei jedem Name jeweils die ersten Zahlen eingelesen und daraus den Mittelwert berechnet, der dann in die Datei "report" kommt ( z.B bei Daniel die drei mal vorkommt, den Mittelwert aus den 3 Zahlen berechnen)

Die Datei "report" soll so aussehen

Erste Spalte( fängte aber ab dem 2. Zelle) enthält folgende Einträge:
report1
report2

Zweite Spalte:
Daniel
Mittelwert aus den eingelesenen Zahlen von Daniel(dies sind 20 10 30)

Dritte Spalte:
Lucas
Mittelwert aus den eingelesenen Zahlen von Lucas(dies sind 70 12)

Vierte Spalte:
David
Mittelwert aus den eingelesenen Zahlen von David(dies ist 15)

fünfte Spalte:
Jan
Mittelwert aus den eingelesenen Zahlen von Jan(dies ist 20)

Trennzeichen ist der Strichpunkt ";"

Der folgende Code ist nur zum einlesen der berechnete Mittelwert aus der Datei "report" und noch daraus je nach report den Mittelwert zu berechnen.

Code: Alles auswählen

# -*-coding:Latin-1 -*

import csv
import sys


class readInCSV(object):

    def __init__(self):

        self.report = list()
        self.name = list()

    def average(self, filename):
         self.fileName = filename
         try:
             self.fileObj = open(self.fileName, "rb")
             self.fileReader = csv.reader(self.fileObj, delimiter = ';')
         except IOError:
             print "Error --> can\'t find file or read data"
             sys.exit()
         report2name = dict()
         for data in self.fileReader:
             data = ",".join(data)  
             assignment = data.split(",", 1) 
             self.report .append(assignment[0])
             self.name  = [int(n) for n in assignment[1].split(',')]
             report2name [assignment[0]] = self.name 

         for report, name in sorted( report2name .iteritems()):
             print '%s: %.2f' % (report , float(sum(name )) / len(name))

         self.fileObj.close()
Ich hätte auch den Name der Datei dem Konstruktor übergeben sollen aber ich weiss es nicht was am besten wäre, Da es noch weitere funktionen(z.B schreiben in der csv-Datei) in der Klasse kommen werden
Auch mit dem Privat attribut der Klasse. Ich glaube es wäre besser Sie so zu declarieren

self._report = list()
self._name = list()

Ich hoffe ich war nicht zu lang und auch, dass Sie die Aufgabe jetzt etwa besser verstehen werden.
Vielen Dank nochmals und viele Grüße
Fred
Zuletzt geändert von Anonymous am Donnerstag 14. April 2011, 15:22, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Code-Tags gesetzt.
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Das ist irgendwie vermurkster Code mit zusätzlich unglücklicher Wahl der Bezeichnernamen. Eine Liste die name heißt, dann aber Integer-Werte enthält, kommt mir komisch vor. Ich sehe auch noch nicht den Grund, warum eine Klasse im Spiel ist. Alles in allem habe ich aufgehört zu versuchen zu verstehen was da passiert.

Ich möchte mal folgenden Ansatz ins Spiel bringen:

Code: Alles auswählen

import collections
import csv

database = collections.defaultdict(list)
report = csv.reader(open('csv_reader_02.csv'), delimiter=';')
for name, values in list(report):
    database[name].append(int(values.split(' ')[0]))
print database
Eine Bitte: Verwende beim Einstellen von Code ins Forum bitte Python-Tags, sonst ist der Quelltext nicht gerade gut lesbar.
BlackJack

@fred1901: Das sieht alles ein wenig wirr aus und die Beschreibung der Ausgabeformats klingt so als wenn in der ersten Spalte zwar für jeden Report eine Zeile besteht, aber in allen anderen Spalten nur die ersten beiden Zeilen Werte enthalten.

Der Quelltext ist zu kompliziert. Insbesondere ist die Klasse unsinnig. Das erkennt man vielleicht auch schon am Namen, der bei Klassen übrigens mit einem Grossbuchstaben beginnen sollte. Klassen beschreiben "Dinge" während Funktionen und Methoden "Tätigkeiten" beschreiben. `readInCSV` ist keine Beschreibung für ein "Ding".

Attribute sollte man auch alle in der `__init__` definieren. Wenn bei Methodenaufrufen welche hinzukommen wird es schnell unübersichtlich und fehleranfällig. Zumal in `average()` auch Werte an das `readInCSV`-Exemplar gebunden werden, die eindeutig nur innerhalb der Methode von Interesse sind. Andererseits sehe ich keinen Sinn darin auf `self.report` und `self.name` zuzugreifen und damit wäre das einfach nur eine Funktion und keine Methode.

Dateien sollte man mit der ``with``-Anweisung öffnen, dann ist das korrekte Schliessen sichergestellt.

Funktionen oder Methoden sollten das Programm nicht abbrechen. `sys.exit()` gehört nicht in Programmlogik, die nur Daten verarbeitet, sondern höchstens in Programmteile, welche die Benutzerinteraktion abwickeln.

Die Aktion `data` erst mit Komma zusammenzuführen um gleich in der nächsten Zeile das ganze an dem gerade dazwischen gefügten Komma wieder aufzuteilen ist ziemlich sinnfrei.

Beim Namen `name` würde kaum jemand vermuten das sich da eine Liste mit *Zahlen* hinter verbirgt. Beim Erstellen der Liste teilst Du am Komma -- in der Beschreibung der Eingabedaten sind die Zahlen aber durch Leerzeichen getrennt!?

`report` ist auch nicht an etwas gebunden was ein Report wäre, sondern ja wohl an einen Namen. Was die Bindung von `name` an eine Liste mit Zahlen noch verwirrender macht.

Aus den letzten beiden Punkten ergibt sich, dass der Name `report2name` ebenfalls verwirrend und falsch ist.

Der Namenszusatz `Obj` ist übrigens in der Regel ziemlich überflüssig -- *alles* was man in Python an einen Namen binden kann ist ein Objekt. Der Zusatz `Obj` enthält also hier absolut keine zusätzliche Information.

Ich würde erst einmal bei Funktionen bleiben solange es keinen Grund für eine Klasse gibt.

Dann solltest Du das Problem in einzelne Schritte unterteilen bis die so klein sind, dass sie mehr oder weniger trivial implementiert werden können. Das machst Du dann und setzt die Teillösungen zu einer Gesamtlösung zusammen.

Das könnte zum Beispiel mit einer Funktion beginnen, die eine CSV-Datei einliesst und als Ergebnis ein Wörterbuch, das Namen auf Mittelwerte abbildet zurück gibt.

Die kann man dann auf mehrere Report-Dateien anwenden und die Ergebnisse in einer Liste sammeln, die Tupel aus Reportnamen und den Ergebnissen von der Einlesefunktion enthält.

Dann brauchst Du nur noch eine Funktion die das ganze entsprechend für die Ausgabe aufbereitet. Das liesse sich unterteilen in Kopfzeile erstellen und dann eine Zeile für jeden Report erstellen.

Und wichtig beim Entwickeln: Jeden Schritt testen und erst mit der nächsten Funktion weitermachen, wenn das Teilergebnis bis dahin funktioniert.
fred1901
User
Beiträge: 3
Registriert: Mittwoch 13. April 2011, 11:10

Danke für die viele Tipps. Ich werde mal probieren und sehen wie weit ich kommen kann

Grüße
Fred
Antworten