Tạo một từ điển từ một tập tin csv?


153

Tôi đang cố gắng tạo một từ điển từ tệp csv. Cột đầu tiên của tệp csv chứa các khóa duy nhất và cột thứ hai chứa các giá trị. Mỗi hàng của tệp csv đại diện cho một cặp khóa, giá trị duy nhất trong từ điển. Tôi đã cố gắng sử dụng csv.DictReadercsv.DictWritercác lớp, nhưng tôi chỉ có thể tìm ra cách tạo một từ điển mới cho mỗi hàng. Tôi muốn một từ điển. Đây là mã tôi đang cố gắng sử dụng:

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)

Khi tôi chạy đoạn mã trên tôi nhận được a ValueError: too many values to unpack (expected 2). Làm cách nào để tạo một từ điển từ tệp csv? Cảm ơn.


2
Bạn có thể cho một ví dụ về một tập tin đầu vào và cấu trúc dữ liệu kết quả?
robert

1
Khi bạn lặp lại qua csv.reader, bạn sẽ nhận được một hàng, không phải hàng. Vì vậy, biểu mẫu hợp lệ là mydict = {k: v cho k, v in reader} nhưng nếu bạn chắc chắn, chỉ có hai cột trong tệp csv, thì mydict = dict (reader) nhanh hơn nhiều.
Alex Laskin

Câu trả lời:


155

Tôi tin rằng cú pháp bạn đang tìm kiếm như sau:

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}

Cách khác, đối với python <= 2.7.1, bạn muốn:

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

2
Tốt cho tài khoản cho các hàng dài hơn dự kiến; Nhưng anh ta không nên đưa ra ngoại lệ của riêng mình nếu có quá nhiều mặt hàng liên tiếp? Tôi nghĩ điều đó có nghĩa là có lỗi với dữ liệu đầu vào của anh ấy.
máy khao khát

1
Và sau đó, ít nhất anh ta có thể thu hẹp ngoại lệ thành đầu vào bị lỗi
máy khao khát

Điều đó có một số giá trị, nhưng tôi là một người tin tưởng vững chắc rằng có ngoại lệ để nói với bạn rằng bạn đã lập trình một cái gì đó không chính xác - không phải khi thế giới cho bạn chanh. Đó là khi bạn in một thông báo lỗi khá hay và thất bại, hoặc - thích hợp hơn cho trường hợp này - một thông báo cảnh báo khá hay và thành công.
Nate

Xin lỗi, nhìn vào mã của op, thật khó để biết anh ta chỉ muốn 2 mục trên mỗi dòng. Tôi đã sai!
máy khao khát

1
Tôi đã có nhiều dòng trong csv nhưng nó chỉ cung cấp 1 khóa: cặp giá trị
Abhilash Mishra

80

Mở tệp bằng cách gọi mở và sau đó csv.DictReader.

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

Bạn có thể lặp qua các hàng của đối tượng đọc tệp csv bằng cách lặp qua input_file.

for row in input_file:
    print(row)

HOẶC Chỉ truy cập dòng đầu tiên

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

CẬP NHẬT Trong các phiên bản python 3+, mã này sẽ thay đổi một chút:

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

3
Điều này làm cho đối tượng DictReader không phải là một từ điển (và có không phải là một cặp giá trị chính)
HN Singh

1
@HN Singh - Vâng, tôi biết - ý định là nó cũng sẽ giúp được người khác
Laxmikant Ratnaparkhi

1
Đối tượng 'DictReader' không có thuộc tính 'tiếp theo'
Palak

1
@Palak - nó đã được trả lời cho Python 2.7, hãy thử next(dictobj)thay vì dictobj.next()trong các phiên bản 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
Phong cách không pythonic cao.
Alex Laskin

47
@Alex Laskin: Thật sao? Nó trông giống như một con trăn khá dễ đọc với tôi. Nguyên tắc của bạn để sao lưu tuyên bố này là gì? Về cơ bản, bạn chỉ cần gọi anh ấy là "đầu poopy" ...
cỗ máy khao khát

