将文本转换为numpy数组

时间:2017-07-19 15:02:50

标签: python arrays string numpy exception

我需要一个函数,它将(非二进制)字符串作为输入并返回一个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数组,如果输入无法转换为数字,则会正确地抛出错误?

3 个答案:

答案 0 :(得分:2)

您可以直接使用字符串并使用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.])

编辑: 您可以通过验证.fromstring格式来实施自己的input_string。如果它确实具有您要查找的模式(在您的情况下为所有浮点数),则将其转换为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

答案 1 :(得分:1)

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

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

答案 2 :(得分:1)

你可以写一个正则表达式,因为它不是一个非常复杂的语言; 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.

当然要允许可选的逗号,在可选的指数包含,?之后,可选的逗号;如果需要方括号或分号,那么这些也不会太难添加。还要考虑更改&#34;中的*;重复跟踪ws&#34;部分到+以强制数组为非空。