首页 > 解决方案 > 在numpy中随机选择不同的集合?

问题描述

我试图在 numpy 中随机选择一组整数,但遇到了一个奇怪的错误。如果我定义了一个具有两组不同大小的 numpy 数组,np.random.choice则可以毫无问题地在它们之间进行选择:

Set1 = np.array([[1, 2, 3], [2, 4]])
In:  np.random.choice(Set1)
Out: [4, 5]

但是,一旦 numpy 数组的大小相同,就会出现值错误:

Set2 = np.array([[1, 3, 5], [2, 4, 6]])
In:   np.random.choice(Set2)
ValueError: a must be 1-dimensional    

可能是用户错误,但我检查了几次,唯一的区别是集合的大小。我意识到我可以做类似的事情:

Chosen = np.random.choice(N, k)
Selection = Set[Chosen]

N集合的数量和样本的数量在哪里k,但我只是想知道是否有更好的方法,特别是当集合大小相同时我做错了什么来引发值错误。

打印输出Set1Set2参考:

In: Set1
Out: array([list([1, 3, 5]), list([2, 4])], dtype=object)
In: type(Set1)
Out: numpy.ndarray

In: Set2
Out: 
array([[1, 3, 5],
       [2, 4, 6]])
In: type(Set2)
Out: numpy.ndarray

标签: pythonnumpysampling

解决方案


您的问题是由于误解了 numpy 数组的工作原理。第一个示例不能“真正”转换为数组,因为 numpy 不支持不规则数组。您最终会得到一个指向两个 python 列表的对象引用数组。第二个例子是一个适当的 2xN 数值数组。我可以在这里想到两种类型的解决方案。

显而易见的方法(顺便说一句,这在这两种情况下都适用)是选择索引而不是子列表。由于您使用替换进行采样,因此您可以生成索引并直接使用它:

Set[np.random.randint(N, size=k)]

这与

Set[np.random.choice(N, k)]

如果您想选择不替换,最好的选择是使用np.random.choice, 和replace=False。这类似于洗牌,但效率低于洗牌。在任何一种情况下,您都可以为索引编写一个单行代码:

Set[np.random.choice(N, k, replace=False)]

或者:

index = np.arange(Set.shape[0])
np.random.shuffle(index)
Set[index[:k]]

不过,它的好处np.random.shuffle是您可以Set直接将其应用于一维或多维数组。洗牌总是沿着第一个轴发生,所以你可以在k之后取顶部元素:

np.random.shuffle(Set)
Set[:k]

洗牌操作只能在原地工作,所以你必须把它写出来。对于大型数组,它的效率也较低,因为无论多小,您都必须预先创建整个范围k

另一种解决方案是将第二个示例转换为与第一个示例类似的列表对象数组。除非您使用 numpy 的唯一原因是该choice功能,否则我不推荐此解决方案。事实上,我根本不会推荐它,因为random此时您可以并且可能应该使用 pythons 标准模块。除了免责声明,您可以将第二个数组的数据类型强制为object. 它将消除使用 numpy 的任何好处,并且不能直接完成。简单的设置dtype=object仍然会创建一个二维数组,但会在其中存储对 pythonint对象的引用而不是原语。你必须做这样的事情:

Set = np.zeros(N, dtype=object)
Set[:] = [[1, 2, 3], [2, 4]]

您现在将获得一个与第一个示例中的对象基本等效的对象,因此可以np.random.choice直接应用。

笔记

np.random如果没有别的原因,我会在这里展示遗留方法,因为个人惯性。正如我链接到的文档中所建议的那样,正确的方法是使用新的生成器API。对于该choice方法尤其如此,它在新的实现中效率更高。使用不再困难:

Set[np.random.default_rng().choice(N, k, replace=False)]

还有其他优点,例如您现在可以直接选择,甚至可以从多维数组中选择:

np.random.default_rng().choice(Set2, k, replace=False)

也是如此shuffle,就像 一样choice,现在允许您选择要重新排列的轴:

np.random.default_rng().shuffle(Set)
Set[:k]

推荐阅读