深入理解广义线性模型 (GLM):从理论到 Python 实战指南

前置知识

在深入探讨广义线性模型之前,建议你对以下概念有一定的了解。这将帮助你更好地理解后续的内容:

  • 线性回归:理解连续变量的预测和最小二乘法。
  • 逻辑回归:理解分类问题和 Sigmoid 函数的应用。

引言:超越传统线性回归

你好!作为一名技术爱好者,你可能经常遇到各种各样的数据问题。在机器学习的入门旅程中,我们通常从线性回归开始,学习如何预测房价或股票价格。然而,现实世界的数据往往比简单的直线关系要复杂得多。你是否遇到过这样的情况:你想预测的是“是/否”这样的二元结果(比如用户是否会点击广告),或者是某个时间段内的发生次数(比如某路口一天的交通事故数量)?

这时候,传统的线性回归就显得力不从心了。它假设误差呈正态分布,且预测值可以是任何实数,这对于二元分类或计数数据来说显然是不合理的。

为了解决这些局限性,广义线性模型 应运而生。在这篇文章中,我们将深入探讨 GLMs,看看它是如何通过统一框架将线性回归、逻辑回归甚至泊松回归联系在一起的。我们将揭开指数分布族的神秘面纱,并通过 Python 代码示例,带你一步步构建属于你自己的 GLM 模型。

什么是广义线性模型 (GLM)?

简单来说,广义线性模型是一类回归模型的统称,它允许我们建立响应变量与一个或多个预测变量之间多种类型的线性关系。与传统的线性回归相比,GLMs 更加灵活。

传统线性回归的局限性

传统线性回归模型假设响应变量 $Y$ 和预测变量 $X$ 之间呈线性关系,并且误差项服从正态分布。这在处理连续型数据且数据分布近似正态时效果很好。但在处理以下情况时会遇到困难:

  • 二元分类问题:结果只有 0 或 1。
  • 计数数据:结果是整数且非负,如每天网站访问量。
  • 非正态分布:数据的分布呈现明显的偏态。

GLMs 的核心优势

GLMs 通过引入 连接函数指数分布族,打破了线性回归的限制。以下是 GLMs 带来的一些显著优势:

  • 灵活性:我们可以利用 GLMs 对广泛的关系进行建模,包括线性(高斯分布)、逻辑斯蒂(伯努利分布)、泊松(计数数据)甚至 Gamma 关系。这意味着一套框架可以解决多种问题。
  • 模型可解释性:与神经网络这样的“黑盒”模型不同,GLMs 能够清晰地解释响应变量与预测变量之间的关系。你可以直观地看到每个特征对结果的影响程度。
  • 鲁棒性:由于允许响应变量呈非正态分布,GLMs 在处理包含异常值或非正态数据时,比普通线性回归表现得更稳健。
  • 统计推断:GLMs 允许进行假设检验和统计推断(如 P 值、置信区间),这在医学研究、金融分析等领域至关重要,能够帮助我们理解变量间关系的显著性。
  • 处理不平衡数据:通过指定适当的分布(如 Tweedie 分布),GLMs 在处理不平衡数据集时往往比标准方法更有效。

GLMs 的数学构成:三大组件

要真正理解 GLMs,我们需要掌握它的三个核心组件。不要被数学公式吓倒,我们用通俗易懂的方式来拆解它们。

1. 随机成分

随机成分定义了响应变量 $Y$ 服从哪个指数分布族。这是 GLM 灵活性的来源。

2. 线性预测器

线性预测器是预测变量的线性组合,公式为:

$$\eta = X\beta$$

这与线性回归中的公式是一样的,代表了我们想要提取的信号部分。

3. 连接函数

连接函数 $g$ 将线性预测器 $\eta$ 与分布的期望值 $\mu = E[Y]$ 联系起来:

$$g(\mu) = \eta$$

连接函数的选择取决于数据的分布类型。例如,对于逻辑回归,我们使用 Logit 连接函数;对于泊松回归,我们使用对数连接函数。

指数分布族与数据类型匹配

GLMs 的强大之处在于它将不同的数据类型映射到特定的统计分布上。为了构建一个有效的模型,我们需要知道什么样的数据适合什么样的分布(这里的“数据”指的是我们模型的输出标签)。

1. 二元分类数据 – 伯努利分布

  • 场景:预测邮件是否为垃圾邮件(是/否),或者用户是否购买产品。
  • 分布:伯努利分布,即单次试验的二项分布。
  • 典型模型:逻辑回归。

2. 实数值数据 – 高斯/正态分布

  • 场景:预测房价、气温、身高体重等连续值。
  • 分布:正态分布。
  • 典型模型:线性回归。

3. 计数数据 – 泊松分布

  • 场景:预测某客服中心一小时内接到的电话数量,或者某路口一天内的车祸次数。
  • 分布:泊松分布。
  • 典型模型:泊松回归。

