Ein Wörterbuch aus einer CSV-Datei erstellen?


153

Ich versuche, ein Wörterbuch aus einer CSV-Datei zu erstellen. Die erste Spalte der CSV-Datei enthält eindeutige Schlüssel und die zweite Spalte enthält Werte. Jede Zeile der CSV-Datei repräsentiert ein eindeutiges Schlüssel-Wert-Paar im Wörterbuch. Ich habe versucht, die Klassen csv.DictReaderund zu csv.DictWriterverwenden, konnte aber nur herausfinden, wie für jede Zeile ein neues Wörterbuch erstellt werden kann. Ich möchte ein Wörterbuch. Hier ist der Code, den ich verwenden möchte:

import csv

with open('coors.csv', mode='r') as infile:
    reader = csv.reader(infile)
    with open('coors_new.csv', mode='w') as outfile:
    writer = csv.writer(outfile)
    for rows in reader:
        k = rows[0]
        v = rows[1]
        mydict = {k:v for k, v in rows}
    print(mydict)

Wenn ich den obigen Code ausführe, erhalte ich eine ValueError: too many values to unpack (expected 2). Wie erstelle ich ein Wörterbuch aus einer CSV-Datei? Vielen Dank.


2
Können Sie ein Beispiel für eine Eingabedatei und die daraus resultierende Datenstruktur geben?
Robert

1
Wenn Sie über csv.reader iterieren, erhalten Sie eine einzelne Zeile, keine Zeilen. Eine gültige Form ist also mydict = {k: v für k, v im Leser}. Wenn Sie jedoch sicher sind, dass die CSV-Datei nur zwei Spalten enthält, ist mydict = dict (Leser) viel schneller.
Alex Laskin

Antworten:


154

Ich glaube, die Syntax, nach der Sie gesucht haben, lautet wie folgt:

import csv

with open('coors.csv', mode='r') as infile:
    reader = csv.reader(infile)
    with open('coors_new.csv', mode='w') as outfile:
        writer = csv.writer(outfile)
        mydict = {rows[0]:rows[1] for rows in reader}

Alternativ möchten Sie für Python <= 2.7.1:

mydict = dict((rows[0],rows[1]) for rows in reader)

2
Gut, um Zeilen länger als erwartet zu berücksichtigen; Aber sollte er nicht seine eigene Ausnahme machen, wenn zu viele Gegenstände hintereinander sind? Ich würde denken, das würde bedeuten, dass es einen Fehler mit seinen Eingabedaten gibt.
Maschinen Sehnsucht

1
Und dann würde er zumindest in der Lage sein, die Ausnahme auf fehlerhafte Eingaben
einzugrenzen

Das hat einige Vorteile, aber ich bin fest davon überzeugt, dass es Ausnahmen gibt, die Ihnen sagen, dass Sie etwas falsch programmiert haben - nicht, wenn die Welt Ihnen Zitronen gibt. In diesem Fall drucken Sie eine hübsche Fehlermeldung und schlagen fehl oder - für diesen Fall besser geeignet - eine hübsche Warnmeldung und sind erfolgreich.
Nate

Entschuldigung, ich habe mir den Code von op angesehen, schwer zu sagen, ob er nur 2 Artikel pro Zeile haben wollte. Ich lag falsch!
Maschinen Sehnsucht

1
Ich hatte mehrere Zeilen in CSV, aber es gab nur 1 Schlüssel: Wert-Paar
Abhilash Mishra

79

Öffnen Sie die Datei, indem Sie open und dann aufrufen csv.DictReader.

input_file = csv.DictReader(open("coors.csv"))

Sie können die Zeilen des CSV-Dict-Reader-Objekts durchlaufen, indem Sie die Eingabedatei durchlaufen.

for row in input_file:
    print(row)

ODER Nur auf die erste Zeile zugreifen

dictobj = csv.DictReader(open('coors.csv')).next() 

UPDATE In Python 3+ -Versionen würde sich dieser Code ein wenig ändern:

