Bir csv dosyasından sözlük mi oluşturuyorsunuz?


153

Bir csv dosyasından bir sözlük oluşturmaya çalışıyorum. Csv dosyasının ilk sütunu benzersiz anahtarlar ve ikinci sütunu değerler içerir. Csv dosyasının her satırı, sözlük içindeki benzersiz bir anahtar, değer çiftini temsil eder. csv.DictReaderVe csv.DictWritersınıflarını kullanmaya çalıştım , ancak her satır için nasıl yeni bir sözlük oluşturacağımı anlayabiliyordum. Bir sözlük istiyorum. İşte kullanmaya çalıştığım kod:

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)

Yukarıdaki kodu çalıştırdığımda bir olsun ValueError: too many values to unpack (expected 2). Bir csv dosyasından nasıl sözlük oluşturabilirim? Teşekkürler.


2
Bir giriş dosyası ve ortaya çıkan veri yapısına bir örnek verebilir misiniz?
Robert

1
Csv.reader üzerinde yineleme yaptığınızda, satırları değil, tek satırı alırsınız. Dolayısıyla, geçerli form mydict = {k: v for k, v in reader} dır, ancak eminseniz csv dosyasında yalnızca iki sütun olduğundan eminseniz mydict = dict (reader) çok daha hızlıdır.
Alex Laskin

Yanıtlar:


155

Aradığınız sözdiziminin aşağıdaki gibi olduğuna inanıyorum:

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}

Alternatif olarak, python <= 2.7.1 için:

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

2
Beklenenden daha uzun satırları açıklamak iyi; ancak arka arkaya çok fazla öğe varsa kendi istisnasını yükseltmemeli midir? Bunun giriş verilerinde bir hata olduğu anlamına gelirdi.
makine özlemi

1
Ve sonra en azından istisnayı hatalı girdilere daraltabilirdi
makine özlemi

Bunun bir değeri var, ama ben bir şeyi yanlış programladığınızı söylemek için istisnaların var olduğuna inanıyorum - dünya size limon verdiğinde değil. İşte o zaman güzel bir hata mesajı yazdırır ve başarısız olur, ya da - bu durumda daha uygun - güzel bir uyarı mesajı alır ve başarılı olur.
Nate

Üzgünüz, op'un koduna baktı, satır başına sadece 2 ürün isteyip istemediğini söylemek zor. Ben hatalıydım!
makine özlemi

1
CSV'de birden fazla satır vardı ama sadece 1 anahtar verdi: değer çifti
Abhilash Mishra

80

Dosyayı aç ve ardından çağırarak açın csv.DictReader.

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

İnput_file üzerinden yineleyerek csv dosyası dict okuyucu nesnesinin satırları üzerinde yineleme yapabilirsiniz.

for row in input_file:
    print(row)

VEYA Yalnızca ilk satıra erişmek için

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

GÜNCELLEME python 3+ sürümlerinde bu kod biraz değişecektir:

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

3
Bu, DictReader nesnesini bir sözlük değil (ve evet bir anahtar değer çifti değil) yapar
HN Singh

1
@HN Singh - Evet, biliyorum - niyet başkalarına da yardımcı olacaktı
Laxmikant Ratnaparkhi

1
'DictReader' nesnesinin 'next' özelliği yoktur
Palak

1
@Palak - Python 2.7 için cevaplandı , Python 3+ sürümleri next(dictobj)yerine deneyin dictobj.next().
Laxmikant Ratnaparkhi

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

6
Son derece pythonic olmayan bir stil.
Alex Laskin

47
@ Laslex: Gerçekten mi? Bana oldukça okunabilir bir piton gibi görünüyor. Bu ifadeyi destekleme ilkeniz nedir? Temelde ona sadece "poopy kafa" dediniz ...
makine temmuz

26
@ makine özlemi, hayır, kodunun 'kötü' olduğunu söylemedim. Ancak , örneğin for row in reader: k, v = rowyazabiliyorsanız yazmak için tek bir neden yoktur for k, v in reader. Ve eğer beklerseniz, bu okuyucu iki elementli öğeler üreten tekrarlanabilir bir şeydir, o zaman doğrudan dönüştürme için dikte etmek için iletebilirsiniz. d = dict(reader)büyük veri kümelerinde çok daha kısa ve önemli ölçüde daha hızlıdır.
Alex Laskin

44
@Alex Laskin: Açıklama için teşekkürler. Ben şahsen seninle aynı fikirdeydim ama bence birinin kodunu "pitonik olmayan" olarak adlandıracaksan, bu yoruma bir gerekçe ile eşlik etmelisin. Ben "daha kısa" ve "daha hızlı" mutlaka "daha pitonik" eşdeğer olmadığını söyleyebilirim. Okunabilirlik / güvenilirlik de büyük bir endişe kaynağıdır. Yukarıdaki for row in readerparadigmadaki bazı kısıtlamalarımızda çalışmak daha kolaysa, (uzun vadeli gelişimden sonra) daha pratik olabilir. Size kısa vadeli olarak katılıyorum, ancak erken optimizasyona dikkat edin.
makine özlemi

30

Bu zarif değil, panda kullanan tek satırlık bir çözüm.

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

Dizininiz için dtype belirtmek istiyorsanız (bir hata nedeniyle index_col bağımsız değişkenini kullanırsanız, read_csv dosyasında belirtilemez ):

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

3
kitabımda bu en iyi cevap
boardtc

Ve bir başlık varsa ...?
ndtreviv

