【问题标题】:Combinatorics: list with alternative elements组合学:带有替代元素的列表
【发布时间】:2017-03-02 12:53:55
【问题描述】:

我有一个 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 数据帧。

【问题讨论】:

  • 为什么这个问题被否决了?请详细说明,以便我改进。
  • @Divakar:我用过你的。

标签: python numpy combinatorics


【解决方案1】:

这是一个基于 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,这里有一些更“正常”的示例案例运行 -

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 中的转置,沿(axis=0) 列执行part-2 中的操作,还可以使用切片来避免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

性能差异变化不大。

【讨论】:

  • 这比我在我的机器上获得的性能差异要大得多,但你的机器似乎仍然更快(一如既往:()。
  • @DanielForsman 我猜如果有来自不同系统的计时会很好。您也可以随意发布您的时间以及设置。
  • 不,我的测试样本更小,我认为我的性能影响来自 listwise ravel(),它只会随着样本变大而变大。不确定找到最少的重复或最多的唯一性是否更有效。
  • @DanielForsman 根据我的测试,您的第 1 部分还可以,但我猜第二部分循环和寻找独特的部分并不是最好的选择。
  • 令人惊讶,因为您有 sort 的开销,但似乎确实如此。
【解决方案2】:

您可以像这样使用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)

这会返回:

[[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 部分不可解,因为可能存在非唯一解...

【讨论】:

    【解决方案3】:
    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的唯一区别是我不需要预先计算产品的数量,我使用最多的唯一性,他使用最少的重复,应该是等价的。

    【讨论】:

    • “最独特”和“最少重复”是什么意思?哪个效率更高?
    猜你喜欢
    • 2019-05-19
    • 1970-01-01
    • 1970-01-01
    • 2016-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-24
    • 1970-01-01
    相关资源
    最近更新 更多