กำลังสร้างพจนานุกรมจากไฟล์ csv หรือไม่


153

ฉันพยายามสร้างพจนานุกรมจากไฟล์ csv คอลัมน์แรกของไฟล์ csv มีคีย์ที่ไม่ซ้ำกันและคอลัมน์ที่สองมีค่า แต่ละแถวของไฟล์ csv แสดงถึงคีย์ที่ไม่ซ้ำกันคู่ของค่าภายในพจนานุกรม ฉันพยายามใช้csv.DictReaderและcsv.DictWriterคลาส แต่ฉันสามารถหาวิธีสร้างพจนานุกรมใหม่สำหรับแต่ละแถวเท่านั้น ฉันต้องการพจนานุกรมหนึ่งฉบับ นี่คือรหัสที่ฉันพยายามใช้:

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)

ValueError: too many values to unpack (expected 2)เมื่อฉันเรียกใช้รหัสดังกล่าวข้างต้นที่ผมได้รับ ฉันจะสร้างหนึ่งพจนานุกรมจากไฟล์ csv ได้อย่างไร ขอบคุณ


2
คุณสามารถยกตัวอย่างไฟล์อินพุตและโครงสร้างข้อมูลผลลัพธ์ได้หรือไม่?
เบิร์ต

1
เมื่อคุณวนซ้ำ csv.reader คุณจะได้แถวเดียวไม่ใช่แถว ดังนั้นรูปแบบที่ถูกต้องคือ mydict = {k: v สำหรับ k, v ใน reader} แต่ถ้าคุณแน่ใจว่ามีเพียงสองคอลัมน์ในไฟล์ csv ดังนั้น mydict = dict (reader) จึงเร็วกว่ามาก
Alex Laskin

คำตอบ:


155

ฉันเชื่อว่าไวยากรณ์ที่คุณต้องการมีดังนี้:

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}

อีกทางเลือกหนึ่งสำหรับ python <= 2.7.1 คุณต้องการ:

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

2
ดีสำหรับบัญชีที่มีแถวยาวกว่าที่คาดไว้ แต่เขาไม่ควรยกข้อยกเว้นของตัวเองถ้ามีรายการมากเกินไปในแถว? ฉันคิดว่านั่นหมายความว่ามีข้อผิดพลาดกับข้อมูลอินพุตของเขา
เครื่องจักรโหยหา

1
จากนั้นอย่างน้อยเขาก็สามารถ จำกัด การยกเว้นให้เหลือความผิดพลาด
เครื่องโหยหา

นั่นเป็นข้อดี แต่ฉันเชื่อว่ามีข้อยกเว้นที่จะบอกคุณว่าคุณตั้งโปรแกรมบางอย่างไม่ถูกต้อง - ไม่ใช่เมื่อโลกให้เลมมอนแก่คุณ นั่นคือเมื่อคุณพิมพ์ข้อความแสดงข้อผิดพลาดสวยและล้มเหลวหรือ - เหมาะสมกว่าสำหรับกรณีนี้ - ข้อความเตือนสวยและประสบความสำเร็จ
เนท

ขออภัยดูรหัสของ op และยากที่จะบอกว่าเขาต้องการเพียง 2 รายการต่อบรรทัด ฉันผิดไป!
เครื่องจักรโหยหา

1
ฉันมีหลายบรรทัดใน csv แต่ให้เพียง 1 คีย์: คู่ค่า
Abhilash Mishra

80

csv.DictReaderเปิดไฟล์โดยการเรียกเปิดแล้ว

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

คุณสามารถวนซ้ำแถวของวัตถุ csv dict reader โดยทำซ้ำผ่าน input_file

for row in input_file:
    print(row)

หรือเพื่อเข้าถึงบรรทัดแรกเท่านั้น

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

อัพเดท ใน python 3+ เวอร์ชั่นรหัสนี้จะเปลี่ยนเล็กน้อย:

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

3
สิ่งนี้ทำให้วัตถุ DictReader ไม่ใช่พจนานุกรม (และใช่ไม่ใช่คู่ของค่าคีย์)
HN Singh

1
@HN Singh - ใช่ฉันรู้ - ความตั้งใจคือมันจะช่วยคนอื่นด้วย
Laxmikant Ratnaparkhi

1
วัตถุ 'DictReader' ไม่มีแอตทริบิวต์ 'ถัดไป'
Palak

1
@Palak - ได้รับคำตอบสำหรับ Python 2.7 ลองnext(dictobj)แทนdictobj.next()ใน 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

6
สไตล์ที่ไม่ไพเราะสูง
Alex Laskin

47
@Alex Laskin: จริงเหรอ? ดูเหมือนว่าฉันจะชอบงูหลาม คุณมีหลักการอะไรในการสำรองข้อความนี้? โดยพื้นฐานแล้วคุณเรียกเขาว่า "poopy head" ...
machine โหยหา