@ndtreviv başlıkları yoksaymak için atlama çubuklarını kullanabilirsiniz.
mudassirkhan19

17

Sadece dikte etmek için csv.reader dönüştürmek zorunda:

~ >> 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
bu çözüm derli topludır ve girdilerinin hiçbir zaman üç veya daha fazla sütuna sahip olmayacağından emin olabilirse harika çalışır . Bu şimdiye kadar karşılaştığım Ancak, biraz böyle bir özel durum arttırılacaktır: ValueError: dictionary update sequence element #2 has length 3; 2 is required.
Nate

machine, sorudaki hatadan yola çıkarak, csv dosyasında 2'den fazla sütun var
John La Rooy

@gnibbler, hayır, sorudaki hata satırın iki kez açılmasından kaynaklanıyor. İlk önce okuyucuyu yinelemeye çalışır , aslında tek sıra olan satırları elde eder . Ve bu tek sıra üzerinde yinelemeye çalıştığında, doğru bir şekilde açılamayan iki öğe alır.
Alex Laskin

Genel bir yorum: bellekte yinelenebilir nesnelerden tutulan nesnelerin yapılması bellek problemine neden olabilir. Bellek alanınızı ve yinelenebilir kaynak dosyasının boyutunu kontrol etmenizi öneririz. Yinelenebilirlerin ana avantajı (bütün nokta?) Büyük şeyleri hafızada tutmamaktır.
travelingbones

@Nate: Yani gerekirse sararak sabitlenebilir filterile çağrı map(operator.itemgetter(slice(2)), ...)sadece o yapım ilk iki iterms çeker, böylece: dict(map(operator.itemgetter(slice(2)), filter(None, csv.reader(f)))). Python 2 ise, yaptığınızdan emin olun from future_builtins import map, filter, bu yüzden önce dictbirden fazla gereksiz geçici üretmek yerine bir jeneratörü doğrudan okur list).
ShadowRanger

12

Bunun için numpy de kullanabilirsiniz.

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

5

if rowsDosyanın sonunda boş bir satır olması durumunda eklemeyi öneririm

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)

Hem iyi yapılmış hem de iyi düşünülmüş. Ama yukarıda söylediğim gibi, giriş hattının beklediğinden daha uzun olduğu gerçeğini gerçekten görmezden gelmeli mi? İkiden fazla öğe içeren bir satır alırsa, kendi özel durumunu (özel bir mesajla) yükseltmesi gerektiğini söyleyebilirim.
makine özlemi

Daha doğrusu, yukarıda @Nate tarafından belirtildiği gibi, en azından bir uyarı mesajı yazdırın. Bu görmezden gelmek isteyeceğiniz bir şey gibi görünmüyor.
makine özlemi

cevabınız (benimkine karşı) bir şey düşünmeye başladı - bu durumda dilimleme ve indeksleme arasında bir verimlilik farkı var mı?
Nate

1
Makine, fikrim yok. Belki de bir veritabanından bir kullanıcı tablosunun dökümü ve sadece kullanıcı kimliği bir diksiyon istiyor: kullanıcı adı veya örneğin bir şey
John La Rooy

1
Hey millet, yorumlar için teşekkürler. Tartışmanız gerçekten sorunumda bana yardımcı oldu. Girdi beklenenden daha uzunsa bir bayrak kaldırmayla ilgili fikri seviyorum. Verilerim bir veritabanı dökümü ve ikiden fazla veri sütunum var.
drbunsen

5

Tek katmanlı çözüm

import pandas as pd

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

3

Numpy paketini kullanmakta sorun yaşıyorsanız, aşağıdakine benzer bir şey yapabilirsiniz:

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

Aşağıdaki gibi basit csv dosyaları için

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

Yalnızca yerleşik kullanarak bir Python sözlüğüne dönüştürebilirsiniz

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

Bu şu sözlüğü vermelidir

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

Not: Python sözlüklerinin benzersiz anahtarları vardır, bu nedenle csv dosyanızda yinelenme idsvarsa, her satırı bir listeye eklemeniz gerekir.

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 bunların tümü şu şekilde kısaltılabilir set_default: csv_dict.set_default (key, []). append ({key: key değeri, zip değeri (başlık, değerler)}))
mdmjsh

.appendKomutunuzdaki ({key: value}) sözdizimi çok faydalı oldu. Ben bir row.updateyineleme ve DictReaderbir CSV dosyasından yapılmış bir nesneye eklerken aynı sözdizimi kullanarak sona erdi .
Shrout1

1

Bunu kullanabilirsiniz, oldukça havalı:

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

Birçok çözüm gönderildi ve CSV dosyasındaki farklı sayıda sütun için çalışan madene katkıda bulunmak istiyorum. Sütun başına bir anahtar içeren bir sözlük oluşturur ve her anahtarın değeri, bu sütundaki öğelerin yer aldığı bir listedir.

    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

pandalarla, örneğin, çok daha kolaydır. CSV olarak aşağıdaki verilere sahip olduğunuzu varsayalım ve diyelim test.txt/ test.csv(CSV'nin bir tür metin dosyası olduğunu biliyorsunuz)

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

şimdi pandaları kullanıyor

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

her satır için

df.to_dict(orient='records')

ve bu kadar.


0

A defaultdictve kullanmayı deneyin 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)

Döndürür:

{'key1':[value_1, value_2, value_3], 'key2': [value_a, value_b, value_c], 'Key3':[value_x, Value_y, Value_z]}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.