如何索引笛卡尔积

时间:2016-08-04 07:16:30

标签: python

假设变量xtheta可以分别采用可能的值[0, 1, 2][0, 1, 2, 3]

我们在一个实现中说x = 1theta = 3。表示这一点的自然方式是元组(1,3)。但是,我想用一个索引标记状态(1,3)。这样做的“强力”方法是形成所有可能的有序对(x,theta)的笛卡尔积,并进行查找:

import numpy as np
import itertools

N_x = 3
N_theta = 4

np.random.seed(seed = 1)
x = np.random.choice(range(N_x))
theta = np.random.choice(range(N_theta))

def get_box(x, N_x, theta, N_theta):
    states = list(itertools.product(range(N_x),range(N_theta)))
    inds = [i for i in range(len(states)) if states[i]==(x,theta)]
    return inds[0]

print (x, theta)
box = get_box(x, N_x, theta, N_theta)
print box

这会提供(x, theta) = (1,3)box = 7,如果我们在states列表中查找它是有意义的:

[(0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2), (1, 3), (2, 0), (2, 1), (2, 2), (2, 3)]

然而,这种“蛮力”方法似乎效率低下,因为应该可以事先确定指数,而无需查找。有没有一般的方法来做到这一点? (状态N_xN_theta的数量可能会因实际应用而异,笛卡尔积可能会有更多变量。

3 个答案:

答案 0 :(得分:3)

如果您始终按字典顺序存储states,则xtheta的可能值始终是0到某个最大值的完整范围,如您的示例所示,可以使用公式

index = x * N_theta + theta

其中(x, theta)是你的元组之一。

这通过以下方式推广到更高维的元组:如果N是表示变量范围的列表或元组(因此N[0]是第一个变量的可能值的数量,等等。)和p是一个元组,您可以使用以下代码段将索引输入到按字典顺序排列的所有可能元组的列表中:

index = 0
skip = 1
for dimension in reversed(range(len(N))):
    index += skip * p[dimension]
    skip *= N[dimension]

这可能不是最恐怖的方式,但它显示了正在发生的事情:你认为你的元组是一个超立方体,你只能沿着一个维度,但如果你到达边缘,你的坐标在"下一个"尺寸增加,行程坐标重置。建议读者画一些照片。 ;)

答案 1 :(得分:1)

我认为这取决于你拥有的数据。如果它们稀疏,最好的解决方案是字典。适用于任何元组的维度。

import itertools
import random

n = 100
m = 100
l1 = [i for i in range(n)]
l2 = [i for i in range(m)]

a = {}
prod = [element for element in itertools.product(l1, l2)]
for i in prod:
    a[i] = random.randint(1, 100)

关于绩效的一个非常好的来源是this discution

答案 2 :(得分:0)

为了完整起见,我将包括我对Julian Kniephoff解决方案get_box3的实现,其中包含原始实现的稍微修改版本get_box2

# 'Brute-force' method
def get_box2(p, N):
    states = list(itertools.product(*[range(n) for n in N]))
    return states.index(p)

# 'Analytic' method
def get_box3(p, N):
    index = 0
    skip = 1
    for dimension in reversed(range(len(N))):
        index += skip * p[dimension]
        skip *= N[dimension]
    return index

p = (1,3,2)         # Tuple characterizing the total state of the system
N = [3,4,3]         # List of the number of possible values for each state variable

print "Brute-force method yields %s" % get_box2(p, N)
print "Analytical method yields %s" % get_box3(p, N)

'蛮力'和'分析'方法产生相同的结果:

Brute-force method yields 23
Analytical method yields 23

但我希望'分析'方法要快一些。我已按照Julian的建议将表示更改为pN