我有一个包含所有数据的文本文件
data = 'B:/tempfiles/bla.dat'
从文本文件中列出列标题及其类型
col_headers = [('VW_3_Avg','<f8'),('Lvl_Max(1)','<f8')]
然后创建一个包含选项的字典变量:
kwargs = dict(delimiter=',',\
deletechars=' ',\
dtype=col_headers,\
skip_header=4,\
skip_footer=0,\
filling_values='NaN',\
missing_values={'\"NAN\"'}\
)
现在将数据导入变量数据文件
datafile = scipy.genfromtxt(datafile, **kwargs)
然后我用
分配数据VW1 = datafile['VW_3_Avg']
Lv1 = datafile['Lvl_Max(1)']
它与第一个(包含下划线)完美配合,而不与第二个(括号)配合使用。我得到一个错误,不仅是这个条目,还有包含括号的所有内容:
ValueError: field named Lvl_Max(1) not found
当我将文本文件中的括号更改为下划线时,它可以完美地运行。但我无法说出为什么它不会让我使用括号 - 我无法更改文本文件格式,因为这是外部生成的。当然我可以用脚本将括号更改为下划线,但我认为要做到这一点并不是一个大问题。在这种情况下,我在哪里以及为什么错过了正确的格式优先权?
答案 0 :(得分:1)
当您遇到genfromtxt
问题时,首先应该打印shape
和dtype
。
为什么必须在()
中使用col_headers = [('VW_3_Avg','<f8'),('Lvl_Max(1)','<f8')]
?
是因为文件在标题中有这些名称吗?
如果您提供自己的dtype
并使用skip_header
,那么文件上的内容无关紧要。它是dtype
中计数的字段名称,而不是文件中的字段名称。
我们可以深入了解dtype
文档并找到允许的字符。可以作为Python变量名称使用的字段名称肯定会起作用。 ()
被禁止或有问题我并不感到惊讶,尽管我没有测试过。
实际上,'Lvl_Max(1)'
可以作为dtype字段名称使用:
In [235]: col_headers = [('VW_3_Avg','<f8'),('Lvl_Max(1)','<f8')]
In [236]: A=np.zeros((3,),dtype=col_headers)
In [237]: A
Out[237]:
array([(0.0, 0.0), (0.0, 0.0), (0.0, 0.0)],
dtype=[('VW_3_Avg', '<f8'), ('Lvl_Max(1)', '<f8')])
In [238]: A['Lvl_Max(1)']
Out[238]: array([ 0., 0., 0.])
从一开始,您应该做的就是向我们展示datafile.shape
和datafile.dtype
。这些genfromtxt
问题中有90%源于对函数返回的误解。
让我们尝试一下这个dtype的简单文件:
In [239]: txt=b"""1 2
.....: 3 4
.....: 5 6
.....: """
In [240]: np.genfromtxt(txt.splitlines(),dtype=col_headers)
Out[240]:
array([(1.0, 2.0), (3.0, 4.0), (5.0, 6.0)],
dtype=[('VW_3_Avg', '<f8'), ('Lvl_Max1', '<f8')])
查看dtype
。 genfromtxt
已剥离'(1)'
。看起来像genfromtxt
'清理'字段名称,毫无疑问,因为文本文件上的名称可能有各种有趣的东西。
来自genfromtxt
文档:
具有结构化dtype的Numpy数组也可以被视为重新排列,其中可以像访问属性一样访问字段。出于这个原因,我们可能需要确保字段名称不包含任何空格或无效字符,或者它不符合标准属性的名称(如大小或形状),这会使解释器混淆。
genfromtxt
采用deletechars
参数,可让您控制从字段名称中删除哪些字符。但它的应用是不一致的。
In [282]: np.genfromtxt(txt.splitlines(),names=np.dtype(col_headers).names,deletechars=set(b' '),dtype=None)
Out[282]:
array([(1, 2), (3, 4), (5, 6)],
dtype=[('VW_3_Avg', '<i4'), ('Lvl_Max(1)', '<i4')])
In [283]: np.genfromtxt(txt.splitlines(),names=np.dtype(col_headers).names,deletechars=set(b' '))
Out[283]:
array([(1.0, 2.0), (3.0, 4.0), (5.0, 6.0)],
dtype=[('VW_3_Avg', '<f8'), ('Lvl_Max1', '<f8')])
dtype=None
是必须的。
默认设置很大:
defaultdeletechars = set("""~!@#$%^&*()-=+~\|]}[{';: /?.>,<""")
问题是deletechars
传递给validator
:
validate_names = NameValidator(...
deletechars=deletechars,...)
用于清除标题和names
参数中的名称。但随后名称(和dtype)将通过
dtype = easy_dtype(dtype, defaultfmt=defaultfmt, names=names)
没有deletechars
参数。这个问题大约在一年前得到解决https://github.com/numpy/numpy/pull/4649,因此可能会在新版本中修复。
答案 1 :(得分:1)
记录了行为,lib/_iotools.py
中的NameValidator类解析了传递给genfromtxt
的名称:
class NameValidator(object):
"""
Object to validate a list of strings to use as field names.
The strings are stripped of any non alphanumeric character, and spaces
are replaced by '_'. During instantiation, the user can define a list
of names to exclude, as well as a list of invalid characters. Names in
the exclusion list are appended a '_' character.
Once an instance has been created, it can be called with a list of
names, and a list of valid names will be created. The `__call__`
method accepts an optional keyword "default" that sets the default name
in case of ambiguity. By default this is 'f', so that names will
default to `f0`, `f1`, etc.
您案例中的相关行字符串将被删除任何非字母数字字符
您可以通过在名单中使用其他非字母数字字符调用NameValidator.validate
来查看行为:
In [17]: from numpy.lib._iotools import NameValidator
In [18]: l = ["foo(1)","bar!!!","foo bar??"]
In [19]: NameValidator().validate(l)
Out[19]: ('foo1', 'bar', 'foo_bar')
同样使用genfromtxt:
In [24]: datafile = np.genfromtxt("foo.txt", dtype=[('foo!! bar??', '<f8'), ('foo bar bar$', '<f8')], delimiter=",",defaultfmt="%")
In [25]: datafile.dtype
Out[25]: dtype([('foo_bar', '<f8'), ('foo_bar_bar', '<f8')])