【问题标题】:Convert text to numpy array将文本转换为 numpy 数组
【发布时间】:2017-12-24 22:51:29
【问题描述】:

我需要一个将(非二进制)字符串作为输入并返回一个 numpy 数组的函数。

Numpy 提供了函数numpy.fromstring,这适用于所有情况(使用适当的参数):

>>> np.fromstring('1 2 3.1415', dtype=float, sep=' ')
array([ 1.    ,  2.    ,  3.1415])

我的问题是它适用于太多情况。例如,在以下情况下它会静默失败

>>> np.fromstring('not a string', dtype=float, sep=' ')
array([], dtype=float64)

有没有一种方法可以安全地将非二进制字符串转换为 numpy 数组,如果输入无法转换为数字,则该数组会正确抛出错误?

【问题讨论】:

    标签: python arrays string numpy exception


    【解决方案1】:

    您可以直接使用字符串并使用np.arraysplit 将其转换回numpy 数组,如下所示:

    >>> np.array('1 2 3.1415'.split(' '), dtype=float)
    array([ 1.    ,  2.    ,  3.1415])
    >>> np.array('not a string'.split(' '), dtype=float)
    ValueError: could not convert string to float: not
    

    当使用fromstring 时,如果您的输入字符串不只包含实数值数据,您应该期待一个空数组。

    >>> np.fromstring('not a string', dtype=float, sep=' ')
    array([], dtype=float64)
    >>> np.fromstring('not a string 5', dtype=float, sep=' ')
    array([], dtype=float64)
    >>> np.fromstring('8 5', dtype=float, sep=' ')
    array([ 8.,  5.])
    

    编辑: 您可以通过验证您的input_string 格式来实现您自己的.fromstring。如果它确实具有您正在寻找的模式(在您的情况下为所有浮点数),则将其转换为numpy.array。在失败的情况下,您要么想显式通过异常错误,要么返回一个空列表。

    In [1]: import re
    In [2]: import numpy as np    
    In [3]: def my_fromstring(input_string):
    ...:     input_string = input_string.strip()
    ...:     input_string = re.sub(' +', ' ', input_string)
    ...:     float_pattern = '\d+\.d+|\d+'
    ...:     verify_fn = lambda s: map(lambda x: re.match(float_pattern, x),           
    ...:                                    s.split(' '))
    ...:     pattern_match_fn = lambda x: any(map(lambda x: True if x == None          
    ...:                                    else False, x))
    ...:     res = verify_fn(input_string)
    ...:     match = pattern_match_fn(res)
    ...:     if not match:
    ...:         return np.array(map(float, input_string.split(' ')))
    ...:     else:
    ...:         raise ValueError('Incorrect input format')
    ...:     
    

    您现在可以使用自定义函数进行检查:

    In [4]: my_fromstring(' 7 5      8  3  ')
    Out[4]: array([ 7.,  5.,  8.,  3.])
    
    In [5]: my_fromstring('not a string')
    ---------------------------------------------------------------------------
    ValueError                                Traceback (most recent call last)
    <ipython-input-67-88cd38f7ad26> in <module>()
    ----> 1 my_fromstring('not a string')
    
    <ipython-input-65-e355cf28acb0> in my_fromstring(input_string)
         10         return np.array(map(float, input_string.split(' ')))
         11     else:
    ---> 12         raise ValueError('Incorrect input format')
         13 
    
    ValueError: Incorrect input format
    

    【讨论】:

    • 尝试np.fromstring(' not a string', dtype=float, sep=' '),这将返回array([-1.])
    • 如果你知道你的输入数据格式,你可以应用strip函数,你仍然可以得到想要的输出。
    • np.array(s.split(), dtype=float) 如果无法将“单词”之一转换为浮点数,则会引发错误。
    • 这取决于你想对你的数据做什么,我们假设一个任意输入。如果你想明确地有浮点数,那么你必须做一些检查,你最终会得到np.fromstring函数的行为。
    • 如果我添加一个dtype=float 似乎只是调用np.array 是迄今为止最好的解决方案。你能更新一下吗?
    【解决方案2】:

    您可以编写正则表达式,因为它不是一种非常复杂的语言; json spec 显示了浮点数的图表。要允许它们之间的任意换行符和空格,如下所示:

    [\s\n]*(?:-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][-+]?\d+)?[\s\n]*)*
    

    我们将其分解:

    [\s\n]*                                                        leading ws (whitespace)
           (?:                                           [\s\n]+)* repeat with trailing ws
              -?(?:0|[1-9]\d*)                                     an integer, no leading 0s
                              (?:\.\d+)?                           opt. decimal part
                                        (?:[eE][-+]?\d+)           opt. base-10 exponent
    

    ^ 括起来作为字符串的开头,用$ 括起来作为字符串的结尾,例如

    re.match(r'^[\s\n]*(?:-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][-+]?\d+)?[\s\n]*)*$', 
             '1 2 3.12345')
    # returns a Match object
    
    re.match(r'^[\s\n]*(?:-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][-+]?\d+)?[\s\n]*)*$', 
             '1, 2, 3.12345')
    # returns None because we did not allow commas in the regex.
    

    当然允许可选逗号,在可选指数之后包括,?,可选逗号;如果需要方括号或分号,它们也不太难添加。还可以考虑将“使用尾随 ws 重复”部分中的 * 更改为 + 以强制数组为非空。

    【讨论】:

      【解决方案3】:

      为什么不检查操作后数组是否为空,如果是则抛出错误?

      def extract(s):
          a = np.fromstring(s.strip(), dtype=float, sep=' ')
          if a.size == 0 or a.size == 1 and len(str(a[0])) != len(s.strip()):
            raise Exception('No numbers found')
          return a
      

      【讨论】:

      • 这失败了,试试例如np.fromstring(' not a string', dtype=float, sep=' ')
      • 如果空格是问题,我们可以在解析之前strip字符串。查看更改。
      • 好更新,现在至少我不能让它失败,但我们知道没有其他失败案例吗?
      • 这取决于您打算使用该函数的字符串类型。
      • 嗯,您的示例仍然给出np.fromstring('5 not a number', dtype=float, sep=' ')array([ 5.]),这(至少对我而言)不是预期的答案。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-29
      • 2017-03-08
      • 2012-04-18
      • 2018-06-03
      • 2022-01-20
      • 2017-12-15
      相关资源
      最近更新 更多