2014-09-28 41 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