2014-09-28 66 views
0

經過與R的長時間工作,我返回與Python一起工作,發現數組操作不是很方便。數組不能通過行和列名稱進行索引。我希望有人能夠幫助並告訴我如何以Pythonic的方式處理數組。使用數組在numpy中操作

我有兩個numpy陣列

a = np.arange(12).reshape(3,4) 
>>> a 
array([[ 0, 1, 2, 3], 
     [ 4, 5, 6, 7], 
     [ 8, 9, 10, 11]]) 

b = np.arange(20).reshape(4,5).T + 10 
>>> b 
array([[10, 15, 20, 25], 
     [11, 16, 21, 26], 
     [12, 17, 22, 27], 
     [13, 18, 23, 28], 
     [14, 19, 24, 29]]) 

和行的名稱每個陣列

a_rownames = ["m1", "m2", "m3"] 
b_rownames = ["m1", "m2", "m1", "m3", "m2"] 

的任務是在陣列b與相應的值從a替換指定列columns_ids的值。兩個數組ab中列的順序相同。

columns_ids = [False, True, False, True] 

預期的輸出:

array([[10, 1, 20, 3], 
     [11, 5, 21, 7], 
     [12, 1, 22, 3], 
     [13, 9, 23, 11], 
     [14, 5, 24, 7]]) 

如何有效地做到這一點?

+2

請注意,實際上您並不需要命名列來執行此操作,但numpy確實支持命名列(請參閱dtype的文檔),熊貓的數據框專門用於反映您在R中習慣使用的用法。 – mdurant 2014-09-28 15:57:47

+0

'熊貓'的描述,它看起來像我需要從R輕鬆遷移到Python世界。謝謝你指出我!但如果這可能與numpy有關,這也將很好。 – DrDom 2014-09-28 16:27:54

回答

2

如果你放棄了名稱了一下,這是不是太狠:

import numpy 

a = numpy.arange(12).reshape(3,4) 
b = numpy.arange(20).reshape(4,5).T + 10 

b_rows = [0, 1, 0, 2, 1] 
columns_ids = numpy.array([False, True, False, True]) 

b[:, columns_ids] = a[:, columns_ids][b_rows] 

b 
#>>> array([[10, 1, 20, 3], 
#>>>  [11, 5, 21, 7], 
#>>>  [12, 1, 22, 3], 
#>>>  [13, 9, 23, 11], 
#>>>  [14, 5, 24, 7]]) 

如果你真的想要的名稱的外部數組:

a = numpy.arange(12).reshape(3,4) 
b = numpy.arange(20).reshape(4,5).T + 10 

a_rownames = numpy.array(["m1", "m2", "m3"]) 
b_rownames = numpy.array(["m1", "m2", "m1", "m3", "m2"]) 

_, b_rows = numpy.where(a_rownames == b_rownames[:, numpy.newaxis]) 

b[:, columns_ids] = a[:, columns_ids][b_rows] 

b 
#>>> array([[10, 1, 20, 3], 
#>>>  [11, 5, 21, 7], 
#>>>  [12, 1, 22, 3], 
#>>>  [13, 9, 23, 11], 
#>>>  [14, 5, 24, 7]]) 

這片神奇有三個步驟:

_, b_rows = numpy.where(a_rownames == b_rownames[:, numpy.newaxis]) 

首先,我們產生兩個垂直陣列:

a_rownames 
#>>> array(['m1', 'm2', 'm3'], 
#>>>  dtype='<U2') 

b_rownames[:, numpy.newaxis] 
#>>> array([['m1'], 
#>>>  ['m2'], 
#>>>  ['m1'], 
#>>>  ['m3'], 
#>>>  ['m2']], 
#>>>  dtype='<U2') 

然後我們==比較會用「廣播」重複這些陣列,直到尺寸匹配:

a_rownames == b_rownames[:, numpy.newaxis] 
#>>> array([[ True, False, False], 
#>>>  [False, True, False], 
#>>>  [ True, False, False], 
#>>>  [False, False, True], 
#>>>  [False, True, False]], dtype=bool) 

numpy.wherexsys索引此數組來獲取所有值爲True。我們只對ys感興趣,所以我們忽略了xs

_, b_rows = numpy.where(a_rownames == b_rownames[:, numpy.newaxis]) 

另一片神奇:

b[:, columns_ids] = a[:, columns_ids][b_rows] 

需要知道兩種不同類型的索引:

  • 索引與布爾數組濾波器陣列

  • 索引整數數組在這些指標

索引像

array[xs] 

array[xs, :] 

得到行(他們是由於廣播相同)會給你所有由於上述規則而匹配的索引,在第一個軸上進行過濾。

使用

array[:, ys] 

將在第二軸線進行過濾。

所以我們首先篩選列(第二軸)

b[:, columns_ids] 
#>>> array([[ 1, 3], 
#>>>  [ 5, 7], 
#>>>  [ 1, 3], 
#>>>  [ 9, 11], 
#>>>  [ 5, 7]]) 

a[:, columns_ids] 
#>>> array([[ 1, 3], 
#>>>  [ 5, 7], 
#>>>  [ 9, 11]]) 

然後我們就a(第一軸)過濾行:

a[:, columns_ids][b_rows] 
#>>> array([[ 1, 3], 
#>>>  [ 5, 7], 
#>>>  [ 1, 3], 
#>>>  [ 9, 11], 
#>>>  [ 5, 7]]) 

他們現在是相同的形狀,這樣你就可以做切片分配:

b[:, columns_ids] = a[:, columns_ids][b_rows] 
+0

你能解釋一下最後兩個命令的魔力嗎? – DrDom 2014-09-28 16:22:11

+0

很好的解釋,非常感謝! – DrDom 2014-09-28 17:33:47

3

或者生成一個新的數組而不覆蓋原始在b中:

np.where(column_ids[None,:], a[row_ids], b) 

其中column_ids和row_ids也是數組,如同在另一個答案中一樣。

+0

這也是非常好的和極短的解決方案!但是使用'None'創建新軸的原因是什麼?即使使用'np.where(columns_ids,a [b_rows],b)'' – DrDom 2014-09-28 17:32:36

+0

,它也可以正常工作。我發現明確指出正在處理的數組的維度是很有用的。 – mdurant 2014-09-28 19:10:29