numpy.take 和 numpy.choose 有什么区别?

19 投票
3 回答
20343 浏览
提问于 2025-04-18 11:09

看起来 numpy.take(array, indices)numpy.choose(indices, array) 返回的结果是一样的:它们都是根据 indicesarray 中提取出一部分数据。

这两者之间只是一些细微的区别吗?还是说我忽略了更重要的东西?有没有理由让我们更倾向于使用其中一个呢?

3 个回答

0

下面是对 np.choose() 在文档中行为的解释。

np.choose(a,c) == np.array([c[a[I]][I] for I in ndi.ndindex(a.shape)])

索引数组和选择

import numpy as np

print("--------------------------------------------------------------------------------")
print("Index array 'a' and array of choice(s).")
print("--------------------------------------------------------------------------------")
a = np.array([4, 3, 2, 1])
print("'a' is {} shape is {}\n".format(
    a, a.shape
))
    
c = np.arange(60).reshape((5, 3, 4))
_choice = c[0]
print("An example choice is \n{} \nshape is {}\n".format(
    _choice,
    _choice.shape
))
--------------------------------------------------------------------------------
Index array 'a' and array of choice(s).
--------------------------------------------------------------------------------
'a' is [4 3 2 1] shape is (4,)

An example choice is 
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]] 
shape is (3, 4)

广播机制

给定一个整数的“索引”数组 (a) 和一系列 n 个数组 (choices),首先会将 a 和每个选择数组进行广播,调整成相同的形状;我们称这些调整后的数组为 Ba 和 Bchoices[i],其中 i = 0,…,n-1。这样一来,Ba.shape == Bchoices[i].shape 对于每个 i 都是成立的。

Ba.shape == Bchoices[i].shape

print("--------------------------------------------------------------------------------")
print("np.choose() broadcasts 'a' and 'choice' to match (here only on a)")
print("--------------------------------------------------------------------------------")
a = np.vstack([
    np.array(a) for i in range(_choice.shape[0])
])
print("Broadcast shape of 'a' is {}\n 'a' is \n{}\n.".format(a.shape, a))
--------------------------------------------------------------------------------
np.choose() broadcasts 'a' and 'choice' to match (here only on a)
--------------------------------------------------------------------------------
Broadcast shape of 'a' is (3, 4)
 'a' is 
[[4 3 2 1]
 [4 3 2 1]
 [4 3 2 1]]

从选择中选择值

c[a[I]][I] for I in ndi.ndindex(a.shape)

假设 i(在这个范围内)是 Ba 中 (j0, j1, …, jm) 位置的值,那么在新数组中相同位置的值就是 Bchoices[i] 中相同位置的值;

print("--------------------------------------------------------------------------------")
print("Simulate np.choose() behavior of choosing elements c[a[I]][I]]]:")
print("np.array([ c[a[I]][I] for I in np.lib.index_tricks.ndindex(a.shape) ])")
print("--------------------------------------------------------------------------------")
result = np.array([]).astype(int)
for I in np.lib.index_tricks.ndindex(a.shape):
    print("Selecting the element {} at c[{},{}]".format(
        c[a[I]][I].astype(int), a[I], I
    ))
    result = np.concatenate([result, [c[a[I]][I].astype(int)]])
    print("chosen items: {}".format(result))
    
print("\nResult is \n{}\n".format(
    result.reshape(a.shape)
))
--------------------------------------------------------------------------------
Simulate np.choose() behavior of choosing elements c[a[I]][I]]]:
np.array([ c[a[I]][I] for I in np.lib.index_tricks.ndindex(a.shape) ])
--------------------------------------------------------------------------------
Selecting the element 48 at c[4,(0, 0)]
chosen items: [48]
Selecting the element 37 at c[3,(0, 1)]
chosen items: [48 37]
Selecting the element 26 at c[2,(0, 2)]
chosen items: [48 37 26]
Selecting the element 15 at c[1,(0, 3)]
chosen items: [48 37 26 15]
Selecting the element 52 at c[4,(1, 0)]
chosen items: [48 37 26 15 52]
Selecting the element 41 at c[3,(1, 1)]
chosen items: [48 37 26 15 52 41]
Selecting the element 30 at c[2,(1, 2)]
chosen items: [48 37 26 15 52 41 30]
Selecting the element 19 at c[1,(1, 3)]
chosen items: [48 37 26 15 52 41 30 19]
Selecting the element 56 at c[4,(2, 0)]
chosen items: [48 37 26 15 52 41 30 19 56]
Selecting the element 45 at c[3,(2, 1)]
chosen items: [48 37 26 15 52 41 30 19 56 45]
Selecting the element 34 at c[2,(2, 2)]
chosen items: [48 37 26 15 52 41 30 19 56 45 34]
Selecting the element 23 at c[1,(2, 3)]
chosen items: [48 37 26 15 52 41 30 19 56 45 34 23]

Result is 
[[48 37 26 15]
 [52 41 30 19]
 [56 45 34 23]]

np.choose(a,c)

print("--------------------------------------------------------------------------------")
print("Run np.choose(a, c):")
print("--------------------------------------------------------------------------------")
print(np.choose(a, c))
--------------------------------------------------------------------------------
Run np.choose(a, c):
--------------------------------------------------------------------------------
[[48 37 26 15]
 [52 41 30 19]
 [56 45 34 23]]
10

它们肯定不是等价的,您可以通过给这两个方法传递相同的(交换过的)参数来看到这一点:

>>> a = np.array([[1, 2, 3, 4], 
                  [5, 6, 7, 8], 
                  [9, 10, 11, 12], 
                  [13, 14, 15, 16]])
>>> np.choose([0, 2, 1, 3], a)
array([ 1, 10,  7, 16]) # one from each row
>>> np.take(a, [0, 2, 1, 3])
array([1, 3, 2, 4]) # all from same row

我建议您查看一下关于 takechoose 的文档。

32

numpy.take(array, indices)numpy.choose(indices, array) 在一维数组上看起来很像,但这只是巧合。正如jonrsharpe所指出的,它们在多维数组上的表现是不同的。

numpy.take

numpy.take(array, indices) 是从一个扁平化的 array 中挑选元素。(结果中的元素不一定来自同一行。)

举个例子,

numpy.take([[1, 2], [3, 4]], [0, 3])

返回的结果是

array([1, 4])

numpy.choose

numpy.choose(indices, set_of_arrays) 从数组中提取元素:从 indices[0] 中提取第0个元素,从 indices[1] 中提取第1个元素,从 indices[2] 中提取第2个元素,依此类推。(这里的 array 实际上是一组数组。)

例如,

numpy.choose([0, 1, 0, 0], [[1, 2, 3, 4], [4, 5, 6, 7]])

返回的结果是

array([1, 5, 3, 4])

因为第0个元素来自数组0,第1个元素来自数组1,第2个元素来自数组0,第3个元素也来自数组0。

更多信息

以上描述是简化版的,详细的说明可以在这里找到: numpy.takenumpy.choose。例如,当 indicesarray 是一维时,numpy.takenumpy.choose 的表现很相似,因为 numpy.choose 首先会对 array 进行广播处理。

撰写回答