将文本转换为numpy数组

问题描述:

我需要一个函数,它将(非二进制)字符串作为输入并返回一个numpy数组。将文本转换为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的,妥善抛出一个错误,如果输入无法转换为数字阵列?

您可以直接与字符串工作,并使用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 
+0

尝试'np.fromstring('not a string',dtype = float,sep ='')',这会返回'array([ - 1。])''。 –

+0

如果你知道你的输入数据格式,你可以应用'strip'功能,你仍然可以得到想要的输出。 –

+0

'np.array(s.split(),dtype = float)'如果不能将其中一个'words'转换为float,将会抛出一个错误。 – hpaulj

为什么不检查操作后数组是否为空并在出现错误时抛出错误?

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 
+0

这会失败,请尝试'np.fromstring('not a string',dtype = float,sep ='')' –

+0

如果空白是问题,我们可以在解析之前'去掉'字符串。查看更改。 – Farhan

+0

好的更新,现在至少我不能让它失败,但是我们知道没有其他失败的情况吗? –

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

使用与^为创业的串并$封闭为最终OF-字符串,例如

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”部分中的*更改为+以强制该数组非空。