【问题标题】:Most Pythonic way to read CSV values into dict of lists将 CSV 值读入列表字典的大多数 Pythonic 方式
【发布时间】:2014-06-21 20:59:54
【问题描述】:

我有一个 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 的方式来使用没有嵌套循环的内置函数,或者更好的习惯用法,或者存储此数据结构的替代方式,以便我可以通过查询返回可索引列表用钥匙?如果是这样,是否还有一种方法可以格式化由列预先摄取的数据?

【问题讨论】:

  • for k in dict_of_lists.keys(): -> for k in dict_of_lists:

标签: python list csv dictionary


【解决方案1】:

根据您存储的数据类型以及是否可以使用 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 还根据您的要求提供了一种“预先格式化按列摄取的数据”的方法。

转换器变量,可选

将列数据转换为值的一组函数。转换器还可用于为缺失数据提供默认值:converters = {3: lambda s: float(s or 0)}

【讨论】:

    【解决方案2】:

    如果您愿意使用第三方库,那么来自Toolzmerge_with 函数使整个操作变得单行:

    dict_of_lists = merge_with(list, *csv.DictReader(open(f)))
    

    仅使用标准库,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.

    【讨论】:

      【解决方案3】:

      福特的回答没有错,我就在这里添加我的(它利用了 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})
      

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

      1. 导入熊猫

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

        df = pd.read_csv(inputfile)
        
      3. 把df变成字典

        mydict = df.to_ditc(orient='list')
        

      这样,您可以使用 csv 标题来定义键,并且对于每个键,您都有一个元素列表(类似于将 excel 列转换为列表的东西)

      【讨论】:

        【解决方案4】:

        您可以使用 dict 和 set 理解来使您的意图更加明显:

        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{}.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]}
        

        【讨论】:

        • 使用推导式(在本例中是集合推导式)来执行循环通常不是 Pythonic。只需写出显式循环,它更自然,更清楚你在做什么。
        猜你喜欢
        • 1970-01-01
        • 2019-05-25
        • 1970-01-01
        • 2016-02-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-02-11
        相关资源
        最近更新 更多