26
@ khao khát máy móc, không, tôi đã không nói rằng mã của anh ấy là 'xấu'. Nhưng không có một lý do duy nhất để viết for row in reader: k, v = rownếu bạn có thể viết đơn giản for k, v in reader, chẳng hạn. Và nếu bạn mong đợi, trình đọc đó là một mục lặp, tạo ra các mục hai phần tử, thì bạn có thể chỉ cần chuyển trực tiếp nó để ra lệnh cho chuyển đổi. d = dict(reader)ngắn hơn nhiều và nhanh hơn đáng kể trên các bộ dữ liệu khổng lồ.
Alex Laskin

44
@Alex Laskin: Cảm ơn bạn đã làm rõ. Cá nhân tôi đã đồng ý với bạn nhưng tôi nghĩ rằng nếu bạn sẽ gọi mã của ai đó là "không phải pythonic", bạn nên kèm theo nhận xét đó với lời biện minh. Tôi muốn nói rằng "ngắn hơn" và "nhanh hơn" không nhất thiết phải tương đương với "nhiều pythonic". Khả năng đọc / độ tin cậy là một mối quan tâm rất lớn là tốt. Nếu dễ dàng hơn để làm việc trong một số hạn chế của chúng tôi trong for row in readermô hình trên , thì có lẽ (sau khi phát triển dài hạn) sẽ thực tế hơn. Tôi đồng ý với bạn ngắn hạn, nhưng hãy cẩn thận với việc tối ưu hóa sớm.
máy khao khát

30

Đây không phải là thanh lịch mà là một giải pháp một dòng sử dụng gấu trúc.

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

Nếu bạn muốn chỉ định dtype cho chỉ mục của mình (nó không thể được chỉ định trong read_csv nếu bạn sử dụng đối số index_col vì lỗi ):

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

3
trong cuốn sách của tôi đây là câu trả lời hay nhất
boardtc

Và nếu có một tiêu đề ...?
ndtreviv

@ndtreviv bạn có thể sử dụng bỏ qua để bỏ qua các tiêu đề.
Mudassirkhan19 ngày

17

Bạn chỉ cần chuyển đổi csv.reader sang 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
giải pháp đó gọn gàng và sẽ hoạt động tốt nếu anh ta có thể chắc chắn rằng đầu vào của mình sẽ không bao giờ có ba hoặc nhiều cột trong một số hàng. Tuy nhiên, nếu điều đó đã từng gặp phải, một ngoại lệ như thế này sẽ được nêu ra : ValueError: dictionary update sequence element #2 has length 3; 2 is required.
Nate

@machine, đánh giá từ lỗi trong câu hỏi, tệp csv có hơn 2 cột
John La Rooy

@gnibbler, không, lỗi trong câu hỏi là do giải nén gấp đôi hàng. Đầu tiên anh ta cố gắng lặp đi lặp lại qua đầu đọc, thu được các hàng thực sự là một hàng đơn . Và khi anh ta cố gắng lặp lại hàng này, anh ta nhận được hai mục, không thể giải nén chính xác.
Alex Laskin

Một nhận xét chung: làm cho các đối tượng được giữ trong bộ nhớ từ iterables có thể gây ra vấn đề về bộ nhớ. Đề nghị kiểm tra dung lượng bộ nhớ của bạn và kích thước của tệp nguồn lặp. Một lợi thế chính (toàn bộ điểm?) Của iterables là không giữ những thứ lớn trong bộ nhớ.
đi du lịch

@Nate: Điều đó có thể được sửa nếu cần thiết bằng cách kết thúc filtercuộc gọi map(operator.itemgetter(slice(2)), ...), vì vậy nó sẽ chỉ kéo hai vòng lặp đầu tiên, thực hiện nó : dict(map(operator.itemgetter(slice(2)), filter(None, csv.reader(f)))). Nếu đó là Python 2, hãy đảm bảo thực hiện from future_builtins import map, filter, vì vậy, trình dictđọc trực tiếp, thay vì tạo ra nhiều lists tạm thời không cần thiết trước tiên).
ShadowRanger

