csv-Datei lesen, weiterarbeiten und in andere csv wegschreiben

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
don dirko
User
Beiträge: 3
Registriert: Mittwoch 11. Juli 2018, 15:50

Mittwoch 11. Juli 2018, 23:01

Kann man eine CSV-Datei öffnen, deren Werte lesen, weiterverarbeiten und im gleichen zu die ergänzte Liste in eine neue CSV-Datei schreiben? Konkret get es um Liste mit 2 Postleitzahlen, die ich einlese. Ich ermittle für diese beiden PLZs deren Entfernung und möchte das Ergebnis nun in eine neue CSV schreiben.


# Berechnet die Entfernung von zwei PLZ-Gebieten zueinander
# -*- coding: utf-8 -*-
import pygeodb
import csv
import os
os.system('clear')

PLZ1="14163"

with open('VeraOut.csv', 'w') as OutputFile:
fieldnames = ['ID', 'PLZ1', 'PLZ2', 'Distanz']
writer = csv.DictWriter(OutputFile, delimiter=',', fieldnames=fieldnames)
writer.writeheader()
with open('VeraIn.csv') as InputFile:
fieldnames = ['ID', 'PLZ1', 'PLZ2']
reader=csv.DictReader(InputFile)
for row in reader:
ID = row['ID']
PLZ1 = row['PLZ1']
PLZ2 = row['PLZ2']
Distanz = pygeodb.distance(PLZ1,PLZ2)
Km = str(int(round(round(Distanz) / 1000))).strip()
Ausgabe='ID' + ID + ' Entfernung von PLZ ' + PLZ1 + " nach " + PLZ2 + " = " + str(Distanz) + " Meter / " + Km + " km"
print Ausgabe
writer.writerow({row['ID']:ID,row['PLZ1']:PLZ1, row['PLZ2']:PLZ2}) #, row['Distanz']:Distanz})


So wie ich es mir gedachte geht es leider nicht, die Felhlermeldung listet die erste Datenzeile auf:
File "PLZDistanceWriter.py", line 26, in <module>
writer.writerow({row['ID']:ID,row['PLZ1']:PLZ1, row['PLZ2']:PLZ2}) #, row['Distanz']:Distanz})
File "/usr/lib/python2.7/csv.py", line 152, in writerow
return self.writer.writerow(self._dict_to_list(rowdict))
File "/usr/lib/python2.7/csv.py", line 148, in _dict_to_list
+ ", ".join([repr(x) for x in wrong_fields]))
ValueError: dict contains fields not in fieldnames: '1', '14163', '10243'

Die Input-Datei VeraIn halt folgende Einträge:
ID,PLZ1,PLZ2
1,14163,10243
2,14163,72074
3,72074,14109

Hast jemand einen Tipp, wie man das lösen könnte? Ich komme hier nicht weiter.
Benutzeravatar
__blackjack__
User
Beiträge: 1089
Registriert: Samstag 2. Juni 2018, 10:21

Mittwoch 11. Juli 2018, 23:44

@don dirko: Du möchtest Dir noch mal anschauen wie man literale Wörterbücher schreibt, insbesondere wo der Schlüssel und wo der Wert stehen muss.

Sonstiges: Das `os` Modul wird importiert aber nicht verwendet.

Die Zuweisung an `PLZ1` vor dem öffnen der Datei macht keinen Sinn, weil dieser Wert nirgends verwendet wird.

Ich würde die Dateien ja in umgekehrter Reihenfolge öffnen. Dann hat man keine unnötige Datei erzeugt wenn sich die Eingabedatei nicht öffnen lässt.

`fieldnames` wird zweimal an eine Liste mit Spaltennamen gebunden, das eine mal wird das aber nirgends verwendet.

Die Namenskonvention in Python ist klein_mit_unterstrichen für alles ausser Konstanten (KOMPLETT_GROSSBUCHSTABEN) und Klassen (MixedCase). Siehe auch den Style Guide for Python Code.

Das zusammenstückeln von Zeichenkettenteilen und Werten mit ``+`` und `str()` ist eher BASIC als Python. In Python gibt es dafür die `format()`-Methode auf Zeichenketten.

