一个基于另一种假设(并且十分概率论)的分析:czm233 的概率论大学习
#Prototype
东方树叶搞活动了,形如:
购买本产品,扫描瓶盖内侧二维码,即有机会赢取:
- 666 元红包(中奖率 0.00008%)
- 66 元红包(中奖率 0.005%)
- 2 元红包(中奖率 0.5%)
- 1 元红包(中奖率 1.0%)
- 0.5 元红包(中奖率 16.5%)
- 壹元换购(中奖率 25%)
按“能换购则换购”的策略,期望单价是多少?
#Problems
现在考虑一个简化版的问题:
某饮料售价为 c,有 a 的概率获得 r 元,有 b 的概率可以花 w 元复购。将进行一次购买和若干次 w 元复购记为一轮,现在研究以下问题:
-
若希望购买 N 瓶,求期望单价
-
若希望购买 M 轮,求期望单价
#Solution of 1
既然总要买满 N 瓶,那么复购的唯一意义就是降低花费,也就是等价于若购买下一瓶,则获得 (c−w) 元的补贴。故有:
E1,N(cost)E1,∞(cost)=N(N−1)(c−ar−b(c−w))+(c−ar)=c−ar−Nb(N−1)(c−w)=c−ar−b(c−w)
#Solution of 2
先考虑一轮购买。假设购得 1+k 瓶,记此事件为 Ak:
Pr(Ak)E(costk)=bk(1−b)=c+kw−1−bar
为了研究方便,为 Pr(Ak) 构造一个生成函数:
f(x)=(1−b)k=0∑∞(xb)k=1−xb1−b
现在假设有 M 轮购买,共购得 M+p 瓶,记此事件为 Bp。先研究概率,由 Pr(Ak) 构造生成函数可得:
Pr(Bp)E(Bcostp)E2,M(cost)=[xp](1−xb1−b)M=Mc+pw−1−bMar=Mu+pw(u=c−1−bar)=p=0∑∞Pr(Bp)M+pE(Bcostp)=w+M(u−w)p=0∑∞M+pPr(Bp)
然后等于我不会了。
#Solution of 2 - rework
首先换一个形式:单价 c,复购概率 p,复购价格 b,共 k 轮。
单价是拿红包价值算出来的,总之有一些方法可以转换回去。
设一共买了 n 瓶,则有:
E=(p1−p)kn=k∑∞((k−1n−1)pnnck+b(n−k))=b+(c−b)k(p1−p)k[∫01−pp1+uuk−1du]=b+(c−b)k(p1−p)k[(−1)kln(1−p)+j=1∑k−1(−1)k−1−jj1(1−pp)j]
求一下 k→∞ 时的收敛值:
E=b+(c−b)k(p1−p)k[∫01−pp1+uuk−1du]
令 x=1−pp。则 0<p<1 意味着 x>0。
我们关注积分 Ik=∫0x1+uuk−1du 在 k→∞ 时的行为。对于这类积分,可以使用拉普拉斯方法来估计其渐近行为。
对于 x>0,当 k→∞ 时,积分的贡献主要来自于 u 接近上限 x 的区域。通过分部积分法,可以得到渐近展开式:
Ik=∫0x1+uuk−1du=k(1+x)xk+O(k2xk)
这个近似在 x>0 时都成立。将 Ik 的渐近表达式代入 E 中:
E=b+(c−b)k(p1−p)k[k1(1−pp)k1+1−pp1+O(k21(1−pp)k+1)]=b+(c−b)[(p1−p)k(1−pp)k1+1−pp1+k⋅O(k21(p1−p)k(1−pp)k+1)]=b+(c−b)[1−p+k⋅O(k211−pp)]
当 k→∞ 时,余项 O(k11−pp) 趋近于 0。将简化后的项代回 E 的表达式,并取极限:
k→∞limE=b+(c−b)(1−p)=bp+c(1−p)
做完了!问 Gemini 跑个蒙特卡洛试试看,看起来还是挺对的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
| import math
def calculate_expected_price(k: int, b: float, c: float, p: float) -> float: """ 根据封闭形式的数学公式精确计算k轮购买后的平均单价期望。
Args: k (int): 购买的轮数 (必须为正整数)。 b (float): 换购价格。 c (float): 首次购买价格。 p (float): 获得换购资格的概率 (0 < p < 1)。
Returns: float: 总的平均单价的期望。 """ if not isinstance(k, int) or k < 1: raise ValueError("k 必须是正整数") if not 0 < p < 1: raise ValueError("概率 p 必须在 0 和 1 之间")
if b == c: return b
result = b
log_term = ((-1)**k) * math.log(1 - p)
sum_term = 0.0 for j in range(1, k): term = ((-1)**(k - 1 - j)) / j * math.pow(p / (1 - p), j) sum_term += term
inside_brackets = log_term + sum_term coefficient = (c - b) * k * math.pow((1 - p) / p, k)
result += coefficient * inside_brackets return result
import random
def simulate_average_price(k: int, b: float, c: float, p: float, num_simulations: int = 100000) -> float: """ 使用蒙特卡洛方法模拟计算k轮购买后的平均单价期望。
Args: k (int): 购买的轮数 (必须为正整数)。 b (float): 换购价格。 c (float): 首次购买价格。 p (float): 获得换购资格的概率 (0 < p < 1)。 num_simulations (int): 模拟实验的总次数,次数越多结果越精确。
Returns: float: 总的平均单价的近似期望。 """ if not isinstance(k, int) or k < 1: raise ValueError("k 必须是正整数") if not 0 < p < 1: raise ValueError("概率 p 必须在 0 和 1 之间")
total_of_average_prices = 0.0
for _ in range(num_simulations): total_cost_k_rounds = 0 total_bottles_k_rounds = 0
for _ in range(k): round_cost = c round_bottles = 1 while random.random() < p: round_cost += b round_bottles += 1 total_cost_k_rounds += round_cost total_bottles_k_rounds += round_bottles current_average_price = total_cost_k_rounds / total_bottles_k_rounds total_of_average_prices += current_average_price
return total_of_average_prices / num_simulations
k = 9 c = 10.0 b = 2.0 p = 0.75
exact_value = calculate_expected_price(k, b, c, p)
simulated_value = simulate_average_price(k, b, c, p, num_simulations=10000000)
print(f"Args: k={k}, c={c}, b={b}, p={p}\n") print(f"Exact Value: {exact_value:.6f}") print(f"Monte Carlo: {simulated_value:.6f}")
|