假设变量x
和theta
可以分别采用可能的值[0, 1, 2]
和[0, 1, 2, 3]
。
我们在一个实现中说x = 1
和theta = 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_x
和N_theta
的数量可能会因实际应用而异,笛卡尔积可能会有更多变量。
答案 0 :(得分:3)
如果您始终按字典顺序存储states
,则x
和theta
的可能值始终是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的建议将表示更改为p
和N
。