是否有更快的方法在Python中编写“compute_optimal_weights”函数。我运行了数亿次,所以任何速度增加都会有所帮助。每次运行时,函数的参数都不同。
c1 = 0.25
c2 = 0.67
def compute_optimal_weights(input_prices):
input_weights_optimal = {}
for i in input_prices:
price = input_prices[i]
input_weights_optimal[i] = c2 / sum([(price/n) ** c1 for n in input_prices.values()])
return input_weights_optimal
input_sellers_ID = range(10)
input_prices = {}
for i in input_sellers_ID:
input_prices[i] = random.uniform(0,1)
t0 = time.time()
for i in xrange(1000000):
compute_optimal_weights(input_prices)
t1 = time.time()
print "old time", (t1 - t0)
列表和字典中的元素数量各不相同,但平均而言大约有10个元素。 input_prices中的键在所有调用中都是相同的,但值会更改,因此相同的键在不同的运行中将具有不同的值。
答案 0 :(得分:1)
我相信我们可以通过分解循环来加速这个功能。如果我的数学没有错误,请a = price
,b = n
和c = c1
(例如(5/6)**3 == 5**3 / 6**3
:
(5./6.)**2 + (5./4.)**2
==
5**2 / 6.**2 + 5**2 / 4.**2
==
5**2 * (1/6.**2 + 1/4.**2)
使用变量:
sum( (a / b) ** c for each b)
==
sum( a**c * (1/b) ** c for each b)
==
a**c * sum((1./b)**c for each b)
第二个词是不变的,可以取出。离开了:
使用生成器和字典理解:
def compute_optimal_weights(input_prices):
sconst = sum(1/w**c1 for w in input_prices.values())
return {k: c2 / (v**c1 * sconst) for k, v in input_prices.items()}
注意:如果您使用Python2,请将.values()
和.items()
替换为.itervalues()
和.iteritems()
以获得额外的加速(使用大型列表时只需几毫秒)。
此外,如果您不太关心字典并只想要这些值,您可以使用numpy加速它(对于大输入>100
):
def compute_optimal_weights_np(input_prices):
data = np.asarray(input_prices.values()) ** c1
return c2 / (data * np.sum(1./data))
不同输入大小的时间很少:
N = 10
输入:
MINE: 100000 loops, best of 3: 6.02 µs per loop
NUMPY: 100000 loops, best of 3: 10.6 µs per loop
YOURS: 10000 loops, best of 3: 23.8 µs per loop
N = 100
输入:
MINE: 10000 loops, best of 3: 49.1 µs per loop
NUMPY: 10000 loops, best of 3: 22.6 µs per loop
YOURS: 1000 loops, best of 3: 1.86 ms per loop
N = 1000
输入:
MINE: 1000 loops, best of 3: 458 µs per loop
NUMPY: 10000 loops, best of 3: 121 µs per loop
YOURS: 10 loops, best of 3: 173 ms per loop
N = 100000
输入:
MINE: 10 loops, best of 3: 54.2 ms per loop
NUMPY: 100 loops, best of 3: 11.1 ms per loop
YOURS: didn't finish in a couple of minutes
这里的两个选项都比问题中提出的选项快得多。如果你可以提供一致的输入(以数组而不是字典的形式),使用numpy
的好处在大小增加时变得明显:
答案 1 :(得分:1)
使用一点数学运算,您可以在循环早期计算部分sum_price_ratio_scaled
作为常数,并将程序加速 ~80%(对于平均输入大小) 10)。
<小时/>
def compute_optimal_weights(ids, prices):
scaled_sum = 0
for i in ids:
scaled_sum += prices[i] ** -0.25
result = {}
for i in ids:
result[i] = 0.67 * (prices[i] ** -0.25) / scaled_sum
return result
编辑,以响应this answer:虽然使用numpy
将会证明对大量数据集更有效,但鉴于“平均有大约10个元素“在您的input_sellers_ID
列表中,我怀疑这种方法对您的特定应用程序来说是值得的。
虽然利用生成器表达式和字典理解的简洁性可能很诱人,但我注意到在我的机器上运行时,通过使用常规for-in
循环并避免像{{1}这样的函数调用来获得最佳性能。 }。但是,为了完整起见,以上实现的内容将更加“pythonic”:
sum(...)
<小时/>
根据您发布的算法,您尝试使用下面的函数def compute_optimal_weights(ids, prices):
scaled_sum = sum(prices[i] ** -0.25 for i in ids)
return {i: 0.67 * (prices[i] ** -0.25) / scaled_sum for i in ids}
创建一个字典,其中f(i)
是i
列表中的元素之一。< / p>
当您最初写出input_sellers_ID
的公式时,似乎必须为求和过程的每一步重新计算f(i)
,这是昂贵的。但是,使用指数规则简化表达式,您可以看到确定prices[i]
所需的最简单求和实际上是f(i)
的独立(仅i
的索引值曾经使用过1}},这意味着该术语是一个常量,可以在设置字典值的循环之外计算。
请注意,上面我将j
称为input_prices
,将prices
称为input_sellers_ID
。
ids