Membuat kamus dari file csv?

153

Saya mencoba membuat kamus dari file csv. Kolom pertama dari file csv berisi kunci unik dan kolom kedua berisi nilai. Setiap baris file csv mewakili kunci unik, pasangan nilai dalam kamus. Saya mencoba menggunakan csv.DictReaderdan csv.DictWriterkelas, tetapi saya hanya bisa mengetahui cara membuat kamus baru untuk setiap baris. Saya ingin satu kamus. Berikut adalah kode yang saya coba gunakan:

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)

Ketika saya menjalankan kode di atas saya mendapatkan ValueError: too many values to unpack (expected 2). Bagaimana cara membuat satu kamus dari file csv? Terima kasih.

drbunsen
sumber
2
Bisakah Anda memberikan contoh file input dan struktur data yang dihasilkan?
robert
1
Saat Anda mengulangi csv.reader, Anda mendapatkan satu baris, bukan baris. Jadi, formulir yang valid adalah mydict = {k: v untuk k, v di reader} tetapi jika Anda yakin, bahwa hanya ada dua kolom dalam file csv, maka mydict = dict (reader) jauh lebih cepat.
Alex Laskin

Jawaban:

156

Saya percaya sintaks yang Anda cari adalah sebagai berikut:

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}

Bergantian, untuk python <= 2.7.1, Anda ingin:

mydict = dict((rows[0],rows[1]) for rows in reader)
Nate
sumber
2
Bagus untuk menghitung baris yang lebih lama dari yang diharapkan; tetapi bukankah seharusnya dia mengajukan pengecualian sendiri jika ada terlalu banyak item dalam satu baris? Saya akan berpikir itu berarti ada kesalahan dengan data inputnya.
Kerinduan mesin
1
Dan kemudian dia setidaknya bisa mempersempit pengecualian menjadi input yang salah
kerinduan mesin
Itu memiliki beberapa kelebihan, tetapi saya sangat percaya bahwa ada pengecualian untuk memberi tahu Anda bahwa Anda memprogram sesuatu secara tidak benar - bukan karena ketika dunia memberi Anda lemon. Saat itulah Anda mencetak pesan kesalahan yang cantik dan gagal, atau - lebih tepat untuk kasus ini - pesan peringatan yang cantik dan berhasil.
Nate
Maaf, melihat kode op, sulit untuk mengetahui apakah dia hanya menginginkan 2 item per baris. Saya salah!
Kerinduan mesin
1
Saya memiliki beberapa baris dalam csv tetapi hanya memberi 1 kunci: pasangan nilai
Abhilash Mishra
80

Buka file dengan memanggil open lalu csv.DictReader.

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

Anda dapat mengulangi baris dari objek pembaca file csv dicter dengan mengulangi input_file.

for row in input_file:
    print(row)

ATAU Untuk mengakses saluran pertama saja

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

PEMBARUAN Dalam versi python 3+, kode ini akan berubah sedikit:

reader = csv.DictReader(open('coors.csv'))
dictobj = next(reader) 
Laxmikant Ratnaparkhi
sumber
3
Ini membuat objek DictReader bukan kamus (dan ya bukan pasangan nilai kunci)
HN Singh
1
@HN Singh - Ya, saya tahu - niatnya adalah itu akan membantu orang lain juga
Laxmikant Ratnaparkhi
1
Objek 'DictReader' tidak memiliki atribut 'berikutnya'
Palak
1
@ Palak - itu dijawab untuk Python 2.7, coba next(dictobj)bukan dictobj.next()dalam versi Python 3+.
Laxmikant Ratnaparkhi
61
import csv
reader = csv.reader(open('filename.csv', 'r'))
d = {}
for row in reader:
   k, v = row
   d[k] = v
robert
sumber
6
Gaya yang sangat non-pythonic.
Alex Laskin
47
@ Alex Laskin: Benarkah? Sepertinya beberapa python cukup mudah dibaca bagi saya. Apa prinsip Anda untuk mendukung pernyataan ini? Anda pada dasarnya hanya memanggilnya "poopy head" ...
kerinduan mesin
26
@ Kerinduan mesin, tidak, saya tidak mengatakan bahwa kodenya 'buruk'. Tetapi tidak ada alasan tunggal untuk menulis for row in reader: k, v = rowjika Anda bisa menulis for k, v in reader, misalnya. Dan jika Anda berharap, pembaca itu adalah item dua elemen yang dapat diubah, maka Anda dapat meneruskannya langsung ke dikt untuk konversi. d = dict(reader)jauh lebih pendek dan lebih cepat secara signifikan pada dataset besar.
Alex Laskin
44
@ Alex Laskin: Terima kasih atas klarifikasi. Saya pribadi setuju dengan Anda, tetapi saya pikir jika Anda akan memanggil kode seseorang "non-pythonic" Anda harus menemani komentar itu dengan justifikasi. Saya akan mengatakan bahwa "lebih pendek" dan "lebih cepat" belum tentu setara dengan "lebih pythonic". Keterbacaan / keandalan juga merupakan masalah besar. Jika lebih mudah untuk bekerja dalam beberapa kendala kita ke dalam for row in readerparadigma di atas , maka mungkin (setelah pengembangan jangka panjang) lebih praktis. Saya setuju dengan Anda jangka pendek, tetapi waspadalah terhadap pengoptimalan prematur.
Kerinduan mesin
30

Ini tidak elegan tetapi solusi satu baris menggunakan panda.

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

Jika Anda ingin menentukan tipe untuk indeks Anda (itu tidak dapat ditentukan dalam read_csv jika Anda menggunakan argumen index_col karena suatu bug ):