4. 正数连续数据 – Gamma 分布

  • 场景:预测保险索赔金额(总是正数,且往往右偏),或者机器故障前的等待时间。
  • 分布:Gamma 分布。

数学公式详解:指数分布族

为了在技术上更加严谨,让我们看看指数分布族的数学定义。指数分布族是一类分布,其概率密度函数 (PDF) 或概率质量函数 (PMF) 可以写成以下形式:

$$P(y; \eta) = b(y) \exp(\eta^T T(y) – a(\eta))$$

这里有几个关键参数需要理解:

  • $\eta$:自然参数,也称为典范参数。它可以是标量或向量。
  • $T(y)$:充分统计量。通常情况下,$T(y) = y$,意味着数据本身包含了估计参数所需的所有信息。
  • $a(\eta)$:累积量生成函数,主要用于归一化,确保概率的总和为 1。
  • $b(y)$:基数度量

这个统一的公式让我们能够用一种通用的算法(如迭代加权最小二乘法 IRLS)来拟合所有属于该族的模型。

Python 实战:构建不同的 GLM

理论讲得差不多了,让我们动手写点代码。我们将使用 Python 的 statsmodels 库,因为它在统计建模方面提供了非常详细的输出结果,非常适合理解 GLM。

注意:在运行以下代码前,请确保已安装 INLINECODE93b738c4 和 INLINECODEf7e6f872。

示例 1:泊松回归 – 预测骑自行车的人数

假设我们有一组数据,记录了不同天气条件下骑自行车通勤的人数。这是一个典型的计数数据问题。

import pandas as pd
import statsmodels.api as sm
import numpy as np

# 1. 模拟数据生成
np.random.seed(42)
data_size = 200

# 模拟特征:温度、风速、是否是工作日
temp = np.random.normal(20, 5, data_size) # 平均20度
wind_speed = np.random.normal(10, 2, data_size) # 平均风速 10km/h
is_workday = np.random.randint(0, 2, data_size) # 0或1

# 模拟目标变量:骑车人数 (泊松分布)
# 真实的 log(count) 与温度正相关,与风速负相关
true_lambda = np.exp(0.5 * temp - 0.3 * wind_speed + 2 * is_workday)
bike_counts = np.random.poisson(true_lambda)

# 创建 DataFrame
df = pd.DataFrame({
    ‘temp‘: temp,
    ‘wind_speed‘: wind_speed,
    ‘is_workday‘: is_workday,
    ‘bike_counts‘: bike_counts
})

# 2. 构建模型
# 添加截距项
df[‘intercept‘] = 1

# 定义特征和目标
X = df[[‘intercept‘, ‘temp‘, ‘wind_speed‘, ‘is_workday‘]]
y = df[‘bike_counts‘]

# 使用 statsmodels 建立 GLM
# family=sm.families.Poisson() 指定我们使用泊松分布
# link=sm.families.links.log() 指定使用对数连接函数 (Poisson 的默认设置)
model = sm.GLM(y, X, family=sm.families.Poisson())

# 3. 拟合模型
result = model.fit()

# 4. 查看结果
print(result.summary())