reader = csv.DictReader(open('coors.csv'))
dictobj = next(reader) 

3
Dies macht das DictReader-Objekt nicht zu einem Wörterbuch (und ja nicht zu einem Schlüsselwertpaar)
HN Singh

1
@HN Singh - Ja, ich weiß - Absicht war, dass es auch jemand anderem helfen wird
Laxmikant Ratnaparkhi

1
'DictReader'-Objekt hat kein Attribut' next '
Palak

1
@Palak - es wurde für Python 2.7 beantwortet, versuchen Sie es next(dictobj)statt dictobj.next()in Python 3+ Versionen.
Laxmikant Ratnaparkhi

61
import csv
reader = csv.reader(open('filename.csv', 'r'))
d = {}
for row in reader:
   k, v = row
   d[k] = v

6
Sehr nicht-pythonischer Stil.
Alex Laskin

47
@ Alex Laskin: Wirklich? Es sieht für mich wie eine ziemlich lesbare Python aus. Was ist Ihr Prinzip, um diese Aussage zu stützen? Sie nannten ihn im Grunde nur "Poopy Head" ...
Maschine Sehnsucht

26
@ Maschinen-Sehnsucht, nein, ich habe nicht gesagt, dass sein Code "schlecht" ist. Es gibt jedoch keinen einzigen Grund zum Schreiben, for row in reader: k, v = rowwenn Sie beispielsweise einfach schreiben for k, v in readerkönnen. Und wenn Sie erwarten, dass dieser Reader iterierbar ist und Elemente mit zwei Elementen erzeugt, können Sie ihn einfach direkt an das Diktat zur Konvertierung übergeben. d = dict(reader)ist bei großen Datenmengen viel kürzer und deutlich schneller.
Alex Laskin

44
@ Alex Laskin: Danke für die Klarstellung. Ich habe Ihnen persönlich zugestimmt, aber ich denke, wenn Sie den Code von jemandem als "nicht pythonisch" bezeichnen, sollten Sie diesen Kommentar mit einer Begründung versehen. Ich würde sagen, dass "kürzer" und "schneller" nicht unbedingt "pythonischer" sind. Lesbarkeit / Zuverlässigkeit ist ebenfalls ein großes Problem. Wenn es einfacher ist, in einigen unserer Einschränkungen das obige for row in readerParadigma zu berücksichtigen, ist es möglicherweise (nach längerfristiger Entwicklung) praktischer. Ich stimme Ihnen kurzfristig zu, aber hüte dich vor vorzeitiger Optimierung.
Maschinen Sehnsucht

30

Dies ist keine elegante, sondern eine einzeilige Lösung mit Pandas.

import pandas as pd
pd.read_csv('coors.csv', header=None, index_col=0, squeeze=True).to_dict()

Wenn Sie dtype für Ihren Index angeben möchten (dieser kann in read_csv nicht angegeben werden, wenn Sie das Argument index_col aufgrund eines Fehlers verwenden ):

import pandas as pd
pd.read_csv('coors.csv', header=None, dtype={0: str}).set_index(0).squeeze().to_dict()

3
in meinem Buch ist dies die beste Antwort
boardtc

Und wenn es einen Header gibt ...?
Ndtreviv

@ndtreviv Sie können Skiprows verwenden, um Header zu ignorieren.
mudassirkhan19

17

Sie müssen nur csv.reader konvertieren, um zu diktieren:

~ >> cat > 1.csv
key1, value1
key2, value2
key2, value22
key3, value3

~ >> cat > d.py
import csv
with open('1.csv') as f:
    d = dict(filter(None, csv.reader(f)))

print(d)

~ >> python d.py
{'key3': ' value3', 'key2': ' value22', 'key1': ' value1'}

5
Diese Lösung ist ordentlich und funktioniert hervorragend, wenn er sicher sein kann , dass seine Eingaben niemals drei oder mehr Spalten in einer Zeile enthalten. Sollte dies jedoch jemals der Fall sein, wird eine Ausnahme wie diese ausgelöst : ValueError: dictionary update sequence element #2 has length 3; 2 is required.
Nate

