Создание словаря из файла 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? Спасибо.

drbunsen
источник
2
Можете ли вы привести пример входного файла и результирующей структуры данных?
Роберт
1
Когда вы перебираете csv.reader, вы получаете одну строку, а не строки. Итак, допустимая форма: mydict = {k: v для k, v в программе чтения}, но если вы уверены, что в файле csv есть только два столбца, то mydict = dict (программа чтения) будет намного быстрее.
Алекс Ласкин

Ответы:

156

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

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)
Nate
источник
2
Хорошо учитывать строки длиннее, чем ожидалось; но не должен ли он поднять свое собственное исключение, если в строке слишком много предметов? Я думаю, это будет означать ошибку с его входными данными.
машина тоскует
1
И тогда он, по крайней мере, сможет сузить исключение до ошибочного ввода
машина жаждет
Это имеет некоторые достоинства, но я твердо верю, что есть исключения, чтобы сказать вам, что вы запрограммировали что-то неправильно - не для тех случаев, когда мир дает вам лимоны. Вот когда вы печатаете симпатичное сообщение об ошибке и терпите неудачу, или - более подходящее для этого случая - симпатичное предупреждающее сообщение и добиваетесь успеха.
конец
Извините, посмотрел код опа, трудно сказать, хочет ли он только 2 элемента в строке. Я ошибался!
машина тоскует
1
У меня было несколько строк в CSV, но он дал только 1 пара ключ: значение
Абхилаш Мишра
80

Откройте файл, вызвав open, а затем 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 Сингх - Да, я знаю - намерение было помочь кому-то еще
Laxmikant Ratnaparkhi
1
Объект «DictReader» не имеет атрибут «следующий»
Palak
1
@Palak - ответили для Python 2.7, попробуйте next(dictobj)вместо dictobj.next()версий Python 3+.
Лаксмикант Ратнапархи
61
import csv
reader = csv.reader(open('filename.csv', 'r'))
d = {}
for row in reader:
   k, v = row
   d[k] = v
Роберт
источник
6
Очень непитонный стиль.
Алекс Ласкин
47
@ Алекс Ласкин: Правда? Для меня это выглядит довольно читабельным питоном. Каков твой принцип, подтверждающий это утверждение? Вы просто назвали его "головокружительной головой" ...
машина жаждет
26
@ машинное желание, нет, я не говорил, что его код «плохой». Но нет единой причины писать, например, for row in reader: k, v = rowесли вы можете просто написать for k, v in reader. И если вы ожидаете, что этот читатель является итеративным, производящим двухэлементные элементы, то вы можете просто передать его непосредственно в dict для преобразования. 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()
mudassirkhan19
источник
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.
конец
@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 }
Thiru
источник
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
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]
cloudyBlues
источник
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)})
yellow01
источник
Но все это можно сократить, используя 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')

и это все.

TheTechGuy
источник
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]}
Пауло Энрике Дзен
источник