查看对选项的调用集:
In [27]: np.random.choice(range(4), size=(1,3), replace=False)
Out[27]: array([[1, 2, 3]])
In [28]: np.random.choice(range(4), size=(1,3), replace=False)
Out[28]: array([[2, 1, 3]])
In [29]: np.random.choice(range(4), size=(1,3), replace=False)
Out[29]: array([[1, 2, 0]])
In [30]: np.random.choice(range(4), size=(1,3), replace=False)
Out[30]: array([[1, 3, 2]])
In [31]: np.random.choice(range(4), size=(1,3), replace=False)
Out[31]: array([[2, 3, 0]])
In [32]: np.random.choice(range(4), size=(1,3), replace=False)
Out[32]: array([[1, 3, 2]])
请注意,[1,3,2] 出现了两次。
这会产生这个范围内所有长度为 3 的排列(不是随机顺序 - 尽管列表可以打乱)
In [33]: import itertools
In [34]: itertools.permutations?
Init signature: itertools.permutations(self, /, *args, **kwargs)
Docstring:
permutations(iterable[, r]) --> permutations object
Return successive r-length permutations of elements in the iterable.
permutations(range(3), 2) --> (0,1), (0,2), (1,0), (1,2), (2,0), (2,1)
Type: type
In [35]: itertools.permutations(range(4), 3)
Out[35]: <itertools.permutations at 0xaf7193bc>
In [36]: list(_)
Out[36]:
[(0, 1, 2),
(0, 1, 3),
...
(3, 2, 1)]
这些排列的加权值:
In [38]: wgts = np.arange(1, 4)
In [39]: A = np.array(list(itertools.permutations(range(4),3)))
In [40]: A.shape
Out[40]: (24, 3)
In [41]: wgts
Out[41]: array([1, 2, 3])
In [42]: A.dot(wgts)
Out[42]:
array([ 8, 11, 7, 13, 9, 12, 7, 10, 5, 14, 7, 13, 5, 11, 4, 13, 8,
11, 6, 9, 5, 11, 7, 10])
根据您的评论,我知道您正在抽样更换。这是一种快速的蛮力方法,例如搜索
生成一堆测试值。由于这是对每一行进行替换,因此我们只需一次调用 choice 就可以生成许多行:
In [55]: A = np.random.choice(range(4), size=(100,3), replace=True)
In [56]: A
Out[56]:
array([[3, 1, 1],
[0, 3, 0],
[1, 3, 2],
[3, 1, 1],
[2, 0, 2],
[0, 3, 2],
...
[3, 0, 3]])
和之前一样取加权和:
In [57]: wgts = np.arange(1, 4)
In [58]: A.dot(wgts)
Out[58]:
array([ 8, 6, 13, 8, 8, 12, 5, 10, 9, 12, 9, 9, 7, 9, 0, 4, 3,
6, 10, 8, 7, 2, 3, 14, 11, 7, 1, 7, 2, 5, 11, 3, 13, 12,
7, 9, 4, 15, 1, 7, 7, 9, 10, 7, 9, 11, 14, 3, 13, 11, 2,
9, 9, 2, 11, 16, 4, 10, 13, 9, 11, 8, 10, 5, 7, 8, 13, 15,
11, 9, 13, 7, 6, 9, 5, 12, 9, 11, 6, 3, 0, 0, 9, 7, 11,
0, 12, 9, 7, 7, 3, 7, 13, 3, 9, 5, 14, 1, 16, 12])
并找到总和具有目标值的索引:
In [59]: np.where(_==4)
Out[59]: (array([15, 36, 56], dtype=int32),)
In [60]: A[_]
Out[60]:
array([[2, 1, 0],
[2, 1, 0],
[0, 2, 0]])
对于N=5:
In [61]: A = np.random.choice(range(5), size=(100,4), replace=True)
In [62]: A.dot(np.arange(1,5))
Out[62]:
array([29, 20,... 23])
In [63]: np.where(_==5)
Out[63]: (array([], dtype=int32),)
这个样本不够大,让我们试试更大的:
In [64]: A = np.random.choice(range(5), size=(500,4), replace=True)
In [65]: A.dot(np.arange(1,5))
Out[65]:
array([23, 8, 17, ...18])
In [66]: np.where(_==5)
Out[66]: (array([ 58, 267, 443], dtype=int32),)
In [67]: A[_]
Out[67]:
array([[1, 2, 0, 0],
[3, 1, 0, 0],
[2, 0, 1, 0]])
itertools.product 可用于通用所有组合
In [71]: A = np.array(list(itertools.product(range(4),repeat=3)))
In [72]: A.shape
Out[72]: (64, 3)
In [73]: x = A.dot(np.arange(1,4))
In [74]: A[x==4]
Out[74]:
array([[0, 2, 0],
[1, 0, 1],
[2, 1, 0]])
对于 N=5:
In [75]: A = np.array(list(itertools.product(range(5),repeat=4)))
In [76]: A.shape
Out[76]: (625, 4)
In [77]: x = A.dot(np.arange(1,5))
In [78]: A[x==5]
Out[78]:
array([[0, 1, 1, 0],
[1, 0, 0, 1],
[1, 2, 0, 0],
[2, 0, 1, 0],
[3, 1, 0, 0]])
要迭代地进行搜索,我会使用 product 作为生成器:
In [100]: g = itertools.product(range(5), repeat=4)
In [101]: for cnt, row in enumerate(g):
...: if np.arange(1,5).dot(row)==5:
...: print(cnt, row)
...:
...:
30 (0, 1, 1, 0)
126 (1, 0, 0, 1)
175 (1, 2, 0, 0)
255 (2, 0, 1, 0)
400 (3, 1, 0, 0)
或者只找到第一个:
In [102]: g = itertools.product(range(5), repeat=4)
In [103]: for cnt, row in enumerate(g):
...: if np.arange(1,5).dot(row)==5:
...: print(cnt, row)
...: break
...:
30 (0, 1, 1, 0)