gpt4 book ai didi

python - 高效算法而不是循环

转载 作者:太空狗 更新时间:2023-10-29 20:42:29 25 4
gpt4 key购买 nike

我有一个数据集,其中每个样本的结构都与此类似

X=[ [[],[],[],[]], [[],[]] , [[],[],[]] ,[[][]]]

例如:

X=np.array([ [ [1,2,3], [2,4,5] ,[2,3,4] ] , [ [5,6], [6,6] ] , [[2,3,1],[2,3,10],[23,1,2],[1,4,5]]  ] ,"object")

Y=np.array([ [ [12,14,15] ,[12,13,14] ] , [ [15,16], [16,16] ] , [[22,23,21],[32,33,11],[12,44,55]] ] ,"object")

因此对于每个样本,我需要计算 x 的每个元素与具有相同索引的 y 的相应元素之间的点积,并对结果求和。即:

result=0

for i in range(3):
for n,m in itertools.product(X[i],Y[i]):
print "%s, %s" % (n,m)
result+=np.dot(n,m)

.....:
[1, 2, 3], [12, 14, 15]
[1, 2, 3], [12, 13, 14]
[2, 4, 5], [12, 14, 15]
[2, 4, 5], [12, 13, 14]
[2, 3, 4], [12, 14, 15]
[2, 3, 4], [12, 13, 14]
[5, 6], [15, 16]
[5, 6], [16, 16]
[6, 6], [15, 16]
[6, 6], [16, 16]
[2, 3, 1], [22, 23, 21]
[2, 3, 1], [32, 33, 11]
[2, 3, 1], [12, 44, 55]
[2, 3, 10], [22, 23, 21]
[2, 3, 10], [32, 33, 11]
[2, 3, 10], [12, 44, 55]
[23, 1, 2], [22, 23, 21]
[23, 1, 2], [32, 33, 11]
[23, 1, 2], [12, 44, 55]
[1, 4, 5], [22, 23, 21]
[1, 4, 5], [32, 33, 11]
[1, 4, 5], [12, 44, 55]

这是我的全部代码:

 print "***build kernel***"
K = np.zeros((n_samples, n_samples))
for i in range(n_samples):
for j in range(n_samples):

K[i,j] = self.kernel(X[i], X[j])

def kernel(x1,x2):
N=8 #number of objects
result=0
for i in xrange(N):
for n,m in itertools.product(x1[i],x2[i]):
result+=np.dot(n,m)
return result

如您所见,该算法的复杂度太高,而且我的样本比这大得多。所以即使是一个小数据集,即包含 400 个样本,我也必须等待 4 个小时才能得到结果。我正在寻找一种更好的方法来实现这个算法。P.S:我在考虑多线程或多进程,但我不确定它是否有帮助?!

我很感激任何建议!

最佳答案

而不是求和每对的点积,这需要 n * m操作,您可以对每个列表中的所有向量求和,然后只做最终的点积,这只需要 n + m操作。

之前:

def calc_slow(L1, L2):
result = 0
for n, m in itertools.product(L1, L2):
result += np.dot(n, m)
return result

之后:

def calc_fast(L1, L2):
L1_sums = np.zeros(len(L1[0]))
L2_sums = np.zeros(len(L2[0]))
for vec in L1:
L1_sums += vec
for vec in L2:
L2_sums += vec
return np.dot(L1_sums, L2_sums)

编辑:更快的版本,利用 numpy:

def calc_superfast(L1, L2):
return np.dot(np.array(L1).sum(0),
np.array(L2).sum(0))

输出是一样的:

print X[0], Y[0], calc_slow(X[0], Y[0])
print X[0], Y[0], calc_fast(X[0], Y[0])

打印:

[[1, 2, 3], [2, 4, 5], [2, 3, 4]] [[12, 14, 15], [12, 13, 14]] 711
[[1, 2, 3], [2, 4, 5], [2, 3, 4]] [[12, 14, 15], [12, 13, 14]] 711.0

Timing 它表明有显着的改进。时序代码:

import random
import time
def rand_vector(size=3):
return [random.randint(1, 100) for _ in xrange(3)]
def rand_list(length=200):
return [rand_vector() for _ in xrange(length)]

print "Generating lists..."
L1 = rand_list(200)
L2 = rand_list(200)

print "Running slow..."
s = time.time()
print calc_slow(L1, L2)
print "Slow for (%d, %d) took %.2fs" % (len(L1), len(L2), time.time() - s)

print "Running fast..."
s = time.time()
print calc_fast(L1, L2)
print "Fast for (%d, %d) took %.2fs" % (len(L1), len(L2), time.time() - s)

示例输出:

Generating lists...
Running slow...
75715569
Slow for (100, 100) took 1.48s
Running fast...
75715569.0
Fast for (100, 100) took 0.03s

Generating lists...
Running slow...
309169971
Slow for (200, 200) took 5.29s
Running fast...
309169971.0
Fast for (200, 200) took 0.04s

Running fast...
3.05185703539e+12
Fast for (20000, 20000) took 1.94s

两个包含 20000 个元素的列表的操作每个只需要大约 2 秒,而我预计使用旧方法需要几个小时。


这样做的原因是您可以将操作组合在一起。假设您有以下列表:

L1 = [a, b, c], [d, e, f], [g, h, i] 
L2 = [u, v, w], [x, y, z]

然后将每对的点积相加如下所示:

a*u + b*v + c*w + a*x + b*y + c*z +
d*u + e*v + f*w + d*x + e*y + f*z +
g*u + h*v + i*w + g*x + h*y + i*z

您可以分解出 u , v , w , x , y , 和 z元素:

u*(a + d + g) + v*(b + e + h) + w*(c + f + i) +
x*(a + d + g) + y*(b + e + h) + z*(c + f + i)

然后您可以进一步分解这些总和:

(u + x)*(a + d + g) + (v + y)*(b + e + h) + (w + z)*(c + f + i)

这只是每个初始列表中向量求和的点积。

关于python - 高效算法而不是循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15479777/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com