在numpy中随机选择不同的集合?
randomly choose different sets in numpy?
我试图在 numpy 中随机 select 一组整数,但遇到了一个奇怪的错误。如果我定义一个具有两组不同大小的 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
是样本数,但我只是想知道是否有更好的方法,特别是我做错了什么集合大小相同时的值错误。
Set1
和 Set2
的打印输出供参考:
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
您的问题是由于对 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 的 only 原因是为了 choice
函数。事实上,我根本不推荐它,因为此时您可以并且可能应该使用 python 的标准 random
模块。除了免责声明,您可以将第二个数组的数据类型强制为 object
。它将消除使用 numpy 的任何好处,并且不能直接完成。简单地设置 dtype=object
仍然会创建一个二维数组,但会存储对 python int
对象的引用,而不是其中的基元。你必须这样做:
Set = np.zeros(N, dtype=object)
Set[:] = [[1, 2, 3], [2, 4]]
您现在将获得一个与第一个示例中的对象基本相同的对象,因此可以直接应用 np.random.choice
。
备注
我展示了遗留的 np.random
methods here because of personal inertia if nothing else. The correct way, as suggested in the documentation I link to, is to use the new Generator API. This is especially true for the choice
方法,该方法在新实现中效率更高。用法也不难了:
Set[np.random.default_rng().choice(N, k, replace=False)]
还有其他优势,比如您现在可以直接选择,甚至可以从多维数组中选择:
np.random.default_rng().choice(Set2, k, replace=False)
shuffle
也是如此,它与 choice
一样,现在允许您 select 您想要重新排列的轴:
np.random.default_rng().shuffle(Set)
Set[:k]
我试图在 numpy 中随机 select 一组整数,但遇到了一个奇怪的错误。如果我定义一个具有两组不同大小的 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
是样本数,但我只是想知道是否有更好的方法,特别是我做错了什么集合大小相同时的值错误。
Set1
和 Set2
的打印输出供参考:
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
您的问题是由于对 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 的 only 原因是为了 choice
函数。事实上,我根本不推荐它,因为此时您可以并且可能应该使用 python 的标准 random
模块。除了免责声明,您可以将第二个数组的数据类型强制为 object
。它将消除使用 numpy 的任何好处,并且不能直接完成。简单地设置 dtype=object
仍然会创建一个二维数组,但会存储对 python int
对象的引用,而不是其中的基元。你必须这样做:
Set = np.zeros(N, dtype=object)
Set[:] = [[1, 2, 3], [2, 4]]
您现在将获得一个与第一个示例中的对象基本相同的对象,因此可以直接应用 np.random.choice
。
备注
我展示了遗留的 np.random
methods here because of personal inertia if nothing else. The correct way, as suggested in the documentation I link to, is to use the new Generator API. This is especially true for the choice
方法,该方法在新实现中效率更高。用法也不难了:
Set[np.random.default_rng().choice(N, k, replace=False)]
还有其他优势,比如您现在可以直接选择,甚至可以从多维数组中选择:
np.random.default_rng().choice(Set2, k, replace=False)
shuffle
也是如此,它与 choice
一样,现在允许您 select 您想要重新排列的轴:
np.random.default_rng().shuffle(Set)
Set[:k]