我有一个csv文件,其中包含一些包含测量值的列,包括错误值。我想使用numpy genfromtxt将所有内容导入python,并使用dtype格式化我的数组。我们假设我有一个这种格式的csv文件:
# Name, Time, Intensity
Sample1, 300, 1000+-5
Sample2, 300, 1500+-2
我想解析整个文件并将值和不确定性拆分为Intensity列的两个子列。我定义了两个dtypes:
import numpy as np
TypeValErr = np.dtype([("value", np.int32), ("error", np.int32)])
TypeCSV=np.dtype({"names": ["name", "time", "intensity"],
"formats": ["U32", np.int32, TypeValErr],
"titles": ["Name", "Time", "Intensity"]})
使用这个dtypes,我首先自己创建一个测试数组:
Intensity = np.array([(2000, 12)], dtype=TypeValErr)
CSVentry = np.array([("Sample3", 300, Intensity)], dtype=TypeCSV)
print(CSVentry)
这给了我预期的输出
[('Sample3', 300, (2000, 12))]
在下一步中,我想使用此dtype导入CSV。由于Intensity列的格式错误,我想使用转换器将输出转换为正确的格式:
def convertToValErrArr(txt):
splitted = txt.split("+-")
return np.array([(splitted[0], splitted[1])], dtype=TypeValErr)
print(np.array([("Sample3", 300, convertToValErrArr("1800+-7"))], dtype=TypeCSV))
输出再次给出预期的
[('Sample3', 300, (1800, 7))]
但最后,导入本身会引发错误。这是我的代码:
ConvertFunc = lambda x: convertToValErrArr(x)
file = np.genfromtxt("test.csv",
delimiter=",",
autostrip=True,
dtype=TypeCSV,
skip_header=1,
converters={2: lambda x: convertToValErrArr(str(x))})
这是我的错误:
Traceback (most recent call last):
File "csvimport.py", line 28, in <module>
converters={2: lambda x: convertToValErrArr(str(x))})
File "/usr/lib/python3.6/site-packages/numpy/lib/npyio.py", line 1896, in genfromtxt
rows = np.array(data, dtype=[('', _) for _ in dtype_flat])
ValueError: size of tuple must match number of fields.
我没有看到错误。 genfromtxt是以不同的方式处理数据的吗?我希望,有人有个主意!非常感谢。
答案 0 :(得分:1)
使用你的dtype和4列,它可以工作(嵌套dtype和all)
In [58]: TypeValErr = np.dtype([("value", np.int32), ("error", np.int32)])
...: TypeCSV=np.dtype({"names": ["name", "time", "intensity"],
...: "formats": ["U32", np.int32, TypeValErr],
...: "titles": ["Name", "Time", "Intensity"]})
...:
In [59]: txt=b"""# Name, Time, Intensity
...: Sample1, 300, 1000, 5
...: Sample2, 300, 1500, 2"""
In [60]:
In [60]: data=np.genfromtxt(txt.splitlines(), dtype=TypeCSV, delimiter=',',skip_header=True)
In [61]: data
Out[61]:
array([('Sample1', 300, (1000, 5)), ('Sample2', 300, (1500, 2))],
dtype=[(('Name', 'name'), '<U32'), (('Time', 'time'), '<i4'), (('Intensity', 'intensity'), [('value', '<i4'), ('error', '<i4')])])
因此,它可以采用一个平坦的值列表,例如['Sample1', 300, 1000, 5]
并将它们映射到嵌套元组上需要保存此dtype:
('Sample1', 300, (1000, 5))
。
但转换器不会将['Sample1', '300', '1000+-5']
转换为['Sample1', '300', (1000, 5)]
,如果确实如此,则不适合后续使用。
dtype_flat
为:
In [70]: np.lib.npyio.flatten_dtype(TypeCSV)
Out[70]: [dtype('<U32'), dtype('int32'), dtype('int32'), dtype('int32')]
所以你的嵌套dtype是用这样的序列生成的:
In [75]: rows=np.array(('str',1,2, 3),dtype=[('',_) for _ in np.lib.npyio.flatten_dtype(TypeCSV)])
In [76]: rows.view(TypeCSV)
Out[76]:
array(('str', 1, (2, 3)),
dtype=[(('Name', 'name'), '<U32'), (('Time', 'time'), '<i4'), (('Intensity', 'intensity'), [('value', '<i4'), ('error', '<i4')])])
事实上,在错误行
之前就已对该效果发表评论 if len(dtype_flat) > 1:
# Nested dtype, eg [('a', int), ('b', [('b0', int), ('b1', 'f4')])]
# First, create the array using a flattened dtype:
# [('a', int), ('b1', int), ('b2', float)]
# Then, view the array using the specified dtype.
if 'O' in (_.char for _ in dtype_flat):
...
else:
rows = np.array(data, dtype=[('', _) for _ in dtype_flat])
output = rows.view(dtype)
此时 data
是一个&#39; row`元组列表,已经通过转换器传递:
rows = list(
zip(*[[conv._strict_call(_r) for _r in map(itemgetter(i), rows)]
for (i, conv) in enumerate(converters)]))
简化了转换过程
In [84]: converters = [str, int, int, int]
In [85]: row = ['one','1','2','3']
In [86]: [conv(r) for conv, r in zip(converters, row)]
Out[86]: ['one', 1, 2, 3]
但实际上更接近:
In [87]: rows = [row,row]
In [88]: rows
Out[88]: [['one', '1', '2', '3'], ['one', '1', '2', '3']]
In [89]: from operator import itemgetter
In [90]: [[conv(r) for r in map(itemgetter(i), rows)] for (i, conv) in enumerate(converters)]
Out[90]: [['one', 'one'], [1, 1], [2, 2], [3, 3]]
In [91]: list(zip(*_))
Out[91]: [('one', 1, 2, 3), ('one', 1, 2, 3)]
所以长期和短期是converters
无法将列拆分为2列或更多列。拆分,转换,然后映射到dtype的过程以错误的顺序发生。我在开始时演示的内容可能很简单 - 通过文本处理行逐行传递文件。它将用指定的分隔符替换+-
。然后该文件将具有正确的列数以与您的dtype一起使用。