[英]Most Pythonic way to read CSV values into dict of lists
我有一个 CSV 文件,标题位于数据列的顶部,如下所示:
a,b,c
1,2,3
4,5,6
7,8,9
我需要在列表字典中阅读它:
desired_result = {'a': [1, 4, 7], 'b': [2, 5, 8], 'c': [3, 6, 9]}
使用DictReader
阅读本文时,我使用嵌套循环将项目附加到列表中:
f = 'path_to_some_csv_file.csv'
dr = csv.DictReader(open(f))
dict_of_lists = dr.next()
for k in dict_of_lists.keys():
dict_of_lists[k] = [dict_of_lists[k]]
for line in dr:
for k in dict_of_lists.keys():
dict_of_lists[k].append(line[k])
第一个循环将 dict 中的所有值设置为空列表。 下一个循环遍历从 CSV 文件读入的每一行, DictReader
创建一个键值字典。 内部循环将值附加到与相应键匹配的列表中,所以我最终得到了所需的字典列表。 我最终不得不经常写这个。
我的问题是,是否有更 Pythonic 的方式使用没有嵌套循环的内置函数来执行此操作,或者更好的习惯用法,或者存储此数据结构的替代方法,以便我可以通过使用键查询来返回可索引列表? 如果是这样,是否还有一种方法可以预先格式化由列摄取的数据?
根据您存储的数据类型以及是否可以使用 numpy,一个很好的方法是使用numpy.genfromtxt
:
import numpy as np
data = np.genfromtxt('data.csv', delimiter=',', names=True)
这将创建一个 numpy Structured Array ,它提供了一个很好的界面,用于按标题名称查询数据(如果您有标题行,请确保使用names=True
)。
示例,给定data.csv
包含:
a,b,c
1,2,3
4,5,6
7,8,9
然后,您可以通过以下方式访问元素:
>>> data['a'] # Column with header 'a'
array([ 1., 4., 7.])
>>> data[0] # First row
(1.0, 2.0, 3.0)
>>> data['c'][2] # Specific element
9.0
>>> data[['a', 'c']] # Two columns
array([(1.0, 3.0), (4.0, 6.0), (7.0, 9.0)],
dtype=[('a', '<f8'), ('c', '<f8')])
genfromtext
还提供了一种方法,根据您的要求,“ genfromtext
格式化由列摄取的数据”。
转换器:变量,可选
将列的数据转换为值的一组函数。 转换器还可用于为缺失数据提供默认值:
converters = {3: lambda s: float(s or 0)}
。
如果您愿意使用第三方库,那么来自Toolz的merge_with
函数使整个操作成为一个单线:
dict_of_lists = merge_with(list, *csv.DictReader(open(f)))
仅使用 stdlib, defaultdict
使代码减少重复:
from collections import defaultdict
import csv
f = 'test.csv'
dict_of_lists = defaultdict(list)
for record in DictReader(open(f)):
for key, val in record.items(): # or iteritems in Python 2
dict_of_lists[key].append(val)
如果您需要经常这样做,请将其分解为一个函数,例如transpose_csv
。
福特的回答没有问题,我只是在这里添加我的(它使用了 csv 库)
with open(f,'r',encoding='latin1') as csvf:
dialect = csv.Sniffer().sniff(csvf.readline()) # finds the delimiters automatically
csvf.seek(0)
# read file with dialect
rdlistcsv = csv.reader(csvf,dialect)
# save to list of rows
rowslist = [list(filter(None,line)) for line in rdlistcsv]
header = rowslist[0]
data = {}
for i,key in enumerate(header):
ilist = [row[i] for row in rowslist]
data.update({key: ilist})
编辑:实际上,如果你不介意使用熊猫,事情会变得更容易:
进口大熊猫
import pandas as pd
导入文件并将其保存为熊猫数据框
df = pd.read_csv(inputfile)
将 df 变成字典
mydict = df.to_ditc(orient='list')
通过这种方式,您可以使用 csv 标题来定义键,并且对于每个键,您都有一个元素列表(类似于 Excel 列变成了列表)
您可以使用 dict 和 set comprehensions 使您的意图更加明显:
dr=csv.DictReader(f)
data={k:[v] for k, v in dr.next().items()} # create the initial dict of lists
for line_dict in dr:
{data[k].append(v) for k, v in line_dict.items()} # append to each
您可以使用Alex Martelli 的方法在 Python 中展平列表列表以展平迭代器的迭代器,这将第一种形式进一步简化为:
dr=csv.DictReader(f)
data={k:[v] for k, v in dr.next().items()}
{data[k].append(v) for line_dict in dr for k, v in line_dict.items()}
在 Python 2.X 上,如果您的 csv 文件很大,请考虑使用{}.iteritems与{}.items() 。
进一步的例子:
假设这个 csv 文件:
Header 1,Header 2,Header 3
1,2,3
4,5,6
7,8,9
现在假设您想要将每个值的列表的字典转换为浮点数或整数。 你可以做:
def convert(s, converter):
try:
return converter(s)
except Exception:
return s
dr=csv.DictReader(f)
data={k:[convert(v, float)] for k, v in dr.next().items()}
{data[k].append(convert(v, float)) for line_dict in dr for k, v in line_dict.items()}
print data
# {'Header 3': [3.0, 6.0, 9.0], 'Header 2': [2.0, 5.0, 8.0], 'Header 1': [1.0, 4.0, 7.0]}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.