Створення словника з файлу 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, ви отримуєте один рядок, а не рядки. Отже, дійсна форма - це мій вирок = {k: v для k, v у читачі}, але якщо ви впевнені, що у файлі csv є лише два стовпці, то мій presd = dict (читач) набагато швидше.
Алекс Ласкін

Відповіді:


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
І тоді він, принаймні, зміг би звузити виняток до несправного введення
машина, яка тужила

У цьому є певна заслуга, але я твердо вірю, що є винятки, які говорять вам про те, що ви програмували щось неправильно - не для того, коли світ дає вам лимони. Ось тоді ви надрукуєте симпатичне повідомлення про помилку і не працюєте, або - що більше підходить для даного випадку - досить попереджувальне повідомлення та успішно.
Нейт

Вибачте, подивився на код ОП, важко сказати, чи хотів він лише 2 позиції на рядок. Я був неправий!
машина, яка тужить

1
У мене було кілька рядків у CSV, але він дав лише 1 ключ: пара значень
Абхілаш Мішра

80

Відкрийте файл, зателефонувавши відкрити, а потім csv.DictReader.

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

Ви можете повторити рядки об'єкта зчитувача файлів csv, повторивши його через 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 - Так, я знаю - намір полягав у тому, що він допоможе ще
комусь

1
Об'єкт "DictReader" не має атрибута "наступний"
Палак,

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
Сильно непітонічний стиль.
Алекс Ласкін

47
@Alex Laskin: Дійсно? Це схоже на якийсь досить читабельний пітон для мене. Який ваш принцип підтримувати цю заяву? Ви в основному просто називали його "ковпаковою головою" ...
машина, яка тужила

26
@ машинне прагнення, ні, я не сказав, що його код "поганий". Але немає єдиної причини писати, for row in reader: k, v = rowякщо ви можете просто написати for k, v in reader, наприклад. І якщо ви очікуєте, що цей читач є ітерабельним, створюючи двоелементні елементи, то ви можете просто передати його безпосередньо для прорисування для перетворення. d = dict(reader)набагато коротше і значно швидше на величезних наборах даних.
Алекс Ласкін

44
@ Алекс Ласкін: Дякую за пояснення. Я особисто погодився з вами, але думаю, що якщо ви назвете чийсь код "непітонічним", ви повинні супроводжувати цей коментар обгрунтуванням. Я б сказав, що "коротший" і "швидший" не обов'язково еквівалентний "більш пітонічному". Читання / надійність також викликає величезне занепокоєння. Якщо легше працювати в деяких наших обмеженнях у вищезгаданій 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 в диктат:

~ >> 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.
Нейт

@machine, судячи з помилки у запитанні, файл csv має більше 2 стовпців
Джон Ла Рой,

@ gnibbler, ні, помилка в питанні пов'язана з подвійним розпакуванням рядка. Спочатку він спробує перебрати читання, отримуючи рядки, які насправді є одним рядком . І коли він намагається перебрати цей ряд, він отримує два елементи, які неможливо розпакувати правильно.
Алекс Ласкін

Загальний коментар: створення об'єктів, що зберігаються в пам'яті, з ітерабелів, може спричинити проблеми з пам'яттю. Запропонуйте перевірити об'єм пам’яті та розмір ітерабельного вихідного файлу. Основна перевага (вся суть?) Ітерабелів - не зберігати великі речі в пам'яті.
подорожні

@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спочатку створювати кілька непотрібних тимчасових s).
ShadowRanger

12

Для цього також можна використовувати numpy.

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
@machine, не маю ідеї. Можливо, це дамп таблиці користувачів із бази даних, і він просто хоче накреслити userid: ім'я користувача або щось на зразок
John La Rooy

1
Гей, хлопці, дякую за коментарі. Ваше обговорення справді допомогло мені вирішити мою проблему. Мені подобається ідея про підняття прапора, якщо вхід довший, ніж очікувалося. Мої дані - це дамп бази даних, і я маю більше двох стовпців даних.
drbunsen

5

Однолінійний розчин

import pandas as pd

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

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

nb це все можна скоротити до використання set_default: csv_dict.set_default (ключ, []). append ({ключ: значення для ключа, значення в zip (заголовок, значення)}))
mdmjsh

Синтаксис ({key: value}) у вашій .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

Спробуйте використати defaultdictі 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)

Він повертає:

{'key1':[value_1, value_2, value_3], 'key2': [value_a, value_b, value_c], 'Key3':[value_x, Value_y, Value_z]}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.