概率,编程与数据分析
从一个笑话谈起
有关的数据统计说明:在飞机上碰到有人携带炸弹的概率大概是100万分之一,而一架飞机上有两人同时携带炸弹的概率是万亿分之一。于是,有一个数学家自带了一颗炸弹上了飞机,他认为这样做会尽可能提高了自己的安全性。你怎么看?
当然,这个行为并不会让他更安全,那不过是一种心理安慰罢了!
我们通常所说的概率是用来衡量一件事统计意义上的不确定性。
我们生活中的客观现象可以分为两大类:
-
- 确定性现象:
比如:太阳东升西落,在标准大气压下纯水在100℃时沸腾等,它们在一定条件下结果总是确定的;
- 确定性现象:
-
- 非确定性现象:
比如:拋一枚硬币若干次,每次拋之前都不知道是否正面朝上,每届世界杯足球赛开始前,冠军都是未知的,它们在事前总是不可预言的;
- 非确定性现象:
概率论的一些基本概念
-
- 随机试验:
- A.在相同条件下可重复;
- B.试验结果可能不止一个,但在试验前就明确结果有哪些;
- C.一次试验结束前,不能确切的知道那个结果会出现;
满足上面三个特性的试验称为随机试验;
举个栗子:
拋一枚硬币,有两种情况:正面朝上H和背面朝上T;
可以反复拋,每次的结果可能有两种,在拋之前是不确定的,但不会有第三种情况;这就是一个典型的随机试验。
当然,现实中情况可能稍微复杂一些。
现实中,有一定的概率硬币会站立起来。但是在大部分的数学抽象模型中,为了简化问题,我们只考虑H和T两面的情况。而且,根据对称性,这种情形的概率应该是各有50%的可能性;也就是说你抛掷1000次,大约500次朝上,500次朝下,现实中会有一些偏差;但是试验的次数越多,得到的结果就越满足这个比例;
我们可以用python实现一个小程序来模拟这个过程;
import random
countAllHR = 0
countAllTR = 0
tryies = 10000 # 总共做试验的次数
rangeCount = 10000 # 每次投硬币的次数
for i in range(tryies):
countH = 0
countT = 0
countAll = 0
for i in range(rangeCount):
num=random.randint(0,1)
if num==0:
countH = countH + 1
else:
countT = countT + 1
countAll=countAll+1
countAllHR += countH/countAll
countAllTR += countT/countAll
print("Avareage HR is: ", countAllHR/tryies) # 得到H朝上的概率
print("Avareage TR is: ", countAllTR/tryies) # 得到T朝上的概率
思考:某个罪犯在大马路上被车撞了,这个是随机试验吗?天气预报和炒股是随机试验吗?
-
- 随机事件:
随机试验中可能发生也可能不发生的事情称为随机事件,简称事件,一般用大写字母A,B,C,。。。表示。
比如:
我们把单一的试验结果称为一个“基本事件”。比如上面这个例子中:
0,1,2,3,。。。,9这10个数构成10个的基本事件;
- 随机事件:
全体基本事件的集合称为基本事件空间,也成为样本空间;
在随机事件中必然发生的事件称为必然事件,用符号Ω表示;
在随机事件中必然不发生的事件称为不可能事件,用符号φ表示;
在这二者之间呢,大部分事件是可能发生或可能不发生;这叫涉及到随机事件可能性的计算问题;
FE思考题 概率为0的事件是否是不可能事件,概率为1的事件是否是必然事件;
下面我们来看看怎么来计算一个随机事件的可能性(概率)。
概率: 又叫几率,是表示某种事件(情况)出现的可能性大小的一种数量指标,它介于0与1之间。
怎么算一个随机事件的概率
-
- 古典概型:
假设某试验有有限个结果e1,e2,…,eN,假定从该试验的条件及实施方法上分析,每个结果是“等可能的”。比如,投骰子,各面出现的机会是等可能的;
- 古典概型:
在“等可能的情况下”,引入古典概型:
定义: 设一个试验有N个等可能的结果,而事件E恰包含其中的M个结果,则事件E的概率,记为P(E),
定义 P(E) = M/N;
乍一看,似乎按2/3与1/3的比例分合适;但实际上不太合理。
我们可以看出如果继续比下去,直到结束,应该是:
import itertools
count = 0
for i in itertools.product('甲乙', repeat = 2):
print(i)
count += 1
输出:
(‘甲’, ‘甲’)
(‘甲’, ‘乙’)
(‘乙’, ‘甲’)
(‘乙’, ‘乙’)
有四种情况,可以看出,这四种情况的只有最后一种乙才能获胜,所以因该是甲分3/4 * 1000 = 750, 乙分250才合理;
古典概型其实很简单,主要是数数,计数。
怎么很好的计数呢,我们来看两个重要的知识点:
补充两个重要的基础知识(学过的可以忽略):
- A. 加法原理和乘法原理:
- B. - B. 排列数与组合数:
这是高中数学的一个难点,很多同学可能没学好,其实没那么难。
关键点:排列有序组合无序
怎么用Python来实现最基本的排列组合呢?
# coding: utf-8
import itertools
#不放回抽样排列
count = 0
for i in itertools.permutations('ABCD', 2):
print(i)
count += 1
print(count)
print() # 4*4 种情况, 可重复的排列
#有放回抽样排列,可重复
count = 0
for i in itertools.product('ABCD', repeat = 2):
print(i)
count += 1
print(count)
print() # P(2,4)种情况,不可重复的排列
#不放回抽样组合
count = 0
for i in itertools.combinations('ABCD', 2):
print(i)
count += 1
print(count)
print() # C(2,3)种情况,不可重复的组合
#有放回抽样组合,可重复
count = 0
for i in itertools.combinations_with_replacement('ABCD', 2):
print(i)
count += 1
print(count)
print() # C(2,2+4-1)种情况,可重复组合
补充:可重复组合 的推理过程
LeetCode上也经常有排列组合的题目:
class Solution(object):
def permute(self, nums):
res = [] #res 用于记录并返回所有排列组合。
self.excute(nums,[],res)
return res
def excute(self,nums,path,res): #path用于存放经过的元素
if not nums:
res.append(path)
for i in range(len(nums)):
self.excute(nums[:i]+nums[i+1:],path+[nums[i]],res) #每经过一个元素,将其从nums中取出,放入path,
#当nums为空时,就完成一个排列组合。
if __name__ == "__main__":
s = Solution()
print(s.permute([1,2,3]))
古典概率的局限性很显然:只能用于全部试验结果为有限个,且等可能性成立的情况;在某些情况下,这个概念需要引申到试验结果有无限多个的情况,需要“几何概型”。
大家听说过“三个臭皮匠,抵个诸葛亮!” 这句话其实有一定的数学依据。这涉及到概率中的独立性和乘法原理,我们之后会聊到。
大家经常在面试中,在做数据分析时,在做加解密,破解密码时遇到各种概率问题;从一个程序员的角度来看概率问题,更多的细节,可见:
AI的数学基础–概率论与数理统计