import pandas as pd
pd.read_csv('coors.csv', header=None, dtype={0: str}).set_index(0).squeeze().to_dict()
mudassirkhan19
sumber
3
dalam buku saya ini adalah jawaban terbaik
boardtc
Dan jika ada tajuk ...?
ndtreviv
@ndtreviv Anda dapat menggunakan loncatan untuk mengabaikan tajuk.
mudassirkhan19
17

Anda harus mengonversi csv.reader menjadi dict:

~ >> 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'}
Alex Laskin
sumber
5
solusi itu rapi, dan akan bekerja dengan baik jika dia bisa yakin bahwa inputnya tidak akan pernah memiliki tiga kolom atau lebih dalam satu baris. Namun, jika yang pernah mengalami, pengecualian agak seperti ini akan dibangkitkan: ValueError: dictionary update sequence element #2 has length 3; 2 is required.
Nate
@machine, dilihat dari kesalahan dalam pertanyaan, file csv memiliki lebih dari 2 kolom
John La Rooy
@gnibbler, tidak, kesalahan dalam pertanyaan adalah karena membongkar baris ganda. Pertama ia mencoba untuk beralih dari pembaca, memperoleh baris yang sebenarnya satu baris . Dan ketika dia mencoba untuk mengulangi satu baris ini, dia mendapatkan dua item, yang tidak dapat dibongkar dengan benar.
Alex Laskin
Komentar umum: membuat objek yang disimpan dalam memori dari iterables dapat menyebabkan masalah memori. Sarankan memeriksa ruang memori Anda dan ukuran file sumber iterable. Keuntungan utama (keseluruhan poin?) Dari iterables adalah tidak menyimpan hal-hal besar dalam memori.
travelingbones
@Nate: Itu bisa diperbaiki jika perlu dengan membungkus filterpanggilan dengan map(operator.itemgetter(slice(2)), ...), sehingga hanya akan menarik dua iterms pertama, sehingga: dict(map(operator.itemgetter(slice(2)), filter(None, csv.reader(f)))). Jika itu Python 2, pastikan untuk melakukannya from future_builtins import map, filter, jadi dictmembaca generator secara langsung, alih-alih menghasilkan beberapa sementara yang tidak perlu listterlebih dahulu).
ShadowRanger
12

Anda juga bisa menggunakan numpy untuk ini.

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

Saya sarankan menambahkan if rowskalau-kalau ada baris kosong di akhir file

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)
John La Rooy
sumber
Baik dilakukan dan dipikirkan dengan baik. Tapi seperti yang saya katakan di atas, haruskah dia benar-benar mengabaikan fakta bahwa jalur inputnya lebih panjang dari yang dia harapkan? Saya akan mengatakan bahwa dia harus mengajukan pengecualian sendiri (dengan pesan khusus) jika dia mendapatkan garis dengan lebih dari dua item.
Kerinduan mesin
Atau lebih tepatnya, seperti yang dinyatakan di atas oleh @Nate, setidaknya cetak pesan peringatan. Sepertinya ini bukan sesuatu yang ingin Anda abaikan.
Kerinduan mesin
jawaban Anda (vs saya) membuat merenungkan sesuatu - apakah ada perbedaan efisiensi antara mengiris dan mengindeks dalam hal ini?
Nate
1
@machine, tidak tahu. Mungkin itu adalah dump dari tabel pengguna dari database, dan dia hanya ingin dict dari userid: nama pengguna atau sesuatu misalnya
John La Rooy
1
Hai teman-teman, terima kasih atas komentarnya. Diskusi Anda benar-benar membantu saya mengatasi masalah saya. Saya suka ide tentang mengibarkan bendera jika input lebih panjang dari yang diharapkan. Data saya adalah dump basis data dan saya memiliki lebih dari dua kolom data.
drbunsen
5

Solusi satu lapis

import pandas as pd

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

Jika Anda setuju dengan menggunakan paket numpy, maka Anda dapat melakukan sesuatu seperti berikut:

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]
berawanBlues
sumber
3

Untuk file csv sederhana, seperti berikut ini

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

Anda dapat mengonversinya ke kamus Python hanya menggunakan built-in

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)}

Ini harus menghasilkan kamus berikut

{'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'}}

Catatan: Kamus python memiliki kunci unik, jadi jika file csv Anda memiliki duplikat idsAnda harus menambahkan setiap baris ke daftar.

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)})
yellow01
sumber
nb ini semua dapat disingkat menggunakan set_default: csv_dict.set_default (key, []). append ({key: value for key, value in zip (header, values)}))
mdmjsh
Sintaks ({key: value}) pada .appendperintah Anda sangat berguna. Saya akhirnya menggunakan sintaks yang sama dalam row.updateit iterasi dan menambahkan ke DictReaderobjek yang dibuat dari file CSV.
Shrout1
1

Anda dapat menggunakan ini, itu sangat keren:

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
dipalu
sumber
1

Banyak solusi telah diposting dan saya ingin berkontribusi dengan saya, yang berfungsi untuk sejumlah kolom dalam file CSV. Itu menciptakan kamus dengan satu kunci per kolom, dan nilai untuk setiap kunci adalah daftar dengan unsur-unsur dalam kolom tersebut.

    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])
Alejandro Villegas
sumber
1

dengan panda, itu jauh lebih mudah, misalnya. dengan asumsi Anda memiliki data berikut sebagai CSV dan sebut saja test.txt/ test.csv(Anda tahu CSV adalah semacam file teks)

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

sekarang menggunakan panda

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

untuk setiap baris, itu akan menjadi

df.to_dict(orient='records')

dan hanya itu.

TheTechGuy
sumber
0

Coba gunakan a defaultdictdan 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)

Ia mengembalikan:

{'key1':[value_1, value_2, value_3], 'key2': [value_a, value_b, value_c], 'Key3':[value_x, Value_y, Value_z]}
Paulo Henrique Zen
sumber