@ Maschine, nach dem Fehler in der Frage zu urteilen, hat die CSV-Datei mehr als 2 Spalten
John La Rooy

@gnibbler, nein, ein Fehler in der Frage ist auf das doppelte Entpacken der Zeile zurückzuführen. Zuerst versucht er, über den Leser zu iterieren und Zeilen zu erhalten, die eigentlich eine einzelne Zeile sind . Und wenn er versucht, diese einzelne Zeile zu durchlaufen, erhält er zwei Elemente, die nicht richtig ausgepackt werden können.
Alex Laskin

Ein allgemeiner Kommentar: Das Erstellen von Objekten, die aus iterablen Elementen im Speicher gespeichert sind, kann zu Speicherproblemen führen. Schlagen Sie vor, Ihren Speicherplatz und die Größe der iterierbaren Quelldatei zu überprüfen. Ein Hauptvorteil (der springende Punkt?) Von Iterables besteht darin, keine großen Dinge im Speicher zu halten.
Travellingbones

@Nate: Dies kann bei Bedarf behoben werden, indem der filterAnruf mit map(operator.itemgetter(slice(2)), ...)umbrochen wird, sodass nur die ersten beiden Punkte abgerufen werden dict(map(operator.itemgetter(slice(2)), filter(None, csv.reader(f)))). Wenn es sich um Python 2 handelt, stellen Sie sicher from future_builtins import map, filter, dass dies der dictFall ist , damit der Generator direkt gelesen wird, anstatt zuerst mehrere unnötige temporäre lists zu erzeugen .
ShadowRanger

12

Sie können hierfür auch numpy verwenden.

from numpy import loadtxt
key_value = loadtxt("filename.csv", delimiter=",")
mydict = { k:v for k,v in key_value }

5

Ich würde vorschlagen, hinzuzufügen, if rowsfalls am Ende der Datei eine leere Zeile steht

import csv
with open('coors.csv', mode='r') as infile:
    reader = csv.reader(infile)
    with open('coors_new.csv', mode='w') as outfile:
        writer = csv.writer(outfile)
        mydict = dict(row[:2] for row in reader if row)

Gut gemacht und durchdacht. Aber wie ich oben sagte, sollte er wirklich die Tatsache ignorieren, dass seine Eingabezeile länger ist als erwartet? Ich würde sagen, er sollte seine eigene Ausnahme (mit einer benutzerdefinierten Nachricht) auslösen, wenn er eine Zeile mit mehr als zwei Elementen erhält.
Maschinen Sehnsucht

Oder besser gesagt, wie oben von @Nate angegeben, zumindest eine Warnmeldung ausdrucken. Dies scheint einfach nicht etwas zu sein, das Sie ignorieren möchten.
Maschinen Sehnsucht

Ihre Antwort (im Gegensatz zu meiner) hat etwas zum Nachdenken gebracht - gibt es in diesem Fall einen Effizienzunterschied zwischen Schneiden und Indizieren?
Nate

1
@ Maschine, keine Ahnung. Vielleicht ist es ein Speicherauszug einer Benutzertabelle aus einer Datenbank, und er möchte nur ein Diktat der Benutzer-ID: Benutzername oder etwas zum Beispiel
John La Rooy

1
Hey Leute, danke für die Kommentare. Ihre Diskussion hat mir bei meinem Problem wirklich geholfen. Ich mag die Idee, ein Flag zu hissen, wenn die Eingabe länger als erwartet ist. Meine Daten sind ein Datenbankspeicherauszug und ich habe mehr als zwei Datenspalten.
drbunsen

5

Einzeilige Lösung

import pandas as pd

dict = {row[0] : row[1] for _, row in pd.read_csv("file.csv").iterrows()}

3

Wenn Sie mit der Verwendung des numpy-Pakets einverstanden sind, können Sie Folgendes tun:

import numpy as np

