import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import random
import itertools
排列组合计算 n是元素的总个数,m是参数排列组合的个数,!是阶乘
阶乘算法
n
!
=
1
×
2
×
3
×
.
.
.
×
(
n
−
1
)
×
n
n!=1×2×3×...×(n-1)×n
n!=1×2×3×...×(n−1)×n。阶乘亦可以递归方式定义:
0
!
=
1
,
n
!
=
(
n
−
1
)
!
×
n
0!=1,n!=(n-1)!×n
0!=1,n!=(n−1)!×n
def factorial(N):
n = 1
for i in range(1,N+1):
n *= i
return n
排列公式 A ( n , k ) = n ( n − 1 ) . . . . ( n − k + 1 ) = n ! / ( n − k ) ! A(n,k)=n(n-1)....(n-k+1)=n!/(n-k)! A(n,k)=n(n−1)....(n−k+1)=n!/(n−k)!
def Ank(n,k):
return factorial(n)/factorial(n-k)
组合公式 C ( n , k ) = A ( n , k ) / k ! = n ! / k ! ( n − k ) ! = C n n − k C(n,k) ={A(n,k)/k!} = n!/k!(n-k)! = C_n^{n-k} C(n,k)=A(n,k)/k!=n!/k!(n−k)!=Cnn−k
def Cnk(n,k):
return factorial(n)/(factorial(k)*factorial(n-k))
调用标准库的itertoolst函数给出排列组合选项
example1 = ['a','b','c']
product 笛卡尔积 (有放回抽样排列)
list(itertools.product(example1,repeat=2))
permutations 排列 (不放回抽样排列)
list(itertools.permutations(example1,2))
combinations 组合,没有重复 (不放回抽样组合)
list(itertools.combinations(example1, 2))
combinations_with_replacement 组合,有重复 (有放回抽样组合)
list(itertools.combinations_with_replacement(example1, 2))
概率分布计算
P
(
X
=
k
)
=
C
(
n
,
k
)
∗
(
P
k
)
∗
[
(
1
−
p
)
(
n
−
k
)
]
P(X=k) = C(n,k)*(P^{k})*[(1-p)^{(n-k)}]
P(X=k)=C(n,k)∗(Pk)∗[(1−p)(n−k)]
n
是
全
不
的
组
合
元
素
数
,
X
=
k
是
选
择
的
组
合
长
度
,
P
是
事
件
单
独
发
生
的
概
率
n是全不的组合元素数,X=k是选择的组合长度,P是事件单独发生的概率
n是全不的组合元素数,X=k是选择的组合长度,P是事件单独发生的概率
伯努利分布:
def bernoulliDistribution(n,X,P):
k = X
return Cnk(n,k)*(P**k)*((1-P)**(n-k))
验证函数
概率分布计算
通过 n 和 p,我们可以计算出 X 取 0~n 中任何整数值 k 的概率:
例子 : 连续 10 次投硬币,正面朝上的次数 X=5 的概率:
P
(
X
=
5
)
=
C
(
10
,
5
)
∗
(
0.
5
5
)
[
(
1
−
0.5
)
10
−
5
]
P(X=5) = C(10, 5)*(0.5^{5})[(1-0.5)^{10-5}]
P(X=5)=C(10,5)∗(0.55)[(1−0.5)10−5]
=
252
∗
(
0.
5
1
0
)
0.246
= 252 * (0.5^10) ~ 0.246
=252∗(0.510) 0.246
(
大
约
1
/
4
)
(大约 1/4)
(大约1/4)
bernoulliDistribution(n=10,X=5,P=0.5)
需要多少次才能成功呢?
def Ep(n,k,P):
return 1/bernoulliDistribution(n,k,P)
Ep(n=10,k=5,P=0.5)
观察一下,当成功概率变动时候,发生了什么
data = np.array([[i/100,Ep(int(100*(i/100)),int(100*(i/100)),i/100),5] for i in range(1,100)])
plt.plot(data[:,1:2])
【期望和方差】
二项分布的期望(均值)为 np,方差为 np(1-p)。(推导过程不难,不会也可以问问搜索引擎)
二项分布告诉我们:想要“期望 ”大,那就提升 n 和 p。
(限制了 p,就想法扩大 n)
- 而如果客观条件约束了胜算,只要“期望”收益为正,那就追求多次可重复。
例如,赌场,保险公司,风险投资……(这里与上一篇的信息熵对应)
大量可重复,概率的规律才有意义。
因为少量的“试验”次数,难以支撑那一点微小的概率优势;只有不断扩大 n,“运气”才会收敛到“期望”。
(限制了 n,就努力提升 p)
- 对难得的机会,最好事前充分地准备,提升成功概率,降低不确定性。
柏松分布
柏松部分是一种特殊的伯努利分布,公式是
P
(
X
=
k
)
=
e
λ
λ
k
/
k
!
P( X = k ) = e^{\lambda}\lambda^{k}/k!
P(X=k)=eλλk/k!
n
是
实
验
的
次
数
,
p
是
实
验
出
现
情
况
可
能
性
的
乘
积
,
λ
是
n
∗
p
的
乘
积
n是实验的次数,p是实验出现情况可能性的乘积,\lambda是n*p的乘积
n是实验的次数,p是实验出现情况可能性的乘积,λ是n∗p的乘积
例子:
每天早上有一个同事小美会给大家带10份早饭,先到先得,每个员工8点以前能到公司的概率是10%。
公司员工100人,每个人每天到达公司的时间是随机的,且无相关性,不存在商量的情况
新来的员工小曹,能够吃上早饭的概率是多少?
总人数是100
n = 100 n = 100 n=100
八点以前到公司的概率是10%
p = 0.1 p = 0.1 p=0.1
λ = n ∗ p 所 以 : \lambda = n*p 所以: λ=n∗p所以:
λ = 100 ∗ 0.1 = 10 \lambda = 100*0.1 = 10 λ=100∗0.1=10
小美只带10份早饭,所以k的集合是={0,1,2…9},也就是已经被领取的早饭数量的顺序值
( X = k ) : (X = k) : (X=k):
柏松分布的函数
def pocssonDistribution(n,k,p):
Lambda = n*p
probability = np.array([(np.exp(-Lambda)*Lambda**ki)/np.math.factorial(ki) for ki in range(k+1)])
cumulativeProbability = np.array([np.dot(probability[:i],np.ones(i)) for i in range(1,len(probability)+1)])
return probability[:-1],cumulativeProbability[:-1],Lambda
柏松分布概率表
def pocssonDistribution_to_table(n,k,p):
probability,cumulativeProbability,Lambda = pocssonDistribution(n,k,p)
return pd.DataFrame({'k':range(1,len(probability)+1),'Lambda':Lambda,'单次概率':probability,'累计概率':cumulativeProbability})
测试函数
Ptable = pocssonDistribution_to_table(100,20,0.1)
Ptable.head()
如
果
k
超
过
λ
,
则
概
率
开
始
朝
下
走
如果k超过\lambda,则概率开始朝下走
如果k超过λ,则概率开始朝下走
这也符合正常的直觉,当需要早餐的人越来越多时,8点能够拿到早餐的概率就会降低
解读上面的表:
k代表累计已经被领取的早餐:
可以看到,无论是累计还是单次的概率,都随着k值增加,也就是说,8点整点领取第几份早餐的相应概率也在增加
plt.plot(probability,c='r')
plt.plot(cumulativeProbability,c='g')
通过计算得到,如果在整点8到达,能吃到小美的饭的概率就是45.7%
如果公司员工人数发生变动呢?比如减少60人,可能性依然是10%
可以看到,当n和k增大时,概率不变,则n越大,能够吃到的早餐的可能性越大,但是百分之50%是一个上限,继续增加人数,效率并不高
table = pocssonDistribution_to_table(100,20,0.1)
plt.plot(table.k,table.累计概率,c='b')
plt.scatter(table.k,table.累计概率,c='r')
plt.scatter(table.k[14:15],table.累计概率[14:15],c='g')
plt.show()
plt.close()
如果增加早餐的份数也就是k的上限,也就是增加冗余,则可以很高效的解决这个问题
可以看到,累计的概率到k=20左右的时候,增加的效果逐渐降低
换一个例子,假如电话公司节假日客户同时通话的概率是60%