2016-01-20 86 views
0

我有兩個不同行數的特徵矩陣。 假設矩陣A具有比矩陣B更多的行。矩陣的列包括ID1,ID2,Time_slice,特徵值。由於對於某些Time_slice,B中沒有任何特徵值,B中的行數少於A.我需要查找B中哪些行被遺漏。然後將行添加到B中,使用相關的ID1,ID2值以及零特徵。在Python中比較兩個矩陣並填充錯過的行

  ID1 ID2 Time_slice Feature 
A= array([[ 100, 1., 0.,  1.5], 
      [ 100, 1., 1.,  3.7], 
      [ 100, 2., 0.,  1.2], 
     [ 100, 2., 1.,  1.8], 
     [ 100, 2., 2.,  2.9], 
     [ 101, 3., 0.,  1.5], 
      [ 101, 3., 1.,  3.7], 
      [ 101, 4., 0.,  1.2], 
     [ 101, 4., 1.,  1.8], 
     [ 101, 4., 2.,  2.9]]) 

B= array([[ 100, 1., 0.,  1.25], 
      [ 100, 1., 1.,  3.37], 
      [ 100, 2., 0.,  1.42], 
     [ 100, 2., 1.,  1.68]]) 

Output should be as follow: 

     [[ 100, 1., 0.,  1.25], 
      [ 100, 1., 1.,  3.37], 
      [ 100, 2., 0.,  1.42], 
     [ 100, 2., 1.,  1.68], 
     [ 100, 2., 2.,  0 ], 
     [ 101, 3., 0.,  0], 
      [ 101, 3., 1.,  0], 
      [ 101, 4., 0.,  0], 
     [ 101, 4., 1.,  0], 
     [ 101, 4., 2.,  0]]) 

回答

1

你可以嘗試這樣的:

import numpy as np 

A = np.array([[ 100, 1., 0.,  1.5], 
      [ 100, 1., 1.,  3.7], 
      [ 100, 2., 0.,  1.2], 
      [ 100, 2., 1.,  1.8], 
      [ 100, 2., 2.,  2.9], 
      [ 101, 3., 0.,  1.5], 
      [ 101, 3., 1.,  3.7], 
      [ 101, 4., 0.,  1.2], 
      [ 101, 4., 1.,  1.8], 
      [ 101, 4., 2.,  2.9]]) 

B = np.array([[ 100, 1., 0.,  1.25], 
      [ 100, 1., 1.,  3.37], 
      [ 100, 2., 0.,  1.42], 
      [ 100, 2., 1.,  1.68]]) 

listB = B.tolist() 

for rowA in A: 
    if rowA.tolist not in listB: 
     B = np.append(B, [[rowA[0], rowA[1], rowA[2], 0]], axis=0) 

print B 
+0

這將是更好的追加,或者將新行插入一個列表('listB'或一個新的副本),並在最後重建數組。反覆使用'np.append'很慢。 – hpaulj

+1

我在代碼中做了一些更改以比較前三列,並且我嘗試了與@hpaulj所說的優化速度相同的方法。謝謝。 – YNr

+0

@hpaulj,是的重複使用np.append很慢。在列表中工作並最終將其完成到數組對於性能來說更好。當我快速回答問題時,我並沒有考慮perf。謝謝。 – triiiiista

1

看來(從期望的輸出),在A中的行被認爲是在乙匹配行 如果前三列相等。如果我們能夠確定A的哪些行匹配B的行,那麼您的問題將在很大程度上得到解決。

如果識別匹配只取決於來自單個列的值,那麼我們可以使用np.in1d。例如,如果是[0, 1, 2, 5 ,0]A[0, 2]均值B,然後

In [39]: np.in1d([0, 1, 2, 5, 0], [0, 2]) 
Out[39]: array([ True, False, True, False, True], dtype=bool) 

顯示其中的BA匹配行的行。

在NumPy中沒有(當前)這個函數沒有更高維的泛化。

有一個特技,然而,其可被用來視圖的2D陣列多列作爲字節值的單個列 - 從而把2D陣列成一維數組。然後我們可以將np.in1d應用到這個1D數組。這一招,我learned from Jaime,這裏封裝在功能,asvoid

import numpy as np 

def asvoid(arr): 
    """ 
    View the array as dtype np.void (bytes). 

    This views the last axis of ND-arrays as np.void (bytes) so 
    comparisons can be performed on the entire row. 
    https://stackoverflow.com/a/16840350/190597 (Jaime, 2013-05) 

    Some caveats: 
     - `asvoid` will work for integer dtypes, but be careful if using asvoid on float 
     dtypes, since float zeros may compare UNEQUALLY: 
     >>> asvoid([-0.]) == asvoid([0.]) 
     array([False], dtype=bool) 

     - `asvoid` works best on contiguous arrays. If the input is not contiguous, 
     `asvoid` will copy the array to make it contiguous, which will slow down the 
     performance. 

    """ 
    arr = np.ascontiguousarray(arr) 
    return arr.view(np.dtype((np.void, arr.dtype.itemsize * arr.shape[-1]))) 

A = np.array([[ 100, 1., 0.,  1.5], 
       [ 100, 1., 1.,  3.7], 
       [ 100, 2., 0.,  1.2], 
       [ 100, 2., 1.,  1.8], 
       [ 100, 2., 2.,  2.9], 
       [ 101, 3., 0.,  1.5], 
       [ 101, 3., 1.,  3.7], 
       [ 101, 4., 0.,  1.2], 
       [ 101, 4., 1.,  1.8], 
       [ 101, 4., 2.,  2.9]]) 

B = np.array([[ 100, 1., 0.,  1.25], 
       [ 100, 1., 1.,  3.37], 
       [ 100, 2., 0.,  1.42], 
       [ 100, 2., 1.,  1.68]]) 

mask = np.in1d(asvoid(A[:, :3]), asvoid(B[:, :3])) 
result = A[~mask] 
result[:, -1] = 0 
result = np.row_stack([B, result]) 
print(result)  

產量

[[ 100.  1.  0.  1.25] 
[ 100.  1.  1.  3.37] 
[ 100.  2.  0.  1.42] 
[ 100.  2.  1.  1.68] 
[ 100.  2.  2.  0. ] 
[ 101.  3.  0.  0. ] 
[ 101.  3.  1.  0. ] 
[ 101.  4.  0.  0. ] 
[ 101.  4.  1.  0. ] 
[ 101.  4.  2.  0. ]]