组合学:包含替代元素的列表
Combinatorics: list with alternative elements
我有一个 python 列表,其中包含一个或多个元素的一维 numpy 数组作为元素。将每个数组元素视为相应列表元素的替代项。
一个例子:
[array([1]),array([2]),array([2,3]),array([3]),array([4]),array([3,4,5])]
我想要两样东西:
1) 所有选项的组合:
array([[1,2,2,3,4,3],
[1,2,3,3,4,3],
[1,2,2,3,4,4],
[1,2,3,3,4,4],
[1,2,2,3,4,5],
[1,2,3,3,4,5]])
2.重复次数最少的组合:
array([1,2,2,3,4,5])
或
array([1,2,3,3,4,5]).
第二个应该不难得到,一旦有了第一个,但我不确定。
我还想使用更复杂的设置,例如
datasets_complete = [("iris1", iris1), ("iris2", iris2)]
percentages = [0.05, 0.1, 0.2, 0.5]
imputers = [SimpleFill(), KNN(k=3), SoftImpute(), MICE()]
gridWidths = [0.1, 0.2]
seq = [datasets_complete, percentages, imputers, gridWidths]
testgrid = all_combinations(seq)
其中 iris1 和 iris2 是 pandas 数据帧。
您可以像这样使用 itertools.product 函数:
import itertools
from numpy import array
test = [array([1]),array([2]),array([2,3]),array([3]),array([4]),array([3,4,5])]
combinations = [list(tup) for tup in itertools.product(*test)]
print(combinations)
这个returns:
[[1, 2, 2, 3, 4, 3],
[1, 2, 2, 3, 4, 4],
[1, 2, 2, 3, 4, 5],
[1, 2, 3, 3, 4, 3],
[1, 2, 3, 3, 4, 4],
[1, 2, 3, 3, 4, 5]]
第 2 部分不可解,因为可能存在非唯一解...
这是一个基于 NumPy 的方法 -
def all_combs(a): # Parte-1
num_combs = np.prod(list(map(len,a)))
return np.array(np.meshgrid(*a)).reshape(-1,num_combs).T
def get_minrep_combs(a): # Parte-2
out = all_combs(a)
counts = (np.diff(np.sort(out,axis=1),axis=1)==0).sum(1)
return out[counts == counts.min()]
样本运行-
In [161]: a = [np.array([1]),np.array([2]),np.array([2,3]),np.array([3]),\
...: np.array([4]),np.array([3,4,5])]
In [162]: all_combs(a) # Part-1 results
Out[162]:
array([[1, 2, 2, 3, 4, 3],
[1, 2, 2, 3, 4, 4],
[1, 2, 2, 3, 4, 5],
[1, 2, 3, 3, 4, 3],
[1, 2, 3, 3, 4, 4],
[1, 2, 3, 3, 4, 5]])
In [163]: get_minrep_combs(a) # Part-2 results
Out[163]:
array([[1, 2, 2, 3, 4, 5],
[1, 2, 3, 3, 4, 5]])
只是为了让大家了解一下 all_combs
,这里还有一些 "normal" 示例 运行s -
In [166]: a = [np.array([2,3]), np.array([5,6,7])]
In [167]: all_combs(a)
Out[167]:
array([[2, 5],
[3, 5],
[2, 6],
[3, 6],
[2, 7],
[3, 7]])
In [164]: a = [np.array([2,3,4]), np.array([5,6,7,9])]
In [165]: all_combs(a)
Out[165]:
array([[2, 5],
[3, 5],
[4, 5],
[2, 6],
[3, 6],
[4, 6],
[2, 7],
[3, 7],
[4, 7],
[2, 9],
[3, 9],
[4, 9]])
性能
为了性能,我们可以避免 part-1
中的转置,并在 part-2
中沿列 (axis=0)
执行操作,还可以使用切片来避免 np.diff
,因此有一个优化版本,像这样 -
def get_minrep_combs_optimized(a): # Parte-1,2
num_combs = np.prod(list(map(len,a)))
out = np.array(np.meshgrid(*a)).reshape(-1,num_combs)
sorted_out = np.sort(out,axis=0)
counts = (sorted_out[1:] == sorted_out[:-1]).sum(0)
return out[:,counts == counts.min()].T
样本运行-
In [188]: a = [np.array([1]),np.array([2]),np.array([2,3]),np.array([3]),\
...: np.array([4]),np.array([3,4,5])]
In [189]: get_minrep_combs_optimized(a)
Out[189]:
array([[1, 2, 2, 3, 4, 5],
[1, 2, 3, 3, 4, 5]])
运行时测试
这是创建样本输入数据的一种方法,它最多有 3
个元素,每个子列表有 一些 与其他子列表中的元素匹配 -
In [42]: lens = np.random.randint(1,4,(20))
In [43]: a = [np.random.randint(1,10,L) for L in lens]
In [44]: lens
Out[44]: array([1, 1, 2, 2, 2, 2, 1, 2, 3, 2, 1, 2, 2, 3, 1, 1, 3, 2, 2, 3])
In [45]: a
Out[45]:
[array([8]),
array([8]),
array([7, 9]),
array([5, 5]),
array([6, 4]),
array([3, 1]),
array([8]),
array([1, 9]),
array([9, 5, 7]),
array([1, 1]),
array([3]),
array([1, 5]),
array([5, 5]),
array([7, 9, 2]),
array([5]),
array([1]),
array([3, 2, 9]),
array([3, 7]),
array([5, 3]),
array([2, 7, 3])]
计时 -
In [46]: %timeit leastReps(combinations(a)) #@Daniel Forsman's soln
1 loops, best of 3: 330 ms per loop
In [47]: %timeit get_minrep_combs_optimized(a)
10 loops, best of 3: 28.7 ms per loop
让我们有更多的比赛-
In [50]: a = [np.random.randint(1,4,L) for L in lens]
In [51]: %timeit leastReps(combinations(a)) #@Daniel Forsman's soln
1 loops, best of 3: 328 ms per loop
In [52]: %timeit get_minrep_combs_optimized(a)
10 loops, best of 3: 29.5 ms per loop
性能差异没有太大变化。
def combinations(arrList):
mesh=np.meshgrid(*arrList)
mesh=[arr.ravel() for arr in mesh]
return np.array(mesh).T
def leastReps(combs):
uniques=np.array([np.unique(arr).size for arr in list(combs)])
mostUni = (uniques == np.max(uniques))
return combs[mostUni]
我的和Divakar的唯一区别是我不用提前计算产品的数量,我用的uniques最多,他用的repetitions最少,应该是等价的。
我有一个 python 列表,其中包含一个或多个元素的一维 numpy 数组作为元素。将每个数组元素视为相应列表元素的替代项。
一个例子:
[array([1]),array([2]),array([2,3]),array([3]),array([4]),array([3,4,5])]
我想要两样东西:
1) 所有选项的组合:
array([[1,2,2,3,4,3],
[1,2,3,3,4,3],
[1,2,2,3,4,4],
[1,2,3,3,4,4],
[1,2,2,3,4,5],
[1,2,3,3,4,5]])
2.重复次数最少的组合:
array([1,2,2,3,4,5])
或
array([1,2,3,3,4,5]).
第二个应该不难得到,一旦有了第一个,但我不确定。
我还想使用更复杂的设置,例如
datasets_complete = [("iris1", iris1), ("iris2", iris2)]
percentages = [0.05, 0.1, 0.2, 0.5]
imputers = [SimpleFill(), KNN(k=3), SoftImpute(), MICE()]
gridWidths = [0.1, 0.2]
seq = [datasets_complete, percentages, imputers, gridWidths]
testgrid = all_combinations(seq)
其中 iris1 和 iris2 是 pandas 数据帧。
您可以像这样使用 itertools.product 函数:
import itertools
from numpy import array
test = [array([1]),array([2]),array([2,3]),array([3]),array([4]),array([3,4,5])]
combinations = [list(tup) for tup in itertools.product(*test)]
print(combinations)
这个returns:
[[1, 2, 2, 3, 4, 3],
[1, 2, 2, 3, 4, 4],
[1, 2, 2, 3, 4, 5],
[1, 2, 3, 3, 4, 3],
[1, 2, 3, 3, 4, 4],
[1, 2, 3, 3, 4, 5]]
第 2 部分不可解,因为可能存在非唯一解...
这是一个基于 NumPy 的方法 -
def all_combs(a): # Parte-1
num_combs = np.prod(list(map(len,a)))
return np.array(np.meshgrid(*a)).reshape(-1,num_combs).T
def get_minrep_combs(a): # Parte-2
out = all_combs(a)
counts = (np.diff(np.sort(out,axis=1),axis=1)==0).sum(1)
return out[counts == counts.min()]
样本运行-
In [161]: a = [np.array([1]),np.array([2]),np.array([2,3]),np.array([3]),\
...: np.array([4]),np.array([3,4,5])]
In [162]: all_combs(a) # Part-1 results
Out[162]:
array([[1, 2, 2, 3, 4, 3],
[1, 2, 2, 3, 4, 4],
[1, 2, 2, 3, 4, 5],
[1, 2, 3, 3, 4, 3],
[1, 2, 3, 3, 4, 4],
[1, 2, 3, 3, 4, 5]])
In [163]: get_minrep_combs(a) # Part-2 results
Out[163]:
array([[1, 2, 2, 3, 4, 5],
[1, 2, 3, 3, 4, 5]])
只是为了让大家了解一下 all_combs
,这里还有一些 "normal" 示例 运行s -
In [166]: a = [np.array([2,3]), np.array([5,6,7])]
In [167]: all_combs(a)
Out[167]:
array([[2, 5],
[3, 5],
[2, 6],
[3, 6],
[2, 7],
[3, 7]])
In [164]: a = [np.array([2,3,4]), np.array([5,6,7,9])]
In [165]: all_combs(a)
Out[165]:
array([[2, 5],
[3, 5],
[4, 5],
[2, 6],
[3, 6],
[4, 6],
[2, 7],
[3, 7],
[4, 7],
[2, 9],
[3, 9],
[4, 9]])
性能
为了性能,我们可以避免 part-1
中的转置,并在 part-2
中沿列 (axis=0)
执行操作,还可以使用切片来避免 np.diff
,因此有一个优化版本,像这样 -
def get_minrep_combs_optimized(a): # Parte-1,2
num_combs = np.prod(list(map(len,a)))
out = np.array(np.meshgrid(*a)).reshape(-1,num_combs)
sorted_out = np.sort(out,axis=0)
counts = (sorted_out[1:] == sorted_out[:-1]).sum(0)
return out[:,counts == counts.min()].T
样本运行-
In [188]: a = [np.array([1]),np.array([2]),np.array([2,3]),np.array([3]),\
...: np.array([4]),np.array([3,4,5])]
In [189]: get_minrep_combs_optimized(a)
Out[189]:
array([[1, 2, 2, 3, 4, 5],
[1, 2, 3, 3, 4, 5]])
运行时测试
这是创建样本输入数据的一种方法,它最多有 3
个元素,每个子列表有 一些 与其他子列表中的元素匹配 -
In [42]: lens = np.random.randint(1,4,(20))
In [43]: a = [np.random.randint(1,10,L) for L in lens]
In [44]: lens
Out[44]: array([1, 1, 2, 2, 2, 2, 1, 2, 3, 2, 1, 2, 2, 3, 1, 1, 3, 2, 2, 3])
In [45]: a
Out[45]:
[array([8]),
array([8]),
array([7, 9]),
array([5, 5]),
array([6, 4]),
array([3, 1]),
array([8]),
array([1, 9]),
array([9, 5, 7]),
array([1, 1]),
array([3]),
array([1, 5]),
array([5, 5]),
array([7, 9, 2]),
array([5]),
array([1]),
array([3, 2, 9]),
array([3, 7]),
array([5, 3]),
array([2, 7, 3])]
计时 -
In [46]: %timeit leastReps(combinations(a)) #@Daniel Forsman's soln
1 loops, best of 3: 330 ms per loop
In [47]: %timeit get_minrep_combs_optimized(a)
10 loops, best of 3: 28.7 ms per loop
让我们有更多的比赛-
In [50]: a = [np.random.randint(1,4,L) for L in lens]
In [51]: %timeit leastReps(combinations(a)) #@Daniel Forsman's soln
1 loops, best of 3: 328 ms per loop
In [52]: %timeit get_minrep_combs_optimized(a)
10 loops, best of 3: 29.5 ms per loop
性能差异没有太大变化。
def combinations(arrList):
mesh=np.meshgrid(*arrList)
mesh=[arr.ravel() for arr in mesh]
return np.array(mesh).T
def leastReps(combs):
uniques=np.array([np.unique(arr).size for arr in list(combs)])
mostUni = (uniques == np.max(uniques))
return combs[mostUni]
我的和Divakar的唯一区别是我不用提前计算产品的数量,我用的uniques最多,他用的repetitions最少,应该是等价的。