26
@ เครื่องโหยหาไม่ฉันไม่ได้พูดว่ารหัสของเขาคือ 'ไม่ดี' แต่ไม่มีเหตุผลเดียวที่จะเขียนfor row in reader: k, v = rowถ้าคุณสามารถเขียนfor k, v in readerได้ง่าย และถ้าคุณคาดหวังว่าผู้อ่านนั้นสามารถทำซ้ำได้สร้างรายการสององค์ประกอบจากนั้นคุณสามารถส่งโดยตรงไปยัง dict เพื่อการแปลง d = dict(reader)สั้นกว่ามากและเร็วกว่ามากในชุดข้อมูลขนาดใหญ่
Alex Laskin

44
@Alex Laskin: ขอบคุณสำหรับการชี้แจง ฉันเห็นด้วยกับคุณเป็นการส่วนตัว แต่ฉันคิดว่าถ้าคุณจะเรียกรหัสของใครบางคน "ไม่ใช่ pythonic" คุณควรมาพร้อมกับความคิดเห็นที่มีเหตุผล ฉันจะบอกว่า "สั้นลง" และ "เร็วขึ้น" ไม่จำเป็นต้องเทียบเท่ากับ การอ่าน / ความน่าเชื่อถือเป็นเรื่องที่ต้องคำนึงถึงเป็นอย่างมาก ถ้ามันง่ายกว่าที่จะทำงานในข้อ จำกัด บางอย่างของเราในfor row in readerกระบวนทัศน์ข้างต้นก็อาจ (หลังจากการพัฒนาระยะยาว) สามารถนำไปปฏิบัติได้มากขึ้น ฉันเห็นด้วยกับคุณในระยะสั้น แต่ระวังการปรับให้เหมาะสมก่อนเวลา
เครื่องจักรโหยหา

30

นี่ไม่ได้สวยงาม แต่เป็นโซลูชั่นบรรทัดเดียวที่ใช้แพนด้า

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

หากคุณต้องการระบุ dtype สำหรับดัชนีของคุณ (ไม่สามารถระบุได้ใน read_csv หากคุณใช้อาร์กิวเมนต์ index_col เนื่องจากข้อบกพร่อง ):

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

3
ในหนังสือของฉันนี่เป็นคำตอบที่ดีที่สุด
boardtc

และถ้ามีส่วนหัว ... ?
ndtreviv

@ndtreviv คุณสามารถใช้ skiprows เพื่อละเว้นส่วนหัวได้
mudassirkhan19

17

คุณต้องแปลง csv.reader เป็น 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'}

5
วิธีการแก้ปัญหานั้นเป็นระเบียบเรียบร้อยและจะทำงานได้ดีถ้าเขามั่นใจได้ว่าอินพุตของเขาจะไม่มีคอลัมน์สามคอลัมน์ขึ้นไปในบางแถว ValueError: dictionary update sequence element #2 has length 3; 2 is requiredแต่ถ้าที่เคยพบข้อยกเว้นบ้างเช่นนี้จะได้รับการเลี้ยงดู:
เนท

@ เครื่อง, การตัดสินจากข้อผิดพลาดในคำถาม, ไฟล์ csv มีมากกว่า 2 คอลัมน์
John La Rooy

@gnibbler ไม่มีข้อผิดพลาดในคำถามเกิดจากการเปิดแถวซ้ำสองครั้ง ครั้งแรกที่เขาพยายามที่จะย้ำกว่าผู้อ่านได้รับแถวที่เป็นจริงเดียวแถว และเมื่อเขาพยายามที่จะทำซ้ำแถวเดี่ยวนี้เขาจะได้รับสองรายการซึ่งไม่สามารถแตกไฟล์ได้อย่างถูกต้อง
Alex Laskin

ความคิดเห็นทั่วไป: การทำให้วัตถุที่เก็บไว้ในหน่วยความจำจาก iterables สามารถทำให้เกิดปัญหาหน่วยความจำ แนะนำให้ตรวจสอบพื้นที่หน่วยความจำของคุณและขนาดของไฟล์ต้นฉบับ iterable ข้อได้เปรียบหลัก (จุดรวม?) ของ iterables คือไม่เก็บสิ่งที่มีขนาดใหญ่ในหน่วยความจำ
travelingbones

@Nate: นั่นสามารถแก้ไขได้ถ้าจำเป็นโดยการตัดfilterการโทรที่มีmap(operator.itemgetter(slice(2)), ...)ดังนั้นมันจะดึงทั้งสอง iterms dict(map(operator.itemgetter(slice(2)), filter(None, csv.reader(f))))แรกทำให้มัน: หากเป็น Python 2 ให้แน่ใจว่าได้ทำfrom future_builtins import map, filterดังนั้นผู้สร้างdictจะอ่านโดยตรงแทนที่จะสร้างหลาย ๆ ชั่วคราวที่ไม่จำเป็นlistก่อน)
ShadowRanger

