将CSV值读入列表字典的最Python方式

kkbh8khc  于 2022-12-06  发布在  Python
关注(0)|答案(4)|浏览(251)

我有一个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从中创建一个key-values的dict。内部循环将值附加到与相应键匹配的列表中,因此我得到了所需的dict列表。我不得不经常编写此代码。
我的问题是,有没有一种更像Python的方式来实现这一点,使用内置函数而不使用嵌套循环,或者有一种更好的习惯用法,或者有一种替代的方式来存储这种数据结构,以便我可以通过使用键进行查询来返回一个可索引的列表?如果有,是否还有一种方式来格式化列预先接收的数据?

tp5buhyn

tp5buhyn1#

根据所存储数据的类型以及是否可以使用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)} .

n3ipq98p

n3ipq98p2#

如果您愿意使用第三方库,那么Toolz中的merge_with函数可以使整个操作成为一行代码:

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

defaultdict只使用stdlib,减少了代码的重复性:

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

yjghlzjz

yjghlzjz3#

福特的答案没有错,我在这里添加我的答案(使用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.进口Pandas

import pandas as pd

1.导入文件并将其保存为Pandas Dataframe

df = pd.read_csv(inputfile)

1.把df变成字典

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

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

ebdffaop

ebdffaop4#

可以使用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

在Python中,可以使用Alex Martelli's method扁平化列表列表,扁平化迭代器的迭代器,这进一步将第一种形式简化为:

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

现在假设你想把一个dict列表中的每个值转换成float或int。你可以这样做:

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

相关问题