12

Bạn cũng có thể sử dụng numpy cho việc này.

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

5

Tôi khuyên bạn nên thêm if rowsvào trong trường hợp có một dòng trống ở cuối tệp

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)

Cả hai đều được thực hiện tốt và chu đáo. Nhưng như tôi đã nói ở trên, anh ta thực sự nên bỏ qua thực tế là dòng đầu vào của anh ta dài hơn anh ta mong đợi? Tôi muốn nói rằng anh ta nên đưa ra ngoại lệ của riêng mình (với một tin nhắn tùy chỉnh) nếu anh ta nhận được một dòng có nhiều hơn hai mục.
máy khao khát

Hay đúng hơn, như đã nêu ở trên bởi @Nate, ít nhất là in một thông điệp cảnh báo. Điều này dường như không giống như một cái gì đó bạn muốn bỏ qua.
máy khao khát

câu trả lời của bạn (so với của tôi) đã khiến người ta suy ngẫm điều gì đó - có sự khác biệt hiệu quả giữa việc cắt và lập chỉ mục trong trường hợp này không?
Nate

1
@machine, không có ý kiến. Có lẽ đó là một bãi chứa bảng người dùng từ cơ sở dữ liệu và anh ta chỉ muốn một lệnh của userid: tên người dùng hoặc một cái gì đó chẳng hạn
John La Rooy

1
Hey các bạn, cảm ơn cho ý kiến. Cuộc thảo luận của bạn thực sự giúp tôi giải quyết vấn đề của mình. Tôi thích ý tưởng về việc tăng cờ nếu đầu vào dài hơn dự kiến. Dữ liệu của tôi là kết xuất cơ sở dữ liệu và tôi có nhiều hơn hai cột dữ liệu.
drbunsen

5

Giải pháp một lớp lót

import pandas as pd

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

3

Nếu bạn ổn với việc sử dụng gói numpy, thì bạn có thể làm một cái gì đó như sau:

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

Đối với các tệp csv đơn giản, chẳng hạn như sau

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

Bạn có thể chuyển đổi nó thành một từ điển Python chỉ bằng cách sử dụng

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

Điều này sẽ mang lại từ điển sau

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

Lưu ý: Từ điển Python có các khóa duy nhất, vì vậy nếu tệp csv của bạn trùng lặp, idsbạn nên nối từng hàng vào danh sách.

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 điều này hoàn toàn có thể được rút ngắn để sử dụng set_default: csv_dict.set_default (key, []). append ({key: value cho khóa, value trong zip (tiêu đề, giá trị)}))
mdmjsh

Cú pháp ({key: value}) trong .appendlệnh của bạn rất hữu ích. Tôi đã kết thúc bằng cách sử dụng cùng một cú pháp row.updatekhi lặp đi lặp lại và thêm vào một DictReaderđối tượng được tạo từ tệp CSV.
Shrout1

1

Bạn có thể sử dụng cái này, nó khá tuyệt:

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

Nhiều giải pháp đã được đăng và tôi muốn đóng góp cho tôi, giải pháp này hoạt động cho một số cột khác nhau trong tệp CSV. Nó tạo ra một từ điển với một khóa cho mỗi cột và giá trị cho mỗi khóa là một danh sách với các thành phần trong cột đó.

    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

với gấu trúc, nó dễ dàng hơn nhiều, ví dụ. giả sử bạn có dữ liệu sau dưới dạng CSV và hãy gọi nó test.txt/ test.csv(bạn biết CSV là một loại tệp văn bản)

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

hiện đang sử dụng gấu trúc

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

cho mỗi hàng, nó sẽ là

df.to_dict(orient='records')

và đó là nó.


0

Hãy thử sử dụng một 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)

Nó trở lại:

{'key1':[value_1, value_2, value_3], 'key2': [value_a, value_b, value_c], 'Key3':[value_x, Value_y, Value_z]}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.