我有一个csv文件,其标题位于数据列的顶部,如...
<Header1>, <Header2>, ... ,<HeaderN>
<data11> , <data12> , ... ,<data1N>
<data21> , <data12> , ... ,<data2N>
... , ... , ... , ...
<dataM1> , <dataM2> , ... ,<dataMN>
(即标准表格数据)
使用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从中创建键值的dict。内部循环将值附加到与相应键值匹配的列表中,因此我最终得到所需的词典列表。我最终不得不经常写这篇文章。
我的问题是,是否有更多Pythonic方法使用内置函数执行此操作,没有嵌套循环,或更好的习惯用法,或存储此数据结构的替代方法,以便我可以通过查询返回可索引列表关键价值?如果是这样,还有一种方法可以格式化由前面的列提取的数据吗? (对于MWE,只需将上面的数据复制到文本文件中并通过代码运行)提前感谢!
答案 0 :(得分:6)
根据您要存储的数据类型以及使用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
还提供了一种方法,根据您的要求,预先格式化预先填写的数据。&#34;
转换器:变量,可选
将列数据转换为值的函数集。转换器还可用于为缺失数据提供默认值:converters = {3:lambda s:float(s或0)}。
答案 1 :(得分:1)
如果您愿意使用第三方库,那么来自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
答案 2 :(得分:0)
福特的回答没有错,我只是在这里添加我的(它使用了 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
导入文件并保存为pandas数据框
df = pd.read_csv(inputfile)
把df变成字典
mydict = df.to_ditc(orient='list')
通过这种方式,您可以使用 csv 标题来定义键,并且对于每个键,您都有一个元素列表(类似于 Excel 列变成列表)
答案 3 :(得分:-1)
您可以使用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's method在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 vs {}.items()。
进一步的例子:
假设这个csv文件:
Header 1,Header 2,Header 3
1,2,3
4,5,6
7,8,9
现在假设你想要一个转换为float或int的每个值的列表的dict。你可以这样做:
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]}