将CSV文件数据读取为命名元组行的pythonic方法是啥?
Posted
技术标签:
【中文标题】将CSV文件数据读取为命名元组行的pythonic方法是啥?【英文标题】:What is the pythonic way to read CSV file data as rows of namedtuples?将CSV文件数据读取为命名元组行的pythonic方法是什么? 【发布时间】:2012-02-18 21:36:35 【问题描述】:获取包含标题行的数据文件并将该行读入命名元组以便可以通过标题名称访问数据行的最佳方法是什么?
我正在尝试这样的事情:
import csv
from collections import namedtuple
with open('data_file.txt', mode="r") as infile:
reader = csv.reader(infile)
Data = namedtuple("Data", ", ".join(i for i in reader[0]))
next(reader)
for row in reader:
data = Data(*row)
阅读器对象不可下标,所以上面的代码抛出了TypeError
。将文件头读入命名元组的pythonic方法是什么?
【问题讨论】:
【参考方案1】:用途:
Data = namedtuple("Data", next(reader))
并省略该行:
next(reader)
将此与基于以下 martineau 评论的迭代版本相结合,示例变为 Python 2
import csv
from collections import namedtuple
from itertools import imap
with open("data_file.txt", mode="rb") as infile:
reader = csv.reader(infile)
Data = namedtuple("Data", next(reader)) # get names from column headers
for data in imap(Data._make, reader):
print data.foo
# ...further processing of a line...
对于 Python 3
import csv
from collections import namedtuple
with open("data_file.txt", newline="") as infile:
reader = csv.reader(infile)
Data = namedtuple("Data", next(reader)) # get names from column headers
for data in map(Data._make, reader):
print(data.foo)
# ...further processing of a line...
【讨论】:
drbunsen:完成此操作后,您可以将处理循环更改为:for data in map(Data._make, reader):
。
如果 csv 数据缺少标题怎么办?有没有办法为列分配名称? (如果 CSV 数据缺少命名标题,并且您想分配列名,那么在我看来,我唯一的选择是将其作为字典序列读取)。
@Crossfit_and_Beer 我不太明白你的评论。如果您想将 CSV 文件作为一系列字典读取,您仍然需要列名作为键,那么区别在哪里?如果你想使用namedtuple
s,你可以简单地用固定的字段名静态声明namedtuple
类型而不是next(reader)
。其余代码保持不变。
@Jean-FrançoisFabre 我撤销了您的更改,因为生成的代码对于 Python 2 和 Python 3 都是错误的。在 Python 2 中,mode="rb"
是必需的,而在 Python 3 中 newline=""
是必需的。
@Jean-FrançoisFabre 我无法尝试,因为我无法访问b
真正发挥作用的平台,我认为没有必要。 csv
模块的最新 Python 2 和 Python 3 文档都说明了这些要求,因此即使您发现它恰好在某些平台上针对某些输入工作,您仍然以未记录的方式使用 API,这可能会中断随时。【参考方案2】:
请查看csv.DictReader
。基本上,它提供了在您查找时从第一行获取列名的能力,然后,您可以使用字典按名称访问行中的每一列。
如果由于某种原因您仍需要以 collections.namedtuple
的形式访问行,则应该很容易将字典转换为命名元组,如下所示:
with open('data_file.txt') as infile:
reader = csv.DictReader(infile)
Data = collections.namedtuple('Data', reader.fieldnames)
tuples = [Data(**row) for row in reader]
【讨论】:
这个解决方案的问题是每一行都转换成字典,然后再转换成命名元组。如果不需要中间字典,则效率低下。 这不会保留顺序,因此您的 csv 中的第一列将成为您命名元组中的随机列。到那时,还不如使用字典。【参考方案3】:我建议这种方法:
import csv
from collections import namedtuple
with open("data.csv", 'r') as f:
reader = csv.reader(f, delimiter=',')
Row = namedtuple('Row', next(reader))
rows = [Row(*line) for line in reader]
如果您使用 Pandas,解决方案会变得更加优雅:
import pandas as pd
from collections import namedtuple
data = pd.read_csv("data.csv")
Row = namedtuple('Row', data.columns)
rows = [Row(*row) for index, row in data.iterrows()]
在这两种情况下,您都可以通过字段名称与记录进行交互:
for row in rows:
print(row.foo)
【讨论】:
我不认为Row = namedtuple('Row', next(reader))
会像你那样工作,因为namedtuple
的第二个参数应该是元组子类的字段名,“是一个字符串序列如['x', 'y']
"根据documentation。您还在循环中反复创建 reader
。以上是关于将CSV文件数据读取为命名元组行的pythonic方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章
python 将csv文件转换为Pandas数据帧并遍历其行的函数