离散概率分布全指南:从理论到Python实战
你在做用户转化分析时,是否遇到过这样的问题。
发送100封邮件,预计有多少人会点击?
或者在质检时想知道,抽查10件产品,出现次品的概率是多少?
这些看似简单的业务问题,背后都离不开离散概率分布。
本文会带你掌握数据科学中最常用的7种离散分布,并且以完整代码实现。
一、 什么是离散概率分布?为什么你需要它
一句话理解核心概念
离散概率分布就是给"可数结果"分配概率的工具。比如:
● 掷骰子(1~6点)
● 统计网站访客数量(0人、1人、2人...)
● 判断邮件是否被打开(打开/未打开)
它和连续分布(如身高、体重)的本质区别是:离散分布处理整数或类别,连续分布处理小数测量值。
为什么它对你的工作有用?
Netflix用它做推荐算法、银行用它评估信用风险、制造业用它做质量抽检。具体到开发场景:

二、 数学基础扫盲
在进入具体分布前,先理解三个核心工具:
1. 概率质量函数(PMF)
告诉你每个结果的精确概率。
两条铁律:
1. 所有概率 ≥ 0(不能出现负概率)
2. 所有概率加起来 = 1(总得有个结果发生)
实战例子:
# 掷骰子的PMF
outcomes = [1, 2, 3, 4, 5, 6]
probabilities = [1/6] * 6 # 每面概率1/6
print(sum(probabilities)) # 输出: 1.0
2. 累积分布函数(CDF)
告诉你"结果≤某个值"的累积概率。
举例:掷骰子"点数≤3"的概率 = P(1) + P(2) + P(3) = 0.5
3. 期望值与方差
期望值(均值):长期平均结果
方差:结果的波动程度
# 快速计算示例
import numpy as np
X = [0, 1, 2, 3]
P = [0.1, 0.2, 0.3, 0.4]
mean = sum(x * p for x, p in zip(X, P)) # 期望值
variance = sum((x - mean)**2 * p for x, p in zip(X, P)) # 方差
print(f"均值: {mean}, 方差: {variance}")
三、 核心分布实战指南
1. 伯努利分布:最简单的"成功/失败"模型
适用场景:单次事件,只有两种结果
● 用户是否点击广告
● 邮件是否被打开
● 产品是否合格
公式:P(X=1) = p,P(X=0) = 1-p
Python实现
from scipy.stats import bernoulli
# 场景:邮件打开率60%
p = 0.6
rv = bernoulli(p)
print(f"打开概率: {rv.pmf(1)}") # 0.6
print(f"未打开概率: {rv.pmf(0)}") # 0.4
print(f"期望值: {rv.mean()}") # 0.6
AI应用示例(本地):
import random
def classify_sentiment_safe(text, use_api=False):
"""安全的情绪分类函数,带本地备选"""
if not use_api:
# 本地简单实现
positive_words = ['好', '优秀', '棒', '不错', '满意', '喜欢', '赞']
negative_words = ['差', '糟糕', '烂', '不好', '失望', '讨厌']
text_lower = text.lower()
positive_count = sum(1 for word in positive_words if word in text_lower)
negative_count = sum(1 for word in negative_words if word in text_lower)
if positive_count > negative_count:
return 1
elif negative_count > positive_count:
return 0
else:
return random.randint(0, 1) # 随机
try:
# API调用(需要配置有效密钥)
import requests
API_KEY = "你的硅基流动API_KEY"
if API_KEY == "你的硅基流动API_KEY":
print("请配置有效API_KEY,使用本地模拟")
return classify_sentiment_safe(text, use_api=False)
MODEL = "THUDM/GLM-4-9B-0414"
response = requests.post(
"https://api.siliconflow.cn/v1/chat/completions",
headers={"Authorization": f"Bearer {API_KEY}"},
json={
"model": MODEL,
"messages": [{"role": "user", "content": f"判断情感(正面=1/负面=0):{text}"}]
},
timeout=10
)
response.raise_for_status()
result = response.json()['choices'][0]['message']['content']
return 1 if "1" in result or "正面" in result else 0
except Exception as e:
print(f"API调用失败: {e},使用本地模拟")
return classify_sentiment_safe(text, use_api=False)
# 模拟100次分类,统计成功率
results = [classify_sentiment_safe("这个产品很好用", use_api=False) for _ in range(100)]
success_rate = sum(results) / len(results)
print(f"模型正面判断率: {success_rate:.2f}")
2. 二项分布:重复N次独立试验
适用场景:多次重复伯努利试验
● 100封邮件有多少人会点击
● 生产100件产品有多少件不合格
核心假设:
1. 每次试验成功概率相同
2. 试验次数固定
3. 各次试验独立
Python实现:
from scipy.stats import binom
import matplotlib.pyplot as plt
import numpy as np
def setup_chinese_font():
"""设置中文字体,避免乱码"""
try:
plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei', 'DejaVu Sans']
plt.rcParams['axes.unicode_minus'] = False
return True
except:
print("中文显示设置失败,使用默认字体")
return False
# 场景:发送100封邮件,点击率30%
n, p = 100, 0.3
rv = binom(n, p)
# 计算恰好40人点击的概率
prob_40 = rv.pmf(40)
print(f"恰好40人点击: {prob_40:.4f}")
# 计算至少20人点击的概率
prob_at_least_20 = 1 - rv.cdf(19)
print(f"至少20人点击: {prob_at_least_20:.4f}")
# 可视化
setup_chinese_font()
x = range(0, 61) # 只显示0-60范围
plt.figure(figsize=(10, 6))
plt.bar(x, [rv.pmf(i) for i in x], alpha=0.7)
plt.xlabel('点击人数')
plt.ylabel('概率')
plt.title('二项分布PMF (n=100, p=0.3)')
plt.tight_layout()
plt.show()
实战应用:A/B测试显著性检验
def ab_test_significance(clicks_a, trials_a, clicks_b, trials_b):
"""判断两个版本转化率是否有显著差异"""
try:
from scipy.stats import binomtest
rate_a = clicks_a / trials_a
rate_b = clicks_b / trials_b
# 使用精确二项检验
result = binomtest(clicks_b, trials_b, rate_a, alternative='two-sided')
p_value = result.pvalue
if p_value < 0.05 and abs(rate_b - rate_a) > 0.01: # 添加最小效果阈值
return f"版本B显著不同 (p={p_value:.4f}, 提升: {(rate_b-rate_a):.2%})"
else:
return f"无显著差异 (p={p_value:.4f})"
except ImportError:
from scipy.stats import chi2_contingency
import numpy as np
obs = np.array([[clicks_a, trials_a-clicks_a],
[clicks_b, trials_b-clicks_b]])
_, p_value, _, _ = chi2_contingency(obs)
return f"卡方检验: p={p_value:.4f}"
# 测试数据
result = ab_test_significance(clicks_a=300, trials_a=1000,
clicks_b=350, trials_b=1000)
print(result)
3. 泊松分布:预测"稀有但稳定"的事件
适用场景:
● 客服中心每小时来电数
● 网站每分钟访问量
● 系统每天故障次数
核心特征:均值 = 方差(这是识别泊松分布的关键)
Python实现:
from scipy.stats import poisson
# 场景:客服平均每小时接3通电话
lambda_rate = 3
rv = poisson(mu=lambda_rate)
# 计算1小时内无来电的概率
prob_0 = rv.pmf(0)
print(f"无来电概率: {prob_0:.4f}") # 约5%
# 计算接到5通以上电话的概率
prob_above_5 = 1 - rv.cdf(5)
print(f"超过5通电话: {prob_above_5:.4f}")
# 实际应用:人力规划
print(f"95%置信区间内最多接听: {rv.ppf(0.95):.0f}通")
结合AI的异常检测应用:
import numpy as np
from scipy.stats import poisson
def detect_anomaly(observed_count, lambda_rate, threshold=0.05):
"""检测观测值是否异常(基于泊松分布)"""
rv = poisson(mu=lambda_rate)
p_value = 1 - rv.cdf(observed_count - 1) # P(X >= observed_count)
if p_value < threshold:
return f"⚠️ 异常!观测值{observed_count}超出正常范围(p={p_value:.4f})"
return f"✓ 正常范围(p={p_value:.4f})"
# 示例:正常情况下每小时3次API调用,今天突然来了10次
print(detect_anomaly(observed_count=10, lambda_rate=3))
4. 几何分布:第一次成功需要多少次
适用场景:
● 抽奖系统:平均多少次能中奖
● 获客成本:联系多少个客户能成交第一单
关键特性:无记忆性(前面失败不影响后续概率)
Python实现:
from scipy.stats import geom
# 场景:转化率20%,第一次成功平均需要多少次
p = 0.2
rv = geom(p)
print(f"期望尝试次数: {rv.mean()}") # 5次
print(f"第3次成功的概率: {rv.pmf(3):.4f}")
# 实战:计算获客成本
cost_per_contact = 50 # 每次联系成本50元
expected_cost = rv.mean() * cost_per_contact
print(f"预期获客成本: {expected_cost:.0f}元")
5. 超几何分布:不放回抽样的精确计算
适用场景:
● 质检抽样(样本量小,不能放回)
● 抽卡游戏概率(牌堆固定)
与二项分布的区别:超几何是不放回,二项是放回
Python实现:
from scipy.stats import hypergeom
# 场景:100件产品中有8件次品,抽查10件
N, K, n = 100, 8, 10 # 总数、次品数、抽样数
rv = hypergeom(M=N, n=K, N=n)
# 计算至少抽到1件次品的概率
prob_at_least_1 = 1 - rv.pmf(0)
print(f"至少1件次品: {prob_at_least_1:.4f}") # 58.34%
# 对比:如果用二项分布(放回抽样)会怎样
from scipy.stats import binom
rv_binom = binom(n=10, p=8/100)
prob_binom = 1 - rv_binom.pmf(0)
print(f"二项分布结果: {prob_binom:.4f}") # 56.51%(略有偏差)
四、 进阶分布速览
1. 分类分布:多类别场景
import numpy as np
from scipy.stats import rv_discrete
# 场景:用户可能访问首页/产品页/关于页
pages = ["home", "product", "about"]
probs = [0.5, 0.3, 0.2]
rv = rv_discrete(values=(np.arange(len(probs)), probs))
print(f"访问产品页概率: {rv.pmf(1)}") # 0.3
2. 离散均匀分布:完全随机
from scipy.stats import randint
# 场景:随机抽取1~100的整数
rv = randint(low=1, high=101)
print(f"抽到50的概率: {rv.pmf(50)}") # 0.01
五、 完整环境配置与避坑指南
1. 环境安装
# 创建虚拟环境
conda create -n prob_dist python=3.9
conda activate prob_dist
# 安装核心库(使用国内镜像加速)
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple numpy scipy matplotlib requests
# 或使用阿里云镜像
pip install -i https://mirrors.aliyun.com/pypi/simple/ numpy scipy matplotlib requests
2. 常见报错解决
报错1:AttributeError: module 'scipy.stats' has no attribute 'binom'
# 解决:升级scipy版本
pip install --upgrade scipy
报错2:泊松分布参数错误
# 错误写法
rv = poisson(3) # ❌ 缺少参数名
# 正确写法
rv = poisson(mu=3) # ✓ 必须指定mu
报错3:超几何分布参数顺序混淆
# scipy的参数顺序:M(总数), n(成功数), N(抽样数)
rv = hypergeom(M=100, n=8, N=10) # 正确
# 不要和数学公式的N、K、n混淆!
六、 实战项目:构建智能质检系统
综合运用多个分布,构建一个完整的质检决策系统:
from scipy.stats import hypergeom, poisson, binom
import numpy as np
import matplotlib.pyplot as plt
class QualityControl:
def __init__(self, batch_size, defect_rate, sample_size):
self.batch_size = batch_size
self.defect_rate = defect_rate
self.sample_size = sample_size
def sampling_plan(self, accept_threshold):
"""计算抽样方案的接收概率"""
expected_defects = int(self.batch_size * self.defect_rate)
rv = hypergeom(M=self.batch_size, n=expected_defects, N=self.sample_size)
prob_accept = rv.cdf(accept_threshold)
return prob_accept
def predict_daily_defects(self, production_rate):
"""预测每日次品数(泊松分布)"""
lambda_rate = production_rate * self.defect_rate
rv = poisson(mu=lambda_rate)
return {
'expected': rv.mean(),
'95%_upper': rv.ppf(0.95),
'prob_zero': rv.pmf(0)
}
def compare_distributions(self):
"""比较超几何分布和二项分布的差异"""
expected_defects = int(self.batch_size * self.defect_rate)
# 超几何分布(不放回)
hyper_rv = hypergeom(M=self.batch_size, n=expected_defects, N=self.sample_size)
# 二项分布(放回)
binom_rv = binom(n=self.sample_size, p=self.defect_rate)
x_values = range(0, min(self.sample_size, expected_defects) + 1)
plt.figure(figsize=(10, 6))
plt.bar([x - 0.2 for x in x_values],
[hyper_rv.pmf(x) for x in x_values],
width=0.4, label='超几何分布', alpha=0.7)
plt.bar([x + 0.2 for x in x_values],
[binom_rv.pmf(x) for x in x_values],
width=0.4, label='二项分布', alpha=0.7)
plt.xlabel('次品数量')
plt.ylabel('概率')
plt.title('抽样分布比较')
plt.legend()
plt.tight_layout()
plt.show()
# 使用示例
if __name__ == "__main__":
# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False
qc = QualityControl(batch_size=1000, defect_rate=0.02, sample_size=50)
# 场景1:抽样方案评估
accept_prob = qc.sampling_plan(accept_threshold=2)
print(f"抽到≤2件次品时接收批次的概率: {accept_prob:.2%}")
# 场景2:日产量预测
daily_stats = qc.predict_daily_defects(production_rate=500)
print(f"预期每日次品数: {daily_stats['expected']:.1f}件")
print(f"95%置信上限: {daily_stats['95%_upper']:.0f}件")
print(f"无次品概率: {daily_stats['prob_zero']:.2%}")
# 场景3:分布比较
qc.compare_distributions()
是单次事件?
├─ 是 → 伯努利分布
└─ 否 → 是固定次数重复试验?
├─ 是 → 二项分布
└─ 否 → 是计数事件频率?
├─ 是 → 泊松分布
└─ 否 → 是等待第一次成功?
├─ 是 → 几何分布
└─ 否 → 是不放回抽样?
├─ 是 → 超几何分布
└─ 否 → 检查其他分布
进阶学习路径
理论深化:学习矩母函数(MGF)理解分布性质
连续分布:掌握正态分布、指数分布
统计检验:卡方检验、t检验
贝叶斯推断:将概率分布与先验知识结合