# 实用见解:如何解读结果?
print("
=== 模型解读 ===")
print(f"温度系数: {result.params[‘temp‘]:.4f}")
print("这意味着:温度每升高 1 度,骑车人数的对数期望增加约 0.5 倍。")
print("为了更直观理解,我们可以计算发生率比 (Incidence Rate Ratio) = exp(系数)")
print(f"温度的 IRR: {np.exp(result.params[‘temp‘]):.4f}")
print("即温度每升高 1 度,骑车人数平均增加约 {(np.exp(result.params[‘temp‘])-1)*100:.2f}%")

示例 2:逻辑回归 – 预测用户流失

虽然大家常用 INLINECODE76fbe372,但用 INLINECODEc1ce41a1 的 GLM 框架实现逻辑回归能让你看到统计显著性。

# 1. 准备数据 (使用简单的合成数据)
n_samples = 500

# 特征:账户年龄、月消费、客户支持调用次数
age = np.random.normal(2, 1, n_samples)
spend = np.random.normal(50, 10, n_samples)
calls = np.random.poisson(2, n_samples)

# 简单的逻辑:消费越高越不容易流失,调用支持越多越容易流失
# 线性组合
z = 0.5 * age - 0.1 * spend + 0.8 * calls - 2
# Sigmoid 函数将线性组合映射到 0-1 概率
prob = 1 / (1 + np.exp(-z))
# 生成二元结果
churn = (np.random.rand(n_samples) < prob).astype(int)

df_logit = pd.DataFrame({'age': age, 'spend': spend, 'calls': calls, 'churn': churn})

# 2. 构建模型
df_logit['intercept'] = 1
X_logit = df_logit[['intercept', 'age', 'spend', 'calls']]
y_logit = df_logit['churn']

# 使用 Binomial 分布 (伯努利是 Binomial 的特例)
# Logit 连接是默认连接
logit_model = sm.GLM(y_logit, X_logit, family=sm.families.Binomial())
logit_result = logit_model.fit()

print(logit_result.summary())

# 实用见解:预测新用户
new_user = pd.DataFrame({
    'intercept': [1], 
    'age': [1.5], 
    'spend': [80], 
    'calls': [5]
})

pred_prob = logit_result.predict(new_user)
print(f"
新用户流失概率预测: {pred_prob[0]:.2f}")

示例 3:Gamma 回归 – 预测保险索赔金额

当目标变量是严格正数且连续(如金额、时间)且呈现右偏分布时,高斯分布不再适用,Gamma 分布是更好的选择。

# 1. 模拟严格正数的连续数据 (右偏分布)
n = 200
age = np.random.randint(20, 70, n)
coverage = np.random.uniform(0, 1, n) # 0 到 1 之间的覆盖比例

# 真实机制:线性预测器 * 关联函数
mu = np.exp(3 + 0.05 * age - 2 * coverage)

# 生成 Gamma 分布的数据
# shape 参数 (alpha)
alpha = 2.0 
# scale = mu / alpha
claims = np.random.gamma(shape=alpha, scale=mu/alpha, size=n)

df_gamma = pd.DataFrame({‘age‘: age, ‘coverage‘: coverage, ‘claim_amount‘: claims})

# 2. 模型构建
df_gamma[‘intercept‘] = 1
X_gamma = df_gamma[[‘intercept‘, ‘age‘, ‘coverage‘]]
y_gamma = df_gamma[‘claim_amount‘]

# Gamma 回归通常使用 Log 连接函数
gamma_model = sm.GLM(y_gamma, X_gamma, family=sm.families.Gamma(link=sm.families.links.log()))
gamma_result = gamma_model.fit()

print(gamma_result.summary())
print("
注意:对于 Gamma 回归,我们通常关注均值的预测,而不是单个值。")

常见错误与最佳实践

在实战中使用 GLMs 时,我们经常踩坑。以下是一些经验之谈:

1. 检查残差

仅仅看模型准确率是不够的。我们需要检查皮尔逊残差偏差残差。如果模型拟合良好,残差应该大致呈正态分布。

# 获取皮尔逊残差
residuals = result.resid_pearson
# 你可以画一个直方图检查其分布
# import matplotlib.pyplot as plt
# plt.hist(residuals, bins=20)
# plt.show()

2. 泊松回归的过散问题

在使用泊松回归时,如果数据的方差远大于均值,这种情况称为“过散”。这会导致标准误被低估,从而使得变量的显著性被虚高。

解决方案:如果遇到过散问题,通常有两种解决办法:

  • 使用 负二项回归 代替泊松回归。
  • 使用 准泊松回归,它通过引入一个离散参数来调整标准误。

3. 模型比较:AIC 和 BIC

我们怎么知道哪个模型更好?可以使用 赤池信息量准则 (AIC)贝叶斯信息量准则 (BIC)。值越小,通常表示模型越好,同时考虑了拟合优度和模型复杂度(惩罚项)。

print(f"泊松模型 AIC: {result.aic}")
# 尝试不同特征组合,对比 AIC 值

4. 正则化:防止过拟合

正如你在开头看到的,GLMs 也可以结合 Lasso (L1) 或 Ridge (L2) 正则化。这在特征数量非常多(比如文本数据)时非常有用。

  • 性能优化建议:对于超大规模数据,传统的 IRLS 算法可能较慢。在这种情况下,可以使用随机梯度下降 (SGD) 来优化 GLM 的目标函数,这在 INLINECODE60ec3f98 (设置 INLINECODE6f2262c9 参数) 中有很好的实现。

总结:何时使用 GLM?

总体而言,广义线性模型是建立响应变量和预测变量之间关系的强大而灵活的工具。虽然现在深度学习很火,但 GLMs 依然在以下领域占主导地位:

  • 金融风控:预测违约概率或理赔金额。
  • 流行病学:分析疾病发病率与风险因素的关系。
  • 市场营销:用于用户流失预测、促销活动的转化率分析。
  • 制造业:预测故障时间或次品数量。

关键要点回顾

  • 统一框架:GLM 通过连接函数和指数分布族统一了线性、逻辑和泊松回归。
  • 三个核心:随机分布、线性预测器、连接函数。
  • 分布选择:根据 $Y$ 的数据类型选择分布(二分类选伯努利,计数选泊松,正数右偏选 Gamma)。
  • 可解释性:GLM 提供了系数解释和统计检验,这是复杂模型难以匹敌的。

如果你有兴趣了解更多关于 GLMs 的数学细节,不妨考虑阅读一本关于回归分析的进阶教材。希望这篇文章能帮助你更好地理解并应用这一经典的统计学工具!

下一步,不妨找一份你手头的数据集,尝试判断它属于哪个分布族,并用 Python 跑一遍 GLM 吧!

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。如需转载,请注明文章出处豆丁博客和来源网址。https://shluqu.cn/38504.html
点赞
0.00 平均评分 (0% 分数) - 0