如何获得列表的加权平均值,其权重受 Python 3.6 中的变量限制
How to get a weighted average of a list of which it's weights is limited by a variable in Python 3.6
我希望标题有意义。我想要实现的是获得鞋子的加权平均价格,这些鞋子的价格不同,数量也不同。所以我有例如:
list_prices = [12,12.7,13.5,14.3]
list_amounts = [85,100,30,54]
BuyAmount = x
我想知道我的加权平均价,以及每只鞋我支付的最高价如果我买了 x 数量的鞋(假设我想先买最便宜的)
这是我现在拥有的(我使用 numpy):
if list_amounts[0] >= BuyAmount:
avgprice = list_prices[0]
highprice = list_prices[0]
elif (sum(list_amounts[0: 2])) >= BuyAmount:
avgprice = np.average(list_prices[0: 2], weights=[list_amounts[0],BuyAmount - list_amounts[0]])
highprice = list_prices[1]
elif (sum(list_amounts[0: 3])) >= BuyAmount:
avgprice = np.average(list_prices[0: 3], weights=[list_amounts[0],list_amounts[1],BuyAmount - (sum(list_amounts[0: 2]))])
highprice = list_prices[2]
elif (sum(list_amounts[0: 4])) >= BuyAmount:
avgprice = np.average(list_prices[0: 4], weights=[list_amounts[0],list_amounts[1],list_amounts[2],BuyAmount - (sum(list_amounts[0: 3]))])
highprice = list_prices[3]
print(avgprice)
print(highprice)
此代码有效,但可能过于复杂和庞大。特别是因为我希望能够处理包含 20 多个项目的数量和价目表。
执行此操作的更好方法是什么?
这是一个通用的矢量化解决方案,使用 cumsum
替换那些切片求和,并使用 argmax
获取适当的索引以用于设置那些 IF-case
操作的切片限制 -
# Use cumsum to replace sliced summations - Basically all those
# `list_amounts[0]`, `sum(list_amounts[0: 2]))`, `sum(list_amounts[0: 3])`, etc.
c = np.cumsum(list_amounts)
# Use argmax to decide the slicing limits for the intended slicing operations.
# So, this would replace the last number in the slices -
# list_prices[0: 2], list_prices[0: 3], etc.
idx = (c >= BuyAmount).argmax()
# Use the slicing limit to get the slice off list_prices needed as the first
# input to numpy.average
l = list_prices[:idx+1]
# This step gets us the weights. Now, in the weights we have two parts. E.g.
# for the third-IF we have :
# [list_amounts[0],list_amounts[1],BuyAmount - (sum(list_amounts[0: 2]))]
# Here, we would slice off list_amounts limited by `idx`.
# The second part is sliced summation limited by `idx` again.
w = np.r_[list_amounts[:idx], BuyAmount - c[idx-1]]
# Finally, plug-in the two inputs to np.average and get avgprice output.
avgprice = np.average(l,weights=w)
# Get idx element off list_prices as the highprice output.
highprice = list_prices[idx]
我们可以进一步优化以删除连接步骤(使用 np.r_
)并达到 avgprice
,就像这样 -
slice1_sum = np.multiply(list_prices[:idx], list_amounts[:idx]).sum()
# or np.dot(list_prices[:idx], list_amounts[:idx])
slice2_sum = list_prices[idx]*(BuyAmount - c[idx-1])
weight_sum = np.sum(list_amounts[:idx]) + BuyAmount - c[idx-1]
avgprice = (slice1_sum+slice2_sum)/weight_sum
你说的没错,你的代码缺乏灵活性。但是在我看来,你是从正确的角度来看问题的,但还不够笼统。
换句话说,您的解决方案实现了这个想法:"let me check first - given the quantities available for each price (which I sorted beautifully in an array) - what are the different sellers I have to buy from, then do all the computation."
更灵活的想法可以是:"Let me start buying the from cheaper available, as much as I can. I will stop when my order is fulfilled, and compute the math step by step"。这意味着您构建一个迭代代码,逐步累积总花费金额,并在完成后计算每件的平均价格和最高价格(即您订购列表中最后访问的价格)。
将此想法转化为代码:
list_prices = [12,12.7,13.5,14.3]
list_amounts = [85,100,30,54]
BuyAmount = x
remaining = BuyAmount
spent_total = 0
current_seller = -1 # since we increment it right away
while(remaining): # inherently means remaining > 0
current_seller += 1
# in case we cannot fulfill the order
if current_seller >= len(list_prices):
# since we need it later we have to restore the value
current_seller -= 1
break
# we want either as many as available or just enough to complete
# BuyAmount
buying = min([list_amounts[current_seller], remaining])
# update remaining
remaining -= buying
# update total
spent_total += buying * list_prices[current_seller]
# if we got here we have no more remaining or no more stock to buy
# average price
avgprice = spent_total / (BuyAmount - remaining)
# max price - since the list is ordered -
highprice = list_prices[current_seller]
print(avgprice)
print(highprice)
我希望标题有意义。我想要实现的是获得鞋子的加权平均价格,这些鞋子的价格不同,数量也不同。所以我有例如:
list_prices = [12,12.7,13.5,14.3]
list_amounts = [85,100,30,54]
BuyAmount = x
我想知道我的加权平均价,以及每只鞋我支付的最高价如果我买了 x 数量的鞋(假设我想先买最便宜的)
这是我现在拥有的(我使用 numpy):
if list_amounts[0] >= BuyAmount:
avgprice = list_prices[0]
highprice = list_prices[0]
elif (sum(list_amounts[0: 2])) >= BuyAmount:
avgprice = np.average(list_prices[0: 2], weights=[list_amounts[0],BuyAmount - list_amounts[0]])
highprice = list_prices[1]
elif (sum(list_amounts[0: 3])) >= BuyAmount:
avgprice = np.average(list_prices[0: 3], weights=[list_amounts[0],list_amounts[1],BuyAmount - (sum(list_amounts[0: 2]))])
highprice = list_prices[2]
elif (sum(list_amounts[0: 4])) >= BuyAmount:
avgprice = np.average(list_prices[0: 4], weights=[list_amounts[0],list_amounts[1],list_amounts[2],BuyAmount - (sum(list_amounts[0: 3]))])
highprice = list_prices[3]
print(avgprice)
print(highprice)
此代码有效,但可能过于复杂和庞大。特别是因为我希望能够处理包含 20 多个项目的数量和价目表。
执行此操作的更好方法是什么?
这是一个通用的矢量化解决方案,使用 cumsum
替换那些切片求和,并使用 argmax
获取适当的索引以用于设置那些 IF-case
操作的切片限制 -
# Use cumsum to replace sliced summations - Basically all those
# `list_amounts[0]`, `sum(list_amounts[0: 2]))`, `sum(list_amounts[0: 3])`, etc.
c = np.cumsum(list_amounts)
# Use argmax to decide the slicing limits for the intended slicing operations.
# So, this would replace the last number in the slices -
# list_prices[0: 2], list_prices[0: 3], etc.
idx = (c >= BuyAmount).argmax()
# Use the slicing limit to get the slice off list_prices needed as the first
# input to numpy.average
l = list_prices[:idx+1]
# This step gets us the weights. Now, in the weights we have two parts. E.g.
# for the third-IF we have :
# [list_amounts[0],list_amounts[1],BuyAmount - (sum(list_amounts[0: 2]))]
# Here, we would slice off list_amounts limited by `idx`.
# The second part is sliced summation limited by `idx` again.
w = np.r_[list_amounts[:idx], BuyAmount - c[idx-1]]
# Finally, plug-in the two inputs to np.average and get avgprice output.
avgprice = np.average(l,weights=w)
# Get idx element off list_prices as the highprice output.
highprice = list_prices[idx]
我们可以进一步优化以删除连接步骤(使用 np.r_
)并达到 avgprice
,就像这样 -
slice1_sum = np.multiply(list_prices[:idx], list_amounts[:idx]).sum()
# or np.dot(list_prices[:idx], list_amounts[:idx])
slice2_sum = list_prices[idx]*(BuyAmount - c[idx-1])
weight_sum = np.sum(list_amounts[:idx]) + BuyAmount - c[idx-1]
avgprice = (slice1_sum+slice2_sum)/weight_sum
你说的没错,你的代码缺乏灵活性。但是在我看来,你是从正确的角度来看问题的,但还不够笼统。
换句话说,您的解决方案实现了这个想法:"let me check first - given the quantities available for each price (which I sorted beautifully in an array) - what are the different sellers I have to buy from, then do all the computation."
更灵活的想法可以是:"Let me start buying the from cheaper available, as much as I can. I will stop when my order is fulfilled, and compute the math step by step"。这意味着您构建一个迭代代码,逐步累积总花费金额,并在完成后计算每件的平均价格和最高价格(即您订购列表中最后访问的价格)。
将此想法转化为代码:
list_prices = [12,12.7,13.5,14.3]
list_amounts = [85,100,30,54]
BuyAmount = x
remaining = BuyAmount
spent_total = 0
current_seller = -1 # since we increment it right away
while(remaining): # inherently means remaining > 0
current_seller += 1
# in case we cannot fulfill the order
if current_seller >= len(list_prices):
# since we need it later we have to restore the value
current_seller -= 1
break
# we want either as many as available or just enough to complete
# BuyAmount
buying = min([list_amounts[current_seller], remaining])
# update remaining
remaining -= buying
# update total
spent_total += buying * list_prices[current_seller]
# if we got here we have no more remaining or no more stock to buy
# average price
avgprice = spent_total / (BuyAmount - remaining)
# max price - since the list is ordered -
highprice = list_prices[current_seller]
print(avgprice)
print(highprice)