12

คุณสามารถใช้สิ่งนี้ได้

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

5

ฉันขอแนะนำให้เพิ่มif rowsในกรณีที่มีบรรทัดว่างที่ท้ายไฟล์

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)

ทั้งทำได้ดีและคิดดี แต่อย่างที่ฉันบอกไว้ข้างต้นเขาควรเพิกเฉยต่อข้อเท็จจริงที่ว่าบรรทัดอินพุตของเขายาวเกินกว่าที่เขาคาดไว้หรือไม่ ฉันว่าเขาควรยกข้อยกเว้นของเขาเอง (พร้อมข้อความที่กำหนดเอง) ถ้าเขาได้รับสายที่มีมากกว่าสองรายการ
เครื่องจักรโหยหา

หรือมากกว่านั้นตามที่ระบุไว้ข้างต้นโดย @Nate อย่างน้อยพิมพ์ข้อความเตือน นี่ดูเหมือนจะไม่เหมือนสิ่งที่คุณต้องการละเว้น
เครื่องจักรโหยหา

คำตอบของคุณ (เทียบกับของฉัน) ทำให้ไตร่ตรองบางสิ่งบางอย่าง - มีความแตกต่างอย่างมีประสิทธิภาพระหว่างการแบ่งส่วนและการจัดทำดัชนีในกรณีนี้หรือไม่
เนท

1
@ เครื่องไม่มีความคิด บางทีมันอาจเป็นดัมพ์ของตารางผู้ใช้จากฐานข้อมูลและเขาแค่ต้องการชื่อผู้ใช้: ชื่อผู้ใช้หรือบางอย่าง
John La Rooy

1
เฮ้พวกขอบคุณสำหรับความคิดเห็น การสนทนาของคุณช่วยฉันด้วยปัญหาของฉัน ฉันชอบความคิดเกี่ยวกับการเพิ่มธงหากอินพุตยาวเกินคาด ข้อมูลของฉันคือการถ่ายโอนข้อมูลฐานข้อมูลและฉันมีมากกว่าสองคอลัมน์ของข้อมูล
drbunsen


3

หากคุณตกลงกับการใช้แพ็คเกจ numpy คุณสามารถทำสิ่งต่อไปนี้ได้:

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

สำหรับไฟล์ csv อย่างง่ายเช่นต่อไปนี้

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

คุณสามารถแปลงเป็นพจนานุกรม Python ได้โดยใช้เพียงบิวด์อินเท่านั้น

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

นี่ควรจะให้พจนานุกรมต่อไปนี้

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

หมายเหตุ: พจนานุกรม Python มีคีย์ที่ไม่ซ้ำกันดังนั้นหากไฟล์ csv ของคุณซ้ำกันidsคุณควรต่อท้ายแต่ละแถวในรายการ

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

สิ่งนี้สามารถย่อให้ใช้ set_default: csv_dict.set_default (key, []). ผนวก ({key: ค่าสำหรับคีย์, ค่าเป็น zip (header, values)}))
mdmjsh

ไวยากรณ์ (คีย์: ค่า}) ใน.appendคำสั่งของคุณมีประโยชน์มาก ฉันลงเอยด้วยการใช้ซินแท็กซ์เดียวกันในการrow.updateวนซ้ำและเพิ่มลงในDictReaderวัตถุที่สร้างจากไฟล์ CSV
Shrout1

1

คุณสามารถใช้สิ่งนี้มันเจ๋งมาก:

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

มีการโพสต์โซลูชันจำนวนมากและฉันต้องการร่วมให้ข้อมูลกับฉันซึ่งใช้ได้กับคอลัมน์จำนวนมากในไฟล์ CSV มันสร้างพจนานุกรมที่มีหนึ่งคีย์ต่อคอลัมน์และค่าสำหรับแต่ละคีย์คือรายการที่มีองค์ประกอบในคอลัมน์ดังกล่าว

    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

ยกตัวอย่างเช่นกับแพนด้ามันง่ายกว่ามาก สมมติว่าคุณมีข้อมูลต่อไปนี้เป็น CSV และเรียกมันว่าtest.txt/ test.csv(คุณรู้ว่า CSV เป็นไฟล์ข้อความชนิดหนึ่ง)

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

ตอนนี้ใช้แพนด้า

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

สำหรับแต่ละแถวมันจะเป็น

df.to_dict(orient='records')

และนั่นคือมัน


0

พยายามที่จะใช้และdefaultdictDictReader

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)

มันกลับมา:

{'key1':[value_1, value_2, value_3], 'key2': [value_a, value_b, value_c], 'Key3':[value_x, Value_y, Value_z]}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.