大多数Pythonic方式将csv值读入列表的dict

时间:2014-05-05 14:05:28

标签: python list csv dictionary

我有一个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,只需将上面的数据复制到文本文件中并通过代码运行)提前感谢!

4 个答案:

答案 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)

如果您愿意使用第三方库,那么来自Toolzmerge_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})

编辑:实际上,如果您不介意使用熊猫,事情会变得更容易:

  1. 导入熊猫

    import pandas as pd
    
  2. 导入文件并保存为pandas数据框

    df = pd.read_csv(inputfile)
    
  3. 把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]}