import numpy as np
import random
import matplotlib.pyplot as plt
# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']
# 显示减号
plt.rcParams['axes.unicode_minus'] = False
计算圆周率
经典方法
def circle(x):
return np.sqrt(1-x**2)
data_x = np.linspace(-1, 1, 10000)
data_y = circle(data_x)
plt.figure(figsize=(5, 5))
plt.plot(data_x, data_y, color='green')
plt.plot(data_x, -data_y, color='green')
plt.vlines(1, -1, 1)
plt.vlines(-1, -1, 1)
plt.hlines(1, -1, 1)
plt.hlines(-1, -1, 1)
plt.hlines(0, 0, 1)
plt.text(0.45, 0.1, 'r', fontsize=20)
plt.axis(False)
plt.show()
向正方形内随机撒点,点落在圆内的概率 p = S 圆 S 正方形 = π r 2 4 r 2 p=\frac{S_圆}{S_{正方形}}=\frac{\pi r^2}{4r^2} p=S正方形S圆=4r2πr2,即 π = 4 p \pi=4p π=4p
def pi1(n):
count_circle = 0
for _ in range(n):
x = np.random.uniform(-1, 1)
y = np.random.uniform(-1, 1)
if x**2+y**2 <= 1:
count_circle += 1
return 4*count_circle/n
plt_x = []
plt_y = []
num = 1000
for i in range(num, 21*num, num):
# 计算与π值的误差
error = (pi1(i)-np.pi)/np.pi
plt_x.append(i)
plt_y.append(error)
plt.plot(plt_x, plt_y, 'o-')
plt.hlines(0, 0, 10*num)
plt.show()
布丰投针
plt.hlines(0, 0, 1)
plt.hlines(1, 0, 1)
plt.hlines(2, 0, 1)
plt.hlines(3, 0, 1)
plt.vlines(0.8, 1, 2, colors='orange')
plt.text(0.82, 1.5, '$d$', color='orange', fontsize=20)
plt.plot([0.4, 0.7], [0.65, 1.6])
plt.vlines(0.7, 0.65, 1.6, linestyle='--')
plt.hlines(0.65, 0.4, 0.7, linestyle='--')
plt.text(0.6, 1.1, '$\Theta$', fontsize=15)
plt.text(0.5, 1.1, '${L}$', fontsize=20)
plt.text(0.72, 1.1, '${L}^{\prime}$', fontsize=20)
plt.axis(False)
plt.show()
平行线间距为d,取长度为L的针(L<d)随机投掷
将夹角 [ 0 , π ] [0,\pi] [0,π]按照 Δ θ \Delta\theta Δθ等分
针与线夹角为 θ \theta θ的概率 p 1 = Δ θ π p_1=\frac{\Delta\theta}{\pi} p1=πΔθ
针与线相交的概率 p 2 = L ′ d = L s i n θ d p_2=\frac{{L}^{\prime}}{d}=\frac{L sin\theta}{d} p2=dL′=dLsinθ
针与线以任意夹角相交的概率 p = ∑ θ = 0 π p 1 ∗ p 2 = ∫ 0 π L d π s i n θ d θ = 2 L d π {p=\sum_{\theta=0}^{\pi}{p_1*p_2}}=\int_{0}^{\pi}{\frac{L}{d\pi}sin\theta d\theta}=\frac{2L}{d\pi} p=∑θ=0πp1∗p2=∫0πdπLsinθdθ=dπ2L,即 π = 2 L p d \pi=\frac{2L}{pd} π=pd2L
有时为了计算方便,取 L = d 2 {L}=\frac{d}{2} L=2d,则 π = 1 p {\pi=\frac{1}{p}} π=p1
# 蒙特卡洛模拟布丰投针
def buffon_needle_simulation(num_trials, needle_length, line_spacing):
"""
num_trials 试验次数
needle_length 针的长度
line_spacing 平行线的间距
"""
intersect_count = 0
for _ in range(num_trials):
# 针的中点位置
needle_midpoint = np.random.uniform(0, line_spacing / 2)
# 针的倾斜角度
needle_angle = np.random.uniform(0, np.pi / 2)
# 如果针和线相交
if needle_midpoint < (needle_length / 2) * np.sin(needle_angle):
intersect_count += 1
p = intersect_count / num_trials
# return 2 * needle_length / p / line_spacing
return 1 / p
# 设置参数
needle_length = 1
line_spacing = 2
plt_x = []
plt_y = []
num = 1000
for i in range(num, 11*num, num):
estimated_pi = buffon_needle_simulation(i, needle_length, line_spacing)
error = (estimated_pi-np.pi)/np.pi
plt_x.append(i)
plt_y.append(error)
plt.plot(plt_x, plt_y, 'o-')
plt.hlines(0, 0, 10*num)
plt.show()
计算定积分
def fx_2(x):
return x**2
data_x = np.linspace(0, 1.15, 10000)
data_x_2 = fx_2(data_x)
plt.figure(figsize=(5, 5))
plt.plot(data_x, data_x_2, 'orange')
plt.text(0.5, 0.5, '$y=x^2$')
plt.hlines(0, 0, 1, colors='green')
plt.hlines(1, 0, 1, colors='green')
plt.vlines(1, 0, 1, colors='green')
plt.vlines(0, 0, 1, colors='green')
for i in np.arange(0.2, 1, 0.05):
plt.vlines(i, 0, fx_2(i), linestyles='--')
plt.show()
定积分 S 阴影 = ∫ 0 1 x 2 d x = 1 3 S_{阴影}=\int_{0}^{1}{x^2}dx=\frac{1}{3} S阴影=∫01x2dx=31
向绿色矩形内随机撒点,点在阴影部分的概率为 p = S 阴影 S 矩形 p=\frac{S_{阴影}}{S_{矩形}} p=S矩形S阴影
def f2(x):
count = 0
for _ in range(x):
random_x = np.random.uniform(0, 1)
random_y = np.random.uniform(0, 1)
if random_y <= fx_2(random_x):
count += 1
return count/x
plt_x = []
plt_y = []
num = 1000
for i in range(num, 11*num, num):
res = f2(i)
# 计算误差
error = 3*res-1
plt_x.append(i)
plt_y.append(error)
# 随着次数上升,误差的大小
plt.plot(plt_x, plt_y, 'o-')
plt.hlines(0, 0, 10*num)
plt.show()
模拟游戏
- 前置条件,基本资金10000,当资金小于500时,认为失败。
- 目标,赚更多钱。
等份策略
每次拿出一定额度(比如100)进行游戏,50%的概率赢100,50%的概率输100
funds = 10000
res_lis = []
for i in range(1, 10000):
random_res = np.random.choice(['win', 'lose'])
if random_res == 'win':
funds += 100
else:
funds -= 100
res_lis.append(funds)
plt.plot(range(1, 10000), res_lis)
plt.hlines(500, 0, 10000)
plt.show()
理论上fund会在10000上下徘徊,模拟过程中,也可能会出现赔本的情况。
对半策略
每次拿出全部本金的一半,50%的概率输一半或赢一半
过程类型指数级变化,相较于等份策略,收敛速度会明显加快。
funds = 10000
res_lis = [10000]
for i in range(1, 10000):
random_res = np.random.choice(['win', 'lose'])
chips = funds/2
if random_res == 'win':
funds += chips
else:
funds -= chips
res_lis.append(funds)
if funds < 500:
break
plt.plot(res_lis)
# plt.hlines(500, 0, 10000)
plt.show()
凯利公式
凯莉公式的核心思想是,如果知道每次下注获胜的概率以及赢得的比例,可以通过公式计算出应该下注的资金比例,以使长期来看最大化投资或赌博的收益。
f
∗
=
b
p
−
q
b
f^*=\frac{bp-q}{b}
f∗=bbp−q
- f ∗ f^* f∗ 表示应该投入的资金的比例。
- b 表示每笔投注的可能净收益(赔率)。
- p 表示投注成功的概率。
- q 表示投注失败的概率。
假设赔率为b,输了失去下注数,赢了获得b倍(包括下注数)
def f4(b, x=10000):
f = (b*0.5-0.5)/b
funds = 10000 # 基本资金
game_count = 0 # 游戏次数
funds_list = [funds] # 保存每次游戏后的资金
for i in range(x):
chips = funds*f
random_res = np.random.choice(['win', 'lose'])
if random_res == 'win':
funds += chips*(b-1)
else:
funds -= chips
game_count += 1
funds_list.append(funds)
if funds < 500:
break
return game_count, funds_list
# 赔率为2进行测试
game_count, funds_list = f4(2)
plt.plot(funds_list)
plt.show()
赔率高于1时,也有输光(<500)的风险。
当输赢收益一样时,最佳 f ∗ f^* f∗为0,即不赌。
题外话:参考电影《消失的她》,第一次下注t元,进行n次,无论上一次的输赢,后续每一次下注数总为上一次的两倍。进行n次后,理论上无论前面输赢情况,只需最后一次(第n次)是赢,根据等比数列求和公式,前n-1项的和总小于第n项,即使前n-1次全输,此时收益也为正。虽然这种方式可以做到理论最优(保证最后一次为赢的情况下,总收益呈指数型上升),但是每次下注的本金是在成倍增长,在实际中本金额度会过大,带来风险。即使可以做到理论最优的方式,现实总也存在操盘等行为,所以说,珍爱生命,原理赌博。
随机游走
醉汉问题
在十字路口中心,有一个醉汉会向四个方向随机移动,在移动足够长的步数后,是否会返回原点?(离原点的距离)
def f5(num):
x = 0
y = 0
x_left = 0
x_right = 0
y_upper = 0
y_lower = 0
x_list = [0]
y_list = [0]
for _ in range(num):
op = np.random.choice(['left', 'right', 'upper', 'lower'])
if op == 'left':
x_left += 1
x -= 1
elif op == 'right':
x_right += 1
x += 1
elif op == 'upper':
y_upper += 1
y += 1
elif op == 'lower':
y_lower += 1
y -= 1
x_list.append(x)
y_list.append(y)
return x_list, y_list, x_left, x_right, y_upper, y_lower
x_list,y_list,x_left,x_right,y_upper,y_lower = f5(100)
plt.plot(x_list,y_list,'o-')
plt.show()
x_left,x_right,y_upper,y_lower
(29, 25, 23, 23)
随机游走中醉汉问题是一个经典的数学问题,描述了一个醉汉在二维空间中随机移动的情况。这个问题的启示包括:
- 随机性的重要性: 醉汉问题突显了随机性在某些情况下的重要性。尽管醉汉在每一步都做出随机决策,但最终却可能会收敛到一个确定的分布。这说明了在某些系统中,即使存在随机性,也可能会出现一定的稳定性或可预测性。
- 扩展到其他领域: 醉汉问题的概念不仅仅局限于数学领域,还可以应用于其他领域,如物理学、计算机科学和金融学等。在物理学中,它可以用来模拟分子在液体中的随机运动;在计算机科学中,可以用来设计随机算法;在金融学中,可以用来模拟资产价格的随机波动。
- 随机过程的理解: 醉汉问题是理解随机过程的一个很好的例子。通过研究醉汉在空间中的随机移动,可以深入了解随机过程的特性、收敛性以及与概率分布相关的概念。
- 决策和结果的分离: 尽管醉汉在每一步都做出随机决策,但最终结果却受到其初始位置和随机决策序列的影响。这表明有时决策和结果之间存在一定程度的分离,即好的决策并不总是能够带来好的结果,反之亦然。
概率
- 虽然目标结果可以预测,但现实总有考虑不到的情况,预测与事实存在偏差很正常。
- 不可能事件的发生概率为0,但概率为0的事件不一定是不可能事件。
- 在概率模型中,总是将概率最高的那一个作为预测结果。
- 有时所有可能的结果概率值都很小,说明每个可能结果的概率值较为接近,此时可以拒绝回答(预测),这个在一些模型上也有应用。(想一想逻辑回归对概率进行二值化的时候,为什么要选择Sigmod函数)