lines = np.genfromtxt("coors.csv", delimiter=",", dtype=None)
my_dict = dict()
for i in range(len(lines)):
   my_dict[lines[i][0]] = lines[i][1]

3

Für einfache CSV-Dateien wie die folgenden

id,col1,col2,col3
row1,r1c1,r1c2,r1c3
row2,r2c1,r2c2,r2c3
row3,r3c1,r3c2,r3c3
row4,r4c1,r4c2,r4c3

Sie können es nur mit integrierten Funktionen in ein Python-Wörterbuch konvertieren

with open(csv_file) as f:
    csv_list = [[val.strip() for val in r.split(",")] for r in f.readlines()]

(_, *header), *data = csv_list
csv_dict = {}
for row in data:
    key, *values = row   
    csv_dict[key] = {key: value for key, value in zip(header, values)}

Dies sollte das folgende Wörterbuch ergeben

{'row1': {'col1': 'r1c1', 'col2': 'r1c2', 'col3': 'r1c3'},
 'row2': {'col1': 'r2c1', 'col2': 'r2c2', 'col3': 'r2c3'},
 'row3': {'col1': 'r3c1', 'col2': 'r3c2', 'col3': 'r3c3'},
 'row4': {'col1': 'r4c1', 'col2': 'r4c2', 'col3': 'r4c3'}}

Hinweis: Python-Wörterbücher haben eindeutige Schlüssel. Wenn Ihre CSV-Datei also doppelt vorhanden ist ids, sollten Sie jede Zeile an eine Liste anhängen.

for row in data:
    key, *values = row

    if key not in csv_dict:
            csv_dict[key] = []

    csv_dict[key].append({key: value for key, value in zip(header, values)})

nb dies alles kann verkürzt werden mit set_default: csv_dict.set_default (key, []). append ({key: Wert für Schlüssel, Wert in zip (Header, Werte)})
mdmjsh

Die Syntax ({key: value}) in Ihrem .appendBefehl war sehr nützlich. row.updateBeim Iterieren und Hinzufügen zu einem DictReaderObjekt, das aus einer CSV-Datei erstellt wurde, habe ich dieselbe Syntax verwendet.
Shrout1

1

Sie können dies verwenden, es ist ziemlich cool:

import dataconverters.commas as commas
filename = 'test.csv'
with open(filename) as f:
      records, metadata = commas.parse(f)
      for row in records:
            print 'this is row in dictionary:'+rowenter code here

1

Es wurden viele Lösungen veröffentlicht, und ich möchte mit meinen einen Beitrag leisten, der für eine andere Anzahl von Spalten in der CSV-Datei funktioniert. Es wird ein Wörterbuch mit einem Schlüssel pro Spalte erstellt, und der Wert für jeden Schlüssel ist eine Liste mit den Elementen in dieser Spalte.

    input_file = csv.DictReader(open(path_to_csv_file))
    csv_dict = {elem: [] for elem in input_file.fieldnames}
    for row in input_file:
        for key in csv_dict.keys():
            csv_dict[key].append(row[key])

1

Mit Pandas ist es zum Beispiel viel einfacher. Angenommen, Sie haben die folgenden Daten als CSV und nennen wir sie test.txt/ test.csv(Sie wissen, dass CSV eine Art Textdatei ist).

a,b,c,d
1,2,3,4
5,6,7,8

jetzt mit Pandas

import pandas as pd
df = pd.read_csv("./text.txt")
df_to_doct = df.to_dict()

für jede Reihe wäre es

df.to_dict(orient='records')

und das ist es.


0

Versuchen Sie, ein defaultdictund zu verwenden DictReader.

import csv
from collections import defaultdict
my_dict = defaultdict(list)

with open('filename.csv', 'r') as csv_file:
    csv_reader = csv.DictReader(csv_file)
    for line in csv_reader:
        for key, value in line.items():
            my_dict[key].append(value)

Es gibt zurück:

{'key1':[value_1, value_2, value_3], 'key2': [value_a, value_b, value_c], 'Key3':[value_x, Value_y, Value_z]}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.