2016-01-25 29 views
-1

我有一個字典,將數值映射到標籤。我用它爲給定的numpy數組創建標籤。該數組最初包含所有NaN值,某些元素使用非NaN值填充。我想將NaN值映射到標籤。但是,這個失敗:如何使用字典將nn中的NaN映射爲值?

import numpy as np 
# make array with all NaNs 
a = np.ones(5) * np.nan 
# populate some of it with non-NaN values 
a[0] = 1 
a[1] = 2 
l = {"1": "one", 2: "two", np.nan: "NA"} 
for k in l: 
    if k == np.nan: 
    print l[k] 
# this returns false 
print (np.nan in a) 

這是因爲數組的初始化?爲什麼np.nan不等於a中的NaN值?

我試圖得到一個工作版本:

print l[a[3]] # should print "NA", not raise keyerror 
+0

我的天堂」這個還沒有提到,但它真的好像你想要與numpy的m一起工作問陣列。他們幫助你避免所有這些南方問題... – mgilson

回答

3

一個有趣的事情有關NaNIEEE指定NaN不等於什麼(包括自身)。 Numpy和Python總體上遵循這個規則。

>>> NaN = float('nan') 
>>> NaN == NaN 
False 
>>> import numpy as np 
>>> np.nan == np.nan 
False 

這應該解釋爲什麼你print l['k']語句不打印過,爲什麼np.nan in a不返回True

一種解決方法可能是:

>>> import numpy as np 
>>> d = {np.nan: 'foo'} 
>>> d[np.nan] 
'foo' 
>>> a = np.array([np.nan]) 
>>> d[a[0]] 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
KeyError: nan 

不幸的是,有沒有:

numpy.isnan(a).any() # Check if any element in `a` is `nan`. 

如果我正確理解您的評論,問題更恰當地通過下面的代碼片段展示由於NaN的瘋狂屬性,您可以在這裏做很多事情。數組本質上是C數組,它們保存浮點數。當你有一個自由浮動np.nan,它有一個永遠不會改變的ID(內存地址),所以Python可以通過指針比較來鎖定它。這就是爲什麼第一位使用上面的字典。

不幸的是,當您將NaN放入數組中時,它會使用NaN填充數組中的值。在這種情況下,該元素的ID是相對於數組中第一個元素的位置 - 所以python不能說這個NaN與您用來構造數組的元素相同(因爲它不是)。由於ID比較現在失敗,並且由於NaN的屬性而導致平等比較失敗,因此您運氣不佳。

至於你的價值 - >標籤轉換,你也許可以使用numpy的內建功能:

label_array = np.empty(a.shape, dtype='|S3') 
label_array[np.isnan(a)] = 'NA' 
label_array[a == 1] = 'one' 
label_array[a == 2] = 'two' 

爲中等大小的數組,這個應該足夠快...

注,如果你直接在a中輸入那個和兩個數字,這真的只會起作用 - 如果你已經做了一些浮點數學計算來計算它們,那就不行了。例如a[n] = 5./2.5的精度誤差可以讓你用數字非常接近2是不太等於2 ...

+0

我想將一個數組的特定元素,基於它的位置,與一個標籤。我想處理包含標籤的字典的鍵是np.nan的情況。你展示瞭如何檢查np.nan是否在數組中,但是不能解決字典映射的問題 – mvd

+0

@mvd - 對不起,我不理解你在這裏嘗試着什麼......你可以使用'numpy.isnan(k)'爲您的測試,而不是'k == np.nan',如果這有幫助... – mgilson

+0

我遍歷一個數組,並且我想創建一個相同大小的數組,每個條目都有一個標籤。標籤的值存儲在字典中。這意味着我需要從數組中獲得一個值,它是nan,並將其用作字典的關鍵字。我不只是檢查平等 – mvd

0

NaN的失敗任何比較檢查,包括對本身。即

NaN == NaN 

是假的。

因此,您的發言

if k == np.nan: 

必須返回爲k的所有值。相反,試試這個:

if not k == k: 
    print l[k] 

這會產生所需的「NA」輸出。

請注意,您不能惡搞這與

if k != k: 

,因爲這也將返回


這是否適合您?

import numpy as np 
# make array with all NaNs 
a = np.ones(5) * np.nan 
# populate some of it with non-NaN values 
a[0] = 1 
a[1] = 2 
a[3] = 1 
l = {1: "one", 2: "two", "NaN": "NA"} 
for k in l: 
    if not k == k: 
    print l[k] 
# this returns false 
print (np.nan in a) 

a_label = [l[a[n]] if a[n] in l else l["NaN"] for n in range(len(a))] 
print a_label 

輸出:

False 
['one', 'two', 'NA', 'one', 'NA'] 
0

您可以創建自己的字典,處理NaN的他們的方式,你希望它:

class MyDict(dict): 

    def __getitem__(self, key): 
     try: 
      if np.isnan(key): 
       return 'NA' 
     except TypeError: 
      pass 
     return super(MyDict, self).__getitem__(key) 

    def __contains__(self, key): 
     try: 
      self.__getitem__(key) 
      return True 
     except KeyError: 
      return False 

測試:

>>> l = MyDict({1: "one", 2: "two"}) 
>>> l[a[3]] 
'NA' 
>>> l[a[0]] 
'one' 
>>> np.nan in l 
True