有效地填充包含许多if else语句的多维数组



我想以一种特定而有效的方式填充一个4dim numpy数组。因为我不太清楚,我开始用if else语句写代码,但这看起来不太好,可能很慢,我也不能确定我是否考虑过每一个组合。下面是我停止写的代码:

sercnew2 = numpy.zeros((gn, gn, gn, gn))
for x1 in range(gn):
    for x2 in range(gn):
        for x3 in range(gn):
            for x4 in range(gn):
                if x1 == x2 == x3 == x4: 
                    sercnew2[x1, x2, x3, x4] = ewp[x1]
                elif x1 == x2 == x3 != x4:
                    sercnew2[x1, x2, x3, x4] = ewp[x1] * ewp[x4]
                elif x1 == x2 == x4 != x3:
                    sercnew2[x1, x2, x3, x4] = ewp[x1] * ewp[x3]
                elif x1 == x3 == x4 != x2:
                    sercnew2[x1, x2, x3, x4] = ewp[x1] * ewp[x2]
                elif x2 == x3 == x4 != x1:
                    sercnew2[x1, x2, x3, x4] = ewp[x2] * ewp[x1]
                elif x1 == x2 != x3 == x4:
                    sercnew2[x1, x2, x3, x4] = ewp[x1] * ewp[x3]
                elif ... many more combinations which have to be considered

基本上应该发生的是,如果所有变量(x1 x2 x3 x4)彼此不同,条目将是:

sercnew2[x1, x2, x3, x4] = ewp[x1]* ewp[x2] * ewp[x3] * ewp[x4]

现在假设变量x2和x4是相同的那么:

sercnew2[x1, x2, x3, x4] = ewp[x1]* ewp[x2] * ewp[x3]
在上面的代码中可以看到其他示例。基本上,如果两个或多个变量相同,那么我只考虑其中一个。我希望这个模式是清晰的。否则,请让我注意,我会尽量更好地表达我的问题。我很确定,有一种更聪明的方法来做这件事。希望你知道的更好,提前谢谢:)

真希望我拿到了!这是一个矢量化的方法-

from itertools import product
n_dims = 4 # Number of dims
# Create 2D array of all possible combinations of X's as rows
idx = np.sort(np.array(list(product(np.arange(gn), repeat=n_dims))),axis=1)
# Get all X's indexed values from ewp array
vals = ewp[idx]
# Set the duplicates along each row as 1s. With the np.prod coming up next,
#these 1s would not affect the result, which is the expected pattern here.
vals[:,1:][idx[:,1:] == idx[:,:-1]] = 1
# Perform product along each row and reshape into multi-dim array
out = vals.prod(1).reshape([gn]*n_dims)

我真的不知道你说这些变量是相同的是什么意思,但如果它们确实是相同的,那么你所要做的就是使用set()

from functools import reduce
from operator import mul
sercnew2 = numpy.zeros((gn, gn, gn, gn))
for x1 in range(gn):
    for x2 in range(x1, gn):
        for x3 in range(x2, gn):
            for x4 in range(x3, gn):
                set_ = [ewp[n] for n in set([x1, x2, x3, x4])]
                sercnew2[x1, x2, x3, x4] = reduce(mul, set_, 1)

它的工作方式是它创建了一个删除重复的set(),然后使用reduce函数我从set_中选择第一个数字,将其与1(初始化值)相乘,其结果将传递给reduce作为第一个参数,第二个将是set_中的第二个项目。对不起,我解释得不好。

您也可以在单个for循环中完成。基于Divakar的索引列表技巧,我们需要做的第一件事是弄清楚如何在4d数组sercnew2中仅提取给定元素的唯一索引。

最快的方法之一(参考:https://www.peterbe.com/plog/uniqifiers-benchmark)是使用集合。然后,只需将sercnew2初始化为1数组,而不是0数组。

from itertools import product
import numpy as np
sercnew2 = np.ones((gn, gn, gn, gn))
n_dims=4
idx = list(product(np.arange(gn), repeat=n_dims))
for i,j,k,l in idx:
    unique_items = set((i,j,k,l))
    for ele in unique_items:
        sercnew2[i,j,k,l] *= ewp[ele]

编辑:正如@unutbu建议的,我们也可以使用https://stackoverflow.com/a/11146645/5714445中的cartesian_product函数来加速idx的初始化

Edit2:如果您很难理解productitertools的作用,它提供了所有的排列。例如,假设gn=2,重复维度设置为4,您得到

[0, 0, 0, 0]
[0, 0, 0, 1]
[0, 0, 1, 0]
[0, 0, 1, 1]
[0, 1, 0, 0]
[0, 1, 0, 1]
[0, 1, 1, 0]
[0, 1, 1, 1]
[1, 0, 0, 0]
[1, 0, 0, 1]
[1, 0, 1, 0]
[1, 0, 1, 1]
[1, 1, 0, 0]
[1, 1, 0, 1]
[1, 1, 1, 0]
[1, 1, 1, 1]

最新更新