Створення словника з файлу 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.