csvファイルから辞書を作成しますか?


153

csvファイルから辞書を作成しようとしています。csvファイルの最初の列には一意のキーが含まれ、2番目の列には値が含まれています。csvファイルの各行は、辞書内の一意のキーと値のペアを表します。クラスcsv.DictReadercsv.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ファイルから1つの辞書を作成するにはどうすればよいですか?ありがとう。


2
入力ファイルと結果のデータ構造の例を教えてください。
ロバート'19

1
csv.readerを反復処理すると、行ではなく単一の行が取得されます。したがって、有効な形式はmydict = {リーダーのk、vの場合はk:v}ですが、csvファイルに2列しかないことが確実であれば、mydict = dict(reader)の方がはるかに高速です。
Alex Laskin、2011

回答:


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
そして彼は、少なくとも故障した入力に例外を絞り込むことができるだろう
機械憧れ

それにはいくつかのメリットがありますが、例外があり、間違ってプログラムしたことを伝えるために例外が存在すると私は確信しています。これは、かなりのエラーメッセージを出力して失敗した場合、または-この場合により適切な-かなりの警告メッセージを表示して成功した場合です。
'25

申し訳ありませんが、opのコードを確認しました。1行に2項目しか必要ないのかわかりません。私は間違っていた!
マシン

1
csvに複数の行がありましたが、キーと値のペアは1つしかありませんでした
Abhilash Mishra

80

openを呼び出してからファイルを開きますcsv.DictReader

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

input_fileを反復することにより、csvファイルdictリーダーオブジェクトの行を反復できます。

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'オブジェクトには属性 'next'がありません
Palak

1
@Palak-Python 2.7で回答されました。Python3 以降のバージョンnext(dictobj)dictobj.next()はなく試してください。
Laxmikant Ratnaparkhi

61
import csv
reader = csv.reader(open('filename.csv', 'r'))
d = {}
for row in reader:
   k, v = row
   d[k] = v

6
非常に非Pythonicスタイル。
Alex Laskin、2011

47
@アレックスラスキン:本当に?私には、かなり読みやすいpythonのように見えます。この声明を裏付けるあなたの原則は何ですか?あなたは基本的に彼を「うんち頭」と呼んだだけです...
憧れるマシン

26
@ machine-yearning、いいえ、彼のコードが「悪い」とは言いませんでした。しかし、たとえば、for row in reader: k, v = row単にと書くことができれば、書く理由は1つではありませんfor k, v in reader。そして、もしあなたが期待しているなら、そのリーダーは反復可能で、2要素のアイテムを生成するので、単純にそれを直接dictに渡して変換することができます。d = dict(reader)巨大なデータセットでは、はるかに短く、著しく高速です。
Alex Laskin、2011

44
@Alex Laskin:説明してくれてありがとう。私はあなたに個人的に同意しましたが、誰かのコードを「非Pythonic」と呼ぶつもりなら、そのコメントに正当な理由を添えるべきだと思います。私は、「より短い」と「より速い」は必ずしも「より多くのpythonic」と同等ではないと言います。読みやすさ/信頼性も大きな懸念事項です。上記のfor row in readerパラダイムに制約を加えて作業する方が簡単な場合は、(長期的な開発後)より実用的になる可能性があります。短期的には同意しますが、時期尚早の最適化に注意してください。
憧れるマシン

30

これはエレガントではありませんが、パンダを使用した1行のソリューションです。

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

インデックスにdtypeを指定する場合(バグのためにindex_col引数を使用する場合、read_csvでは指定できません):

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

3
私の本ではこれが最良の答えです
boardtc

そして、ヘッダーがある場合...?
ndtreviv

@ndtrevivでは、スキップローを使用してヘッダーを無視できます。
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
その解決策は整頓されおり、彼の入力がある行に3つ以上の列を持たないことが確実であれば、うまく機能します。ただし、それが発生すると、次のような例外が発生しますValueError: dictionary update sequence element #2 has length 3; 2 is required
ネイト

@machine、質問のエラーから判断すると、csvファイルには2列以上あります
John La Rooy

@gnibbler、いいえ、質問のエラーは行の二重アンパックによるものです。まず彼は取得、リーダーを反復処理しようとする実際には単一である行を。そして、この1つの行を反復処理しようとすると、2つのアイテムが取得されますが、正しく解凍できません。
Alex Laskin、2011

一般的なコメント:反復可能オブジェクトからメモリに保持されるオブジェクトを作成すると、メモリの問題が発生する可能性があります。メモリ容量と反復可能なソースファイルのサイズを確認することをお勧めします。イテラブルの主な利点(全体のポイント?)は、大きなものをメモリに保持しないことです。
トラベリング

@Nate:必要に応じて、でfilter呼び出しをラップすることで修正できるmap(operator.itemgetter(slice(2)), ...)ため、最初の2つの反復のみをプルして、次のようにしますdict(map(operator.itemgetter(slice(2)), filter(None, csv.reader(f))))。Python 2の場合はfrom future_builtins import map, filter、必ず行うようにしてください。そうすれば、最初にdict複数の不要な一時的なlistsを生成するのではなく、ジェネレータが直接読み取られます。
ShadowRanger 2016年

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)

よくやった、よく考え抜かれた。しかし、私が上で言ったように、彼は彼の入力ラインが彼が予想したよりも長いという事実を本当に無視するべきですか?3つ以上のアイテムを含む行を受け取った場合は、独自の例外を(カスタムメッセージを使用して)上げる必要があると思います。
機械を切望する

または、@ Nateで前述したように、少なくとも警告メッセージを出力します。これはあなたが無視したいもののようには思えません。
マシンを憧れる

あなたの答え(対私)は何かを考えました-この場合、スライスとインデックス付けの間に効率の違いはありますか?
ネイト

1
@machine、わからない。おそらくそれはデータベースからのユーザーテーブルのダンプであり、彼は単にuserid:usernameまたは何かの
辞書を望ん

1
皆さん、コメントありがとうございます。あなたの議論は私の問題を本当に助けてくれました。入力が予想よりも長い場合にフラグを立てるというアイデアが気に入っています。私のデータはデータベースダンプで、3列以上のデータがあります。
drbunsen '19


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(key、[])。append({key:value for key、value in zip(header、values)}))
mdmjsh

.appendコマンドの({key:value})構文は非常に役に立ちました。最終的には、CSVファイルから作成されrow.updateDictReaderオブジェクトを反復して追加するときに、同じ構文を使用しました。
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ファイルのさまざまな列で機能する私のソリューションに貢献したいと思います。列ごとに1つのキーを持つディクショナリを作成し、各キーの値はそのような列の要素のリストです。

    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

使用してみてください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)

それは返します:

{'key1':[value_1, value_2, value_3], 'key2': [value_a, value_b, value_c], 'Key3':[value_x, Value_y, Value_z]}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.