2017-07-19 224 views
0

我需要一個函數,它將(非二進制)字符串作爲輸入並返回一個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的,妥善拋出一個錯誤,如果輸入無法轉換爲數字陣列?

回答

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

嘗試'np.fromstring('not a string',dtype = float,sep ='')',這會返回'array([ - 1。])''。 –

+0

如果你知道你的輸入數據格式,你可以應用'strip'功能,你仍然可以得到想要的輸出。 –

+0

'np.array(s.split(),dtype = float)'如果不能將其中一個'words'轉換爲float,將會拋出一個錯誤。 – hpaulj

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

這會失敗,請嘗試'np.fromstring('not a string',dtype = float,sep ='')' –

+0

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

+0

好的更新,現在至少我不能讓它失敗,但是我們知道沒有其他失敗的情況嗎? –

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 

使用與^爲創業的串並$封閉爲最終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」部分中的*更改爲+以強制該數組非空。