Ich dachte diesen ``str(int(round(round(…``-Unsinn hätten wir in dem anderen Thema schon geklärt. Man braucht `round()` nicht um die ganze Zahl in eine Gleitkommazahl zu wandeln. Da nimmt man entweder `float()` oder man sorgt dafür das die Division auch bei Ganzzahlen eine Gleitkommazahl als Ergebniss hat.

Letztlich brauchst Du auch gar kein neues Wörterbuch erstellen, denn Du hast mit `row` ja schon eines dem bloss noch die zusätzliche Distanz fehlt.

Ungetestet:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Berechnet die Entfernung von zwei PLZ-Gebieten zueinander"""
from __future__ import absolute_import, division, print_function
import csv

import pygeodb


def main():
    with open('VeraIn.csv') as input_file:
        with open('VeraOut.csv', 'w') as output_file:
            writer = csv.DictWriter(
                output_file, fieldnames=['ID', 'PLZ1', 'PLZ2', 'Distanz']
            )
            writer.writeheader()
            for row in csv.DictReader(input_file):
                distanz = pygeodb.distance(row['PLZ1'], row['PLZ2'])
                print(
                    'ID{0[id]} Entfernung von PLZ {0[PLZ1]} nach {0[PLZ2]}'
                    ' = {1} Meter / {2:.0f} km'.format(
                        row, distanz, round(distanz / 1000)
                    )
                )
                row['Distanz'] = distanz
                writer.writerow(row)


if __name__ == '__main__':
    main()
“Capitalism is the astounding belief that the most wickedest of men will do the most wickedest of things for the greatest good of everyone.” – John Maynard Keynes
don dirko
User
Beiträge: 3
Registriert: Mittwoch 11. Juli 2018, 15:50

Donnerstag 12. Juli 2018, 09:02

Vielen Dank für die geduldige Nachhilfe! Ich mache mich ans Umsetzen...
Benutzeravatar
__blackjack__
User
Beiträge: 1089
Registriert: Samstag 2. Juni 2018, 10:21

Donnerstag 12. Juli 2018, 11:49

@don dirko: Wenn externe Module okay sind, könnte man die Zugriffe auf `row` mit dem `addict`-Modul geringfügig netter gestalten (ungetestet):

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Berechnet die Entfernung von zwei PLZ-Gebieten zueinander"""
from __future__ import absolute_import, division, print_function
import csv
from itertools import imap

from addict import Dict
import pygeodb


def main():
    with open('VeraIn.csv') as input_file:
        with open('VeraOut.csv', 'w') as output_file:
            writer = csv.DictWriter(
                output_file, fieldnames=['ID', 'PLZ1', 'PLZ2', 'Distanz']
            )
            writer.writeheader()
            for row in imap(Dict, csv.DictReader(input_file)):
                distanz = pygeodb.distance(row.PLZ1, row.PLZ2)
                print(
                    'ID{0.ID} Entfernung von PLZ {0.PLZ1} nach {0.PLZ2}'
                    ' = {1} Meter / {2:.0f} km'.format(
                        row, distanz, round(distanz / 1000)
                    )
                )
                row.Distanz = distanz
                writer.writerow(row)


if __name__ == '__main__':
    main()
Falls Du irgendwann einmal mit Texten aus CSV-Dateien arbeiten musst die auch etwas anderes als ASCII-Zeichen enthalten können, ist das `unicodecsv`-Modul einen Blick wert.

Und falls Du die `print()`-Ausgabe in der Form nicht wirklich benötigst und die Daten komplett in den Speicher passen, würde `tablib` den Code wesentlich verkürzen (ungetestet):

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Berechnet die Entfernung von zwei PLZ-Gebieten zueinander"""
from __future__ import absolute_import, division, print_function

from tablib import Dataset
import pygeodb


def main():
    dataset = Dataset()
    with open('VeraIn.csv') as input_file:
        dataset.set_csv(input_file)
    
    dataset.append_col(lambda row: pygeodb.distance(row[1], row[2]), 'Distanz')
    print(dataset)
    
    with open('VeraOut.csv', 'w') as output_file:
        output_file.write(dataset.csv)


if __name__ == '__main__':
    main()
“Capitalism is the astounding belief that the most wickedest of men will do the most wickedest of things for the greatest good of everyone.” – John Maynard Keynes
Antworten