Создание словаря из файла csv?

Я пытаюсь создать словарь из файла 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? Спасибо.


person drbunsen    schedule 19.07.2011    source источник
comment
Вы можете привести пример входного файла и результирующей структуры данных?   -  person robert    schedule 19.07.2011
comment
Когда вы перебираете csv.reader, вы получаете одну строку, а не строки. Итак, допустимая форма - mydict = {k: v для k, v в reader}, но если вы уверены, что в файле csv всего два столбца, тогда mydict = dict (reader) работает намного быстрее.   -  person Alex Laskin    schedule 19.07.2011


Ответы (16)


Я считаю, что синтаксис, который вы искали, выглядит следующим образом:

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)
person Nate    schedule 19.07.2011
comment
Хорошо, если строки длиннее, чем ожидалось; но не должен ли он создавать собственное исключение, если в строке слишком много элементов? Я бы подумал, что это будет означать ошибку с его входными данными. - person machine yearning; 19.07.2011
comment
И тогда он, по крайней мере, сможет сузить исключение до ошибочного ввода. - person machine yearning; 19.07.2011
comment
В этом есть некоторые достоинства, но я твердо верю, что существуют исключения, которые говорят вам, что вы что-то запрограммировали неправильно, а не тогда, когда мир дает вам лимоны. Это когда вы печатаете красивое сообщение об ошибке и терпите неудачу или - что более уместно в этом случае - красивое предупреждающее сообщение и преуспеваете. - person Nate; 19.07.2011
comment
Извините, посмотрел на код операции, трудно сказать, нужно ли ему только 2 элемента в строке. Я был неправ! - person machine yearning; 19.07.2011
comment
У меня было несколько строк в csv, но он дал только 1 пару ключ: значение - person Abhilash Mishra; 31.07.2019

Откройте файл, вызвав open, а затем используя csv.DictReader.

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

Вы можете перебирать строки объекта чтения dict файла 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) 
person Laxmikant Ratnaparkhi    schedule 14.07.2016
comment
Это делает объект DictReader не словарем (и да, не парой значений ключа) - person HN Singh; 10.11.2018
comment
@HN Singh - Да, я знаю - это было намерение помочь и кому-то другому - person Laxmikant Ratnaparkhi; 14.11.2018
comment
Объект 'DictReader' не имеет атрибута 'next' - person Palak Bansal; 28.05.2019
comment
@Palak - ответили на Python 2.7, попробуйте next(dictobj) вместо dictobj.next() в версиях Python 3+. - person Laxmikant Ratnaparkhi; 30.05.2019

Это не элегантно, а однострочное решение с использованием панд.

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()
person mudassirkhan19    schedule 06.12.2017
comment
в моей книге это лучший ответ - person boardtc; 13.04.2019
comment
А если есть заголовок ...? - person ndtreviv; 30.05.2019
comment
@ndtreviv вы можете использовать skiprows для игнорирования заголовков. - person mudassirkhan19; 12.06.2019

Вам нужно просто преобразовать 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'}
person Alex Laskin    schedule 19.07.2011
comment
это решение аккуратное и будет отлично работать, если он будет уверен, что его входные данные никогда не будут содержать трех или более столбцов в какой-либо строке. Однако, если это когда-либо произойдет, возникнет исключение, подобное этому: ValueError: dictionary update sequence element #2 has length 3; 2 is required. - person Nate; 19.07.2011
comment
@machine, судя по ошибке в вопросе, в csv файле больше 2-х столбцов - person John La Rooy; 19.07.2011
comment
@gnibbler, нет, ошибка в вопросе из-за двойной распаковки строки. Сначала он пытается перебрать читателя, получая rows, который на самом деле является одной row. И когда он пытается перебрать эту единственную строку, он получает два элемента, которые нельзя правильно распаковать. - person Alex Laskin; 19.07.2011
comment
Общий комментарий: создание объектов, хранящихся в памяти, из итераций может вызвать проблемы с памятью. Предложите проверить объем памяти и размер повторяемого исходного файла. Главное преимущество (в чем суть?) Итераций - не хранить в памяти большие объекты. - person travelingbones; 04.03.2016
comment
@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). - person ShadowRanger; 08.06.2016
comment
Это очень чётко! Спасибо @Alex Laskin - person amc; 23.07.2020

Вы также можете использовать для этого numpy.

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

Однострочное решение

import pandas as pd

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

Для простых файлов 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)})
person fabda01    schedule 17.07.2019
comment
n.b. все это можно сократить до set_default: csv_dict.set_default (key, []). append ({key: value for key, value in zip (header, values)})) - person mdmjsh; 29.11.2019
comment
Синтаксис ({key: value}) в вашей команде .append оказался очень полезным. В итоге я использовал тот же синтаксис в row.update при повторении и добавлении к DictReaderobject, который был создан из файла CSV. - person Shrout1; 12.06.2020

