【问题标题】:String formatting issue (parantheses vs underline)字符串格式问题(括号或下划线)
【发布时间】:2015-12-08 21:13:22
【问题描述】:

我有一个包含我所有数据的文本文件

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 

当我将文本文件中的括号更改为下划线时,它可以完美运行。但我不能说为什么它不允许我使用括号——而且我不能更改文本文件格式,因为这是在外部生成的。当然,我可以使用脚本将括号更改为下划线,但我认为正确处理应该不是什么大问题。在这种情况下,我在哪里以及为什么缺少正确的格式优先级?

【问题讨论】:

  • 你在使用 numpy 吗?
  • laike9m:我的包含所有数据的文本文件。我将在初始帖子中添加此信息。认为这很清楚,对不起。
  • 发生了什么是'Lvl_Max(1)'变成'Lvl_Max1'
  • 请停止在您的问题中添加“已解决”。它使 Stack Overflow 的 问答网站 的状态无效。如果特定评论解决了您的问题,请询问评论者是否可以将其作为正确答案提交。否则,如果答案有帮助,请将其标记为“已接受”,并且不要编辑您的问题以包含它。 (您之前已经多次这样做了。)

标签: python string python-2.7 scipy


【解决方案1】:

当您遇到genfromtxt 问题时,您应该首先打印shapedtype

为什么必须在col_headers = [('VW_3_Avg','&lt;f8'),('Lvl_Max(1)','&lt;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.shapedatafile.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')])

查看dtypegenfromtxt 已剥离 '(1)'。看起来像genfromtxt '清理' 字段名称,毫无疑问,因为文本文件上的名称可能有各种有趣的东西。

来自genfromtxt 文档:

具有结构化 dtype 的 Numpy 数组也可以被视为 recarray,其中可以像访问属性一样访问字段。出于这个原因,我们可能需要确保字段名称不包含任何空格或无效字符,或者它不对应于标准属性的名称(如大小或形状),这会使解释器感到困惑。


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,因此可能会在新(est)版本中得到修复。

【讨论】:

    【解决方案2】:

    该行为已记录在案,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')])
    

    【讨论】:

      猜你喜欢
      • 2011-07-10
      • 1970-01-01
      • 1970-01-01
      • 2020-12-22
      • 1970-01-01
      • 1970-01-01
      • 2019-07-30
      • 2015-10-04
      相关资源
      最近更新 更多