Я бы предложил добавить 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)
person John La Rooy    schedule 19.07.2011
comment
И хорошо сделано, и продуманно. Но, как я сказал выше, должен ли он действительно игнорировать тот факт, что его строка ввода длиннее, чем он ожидал? Я бы сказал, что он должен создать собственное исключение (с настраиваемым сообщением), если он получит строку с более чем двумя элементами. - person machine yearning; 19.07.2011
comment
Или, скорее, как указано выше @Nate, по крайней мере, распечатать предупреждающее сообщение. Это просто не похоже на то, что вы хотели бы игнорировать. - person machine yearning; 19.07.2011
comment
Ваш ответ (против моего) заставил задуматься над чем-то - есть ли разница в эффективности между нарезкой и индексированием в этом случае? - person Nate; 19.07.2011
comment
@machine, понятия не имею. Возможно, это дамп пользовательской таблицы из базы данных, и ему просто нужен идентификатор пользователя: имя пользователя или что-то, например - person John La Rooy; 19.07.2011
comment
@Nate, я бы ожидал, что кортеж (ваш путь) будет немного быстрее - person John La Rooy; 19.07.2011
comment
Привет, ребята, спасибо за комментарии. Ваше обсуждение действительно помогло мне решить мою проблему. Мне нравится идея поднять флаг, если ввод длиннее, чем ожидалось. Мои данные - это дамп базы данных, и у меня более двух столбцов данных. - person drbunsen; 19.07.2011

Предполагая, что у вас есть CSV с такой структурой:

"a","b"
1,2
3,4
5,6

И вы хотите, чтобы результат был:

[{'a': '1', ' "b"': '2'}, {'a': '3', ' "b"': '4'}, {'a': '5', ' "b"': '6'}]

Функция zip (пока не упоминается) проста и весьма полезна.

def read_csv(filename):
    with open(filename) as f:
        file_data=csv.reader(f)
        headers=next(file_data)
        return [dict(zip(headers,i)) for i in file_data]

Если вы предпочитаете панд, он также может сделать это довольно хорошо:

import pandas as pd
def read_csv(filename):
    return pd.read_csv(filename).to_dict('records')
person conmak    schedule 30.09.2020

Если вы согласны с использованием пакета 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]
person cloudyBlues    schedule 06.03.2014

Вы можете использовать это, это довольно круто:

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
person hamed    schedule 10.02.2015

с пандами, например, это намного проще. предполагая, что у вас есть следующие данные как 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')

вот и все.

person TheTechGuy    schedule 14.09.2019

Попробуйте использовать 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]}
person Paulo Henrique Zen    schedule 18.06.2019

Было опубликовано много решений, и я хотел бы внести свой вклад в мой, который работает для другого количества столбцов в файле 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])
person Alejandro Villegas    schedule 08.07.2019

Если у вас есть:

  1. Только 1 ключ и 1 значение в качестве ключа, значение в вашем CSV
  2. Не хочу импортировать другие пакеты
  3. Хотите создать диктант одним выстрелом

Сделай это:

mydict = {y[0]: y[1] for y in [x.split(",") for x in open('file.csv').read().split('\n') if x]}

Что оно делает?

Он использует понимание списка для разделения строк и последнее, если x используется для игнорирования пустой строки (обычно в конце), которая затем распаковывается в dict с использованием понимания словаря.

person Canute S    schedule 22.09.2020

person    schedule
comment
Сильно непифонический стиль. - person Alex Laskin; 19.07.2011
comment
@Alex Laskin: Правда? Мне кажется, что это какой-то довольно читаемый питон. Каков ваш принцип, подтверждающий это заявление? Вы просто назвали его пухлым ... - person machine yearning; 19.07.2011
comment
@ machine-тоска, нет, я не говорил, что его код «плохой». Но нет единственной причины писать for row in reader: k, v = row, если, например, вы можете просто написать for k, v in reader. И если вы ожидаете, что этот читатель является итеративным, производящим двухэлементные элементы, вы можете просто передать его напрямую в dict для преобразования. d = dict(reader) намного короче и значительно быстрее на огромных наборах данных. - person Alex Laskin; 19.07.2011
comment
@Alex Laskin: Спасибо за разъяснения. Я лично согласен с вами, но я думаю, что если вы собираетесь называть чей-то код непифоническим, вы должны сопровождать этот комментарий обоснованием. Я бы сказал, что короче и быстрее не обязательно эквивалентно более питоническому. Читаемость / надежность также является огромной проблемой. Если легче работать с некоторыми из наших ограничений в вышеупомянутой for row in reader парадигме, то это может быть (после долгосрочной разработки) более практичным. Я согласен с вами в краткосрочной перспективе, но остерегайтесь преждевременной оптимизации. - person machine yearning; 19.07.2011
comment
@robert: Спасибо, чувак! Действительно помогло. Другие коды слишком сложно читать. - person Ash; 22.10.2020