2.系统学习-逻辑回归
逻辑回归
- 前言
- 最大似然估计
- 概率
- 似然函数(likelihood function)
- 最大似然估计
- 逻辑回归
- 逻辑回归的似然函数与梯度
- 分类问题常用评价指标
- 项目案例
- 拓展内容
- 作业
前言
逻辑回归与线性回归均属于广义线性模型,区别在于线性回归用于解决回归问题,例如身高、销量等连续变量预测,逻辑回归用于二分类问题,例如判断是否为垃圾邮件,客户是否会点击广告。本章我们将首先了解最大似然估计,一步步推导出逻辑回归模型,最大似然估计广泛用于各类机器学习、深度学习,需要认真理解。接着会以实际案例,讲解非结构化数据处理的基础方法,分类问题建模流程。
学习目标:
- List item
- 最大似然估计
- 逻辑回归模型
- 常用的分类问题评价指标
- 基础数据处理&分类问题建模
- 独自完成Kaggle Titanic竞赛首次提交,得分需要高于0.75链接: Titanic Machine Learning from Disaster
最大似然估计
概率
硬币有正反两面,如果硬币正反两面是均匀的,即每次抛掷后硬币为正的概率是0.5。使用这个硬币,很可能抛10次,有5次是正面。但是假如有人对硬币做了手脚,比如提前对硬币做了修改,硬币正面朝上概率大幅度提升了,你拿到硬币在尝试抛了10次,结果8次都是正面,如何估算下次硬币为正的概率呢?
P
(
8
正
2
反
∣
θ
)
=
C
10
2
(
1
−
θ
)
2
⋅
θ
8
P(8正2反|\theta) = C_{10}^2(1 - \theta)^2 \cdot \theta^8
P(8正2反∣θ)=C102(1−θ)2⋅θ8
import numpy as np
print(f"theta = 0.6, 概率为{10*9/2 * np.power(10.6, 2) * np.power(0.6, 8):.3}")
print(f"theta = 0.7, 概率为{10*9/2 * np.power(10.7, 2) * np.power(0.7, 8):.3}")
print(f"theta = 0.8, 概率为{10*9/2 * np.power(10.8, 2) * np.power(0.8, 8):.3}")
theta = 0.6, 概率为0.121
theta = 0.7, 概率为0.233
theta = 0.8, 概率为0.302
可以看出,我们假设硬币朝正面参数为0.8的时候,出现8正2反情况的概率最大。我们有理由相信,0.8是候选的3个参数中的最接近真实概率的选项。
似然函数(likelihood function)
在上面的尝试中,0.8似乎是一个不错的猜测没,,但是否可能是0.81或者0.79呢,我们当然可以按照上面的方法再次计算概率,但是问题是我们无法遍历整个空间。因此我们需要定义一个函数来表示不同的参数 下,表示多个独立事件θ (x1, x2,…,xn)发生的整体概率,这个函数我们叫它似然函数( likelihood function, 通常用L表),其中组合数部分是常数,我们可以直接忽略。
L
(
x
1
,
x
2
,
…
,
x
n
∣
θ
)
=
∏
i
=
1
n
p
(
x
i
∣
θ
)
L(x_1, x_2, \dots, x_n|\theta) = \prod_{i=1}^{n} p(x_i|\theta)
L(x1,x2,…,xn∣θ)=i=1∏np(xi∣θ)
似然函数通常用L表示,观察到抛硬币“8正2反”的事实,硬币参数 取不同值时,似然函数表示为:
L
(
8
正
2
反
∣
θ
)
=
(
1
−
θ
)
2
⋅
θ
8
L(8正2反|\theta) = (1 - \theta)^2 \cdot \theta^8
L(8正2反∣θ)=(1−θ)2⋅θ8
通过似然函数,我们只要能找到使得似然函数最大(多个独立事件发生的整体概率最大化),就可以完成对硬币参数的估计了,这就是最大似然估计:
θ
^
=
arg
max
θ
∏
i
=
1
n
p
(
x
i
∣
θ
)
\hat{\theta} = \arg\max_{\theta} \prod_{i=1}^{n} p(x_i|\theta)
θ^=argθmaxi=1∏np(xi∣θ)
最大似然估计
通常,由于似然函数为连乘,会造成小数位过高,无法有效表示,我们采用对数似然函数进行表示,把连乘转化为累加形式:
l
(
x
1
,
x
2
,
…
,
x
n
∣
θ
)
=
∑
i
=
1
n
log
p
(
x
i
∣
θ
)
l(x_1, x_2, \dots, x_n|\theta) = \sum_{i=1}^{n} \log p(x_i|\theta)
l(x1,x2,…,xn∣θ)=i=1∑nlogp(xi∣θ)
θ
^
=
arg
max
θ
∑
i
=
1
n
log
p
(
x
i
∣
θ
)
\hat{\theta} = \arg\max_{\theta} \sum_{i=1}^{n} \log p(x_i|\theta)
θ^=argθmaxi=1∑nlogp(xi∣θ)
逻辑回归
逻辑回归是线性分类模型,说线性是因为其决策边界是线性的(平面或超平面),模型输出值域为(0,1),通常我们将输出结果视为属于正样(y = 1)的概率。我们先来看一下逻辑回归模型的数学表示:
P
(
x
)
=
σ
(
w
T
x
)
=
1
1
+
exp
−
w
T
x
P(x) = \sigma(w^T x) = \frac{1}{1 + \exp^{-w^T x}}
P(x)=σ(wTx)=1+exp−wTx1
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
def sigmoid(x):
return 1 / (1 + np.exp(-x))
data = np.arange(-10, 10, 0.1)
plt.plot(data, sigmoid(data))
逻辑回归的似然函数与梯度
tips: 本段包含了不少公式计算,但公式本身的推导细节并不是最重要的,最重要的是通过引入似然函数,我们构造了逻辑回归的损失函数,且该损失函数可以利用梯度下降进行优化。
p
(
y
=
y
i
∣
x
i
)
=
p
(
x
i
)
y
i
(
1
−
p
(
x
i
)
)
1
−
y
i
p(y = y^i | x^i) = p(x^i)^{y^i}(1 - p(x^i))^{1-y^i}
p(y=yi∣xi)=p(xi)yi(1−p(xi))1−yi
Likelihood
=
∏
i
p
(
y
=
y
i
∣
x
i
)
=
∏
i
p
(
x
i
)
y
i
(
1
−
p
(
x
i
)
)
1
−
y
i
\text{Likelihood} = \prod_i p(y = y^i | x^i) = \prod_i p(x^i)^{y^i} (1 - p(x^i))^{1-y^i}
Likelihood=i∏p(y=yi∣xi)=i∏p(xi)yi(1−p(xi))1−yi
两边同时取对数,对数似然函数为:
loglikelihood
=
∑
i
[
y
i
log
p
(
x
i
)
+
(
1
−
y
i
)
log
(
1
−
p
(
x
i
)
)
]
\text{loglikelihood} = \sum_i \left[y^i \log p(x^i) + (1 - y^i) \log (1 - p(x^i))\right]
loglikelihood=i∑[yilogp(xi)+(1−yi)log(1−p(xi))]
loglikelihood
=
∑
i
[
y
i
log
p
(
x
i
)
1
−
p
(
x
i
)
+
log
(
1
−
p
(
x
i
)
)
]
\text{loglikelihood} = \sum_i \left[y^i \log \frac{p(x^i)}{1 - p(x^i)} + \log (1 - p(x^i))\right]
loglikelihood=i∑[yilog1−p(xi)p(xi)+log(1−p(xi))]
那么这个对数似然函数就是我们需要优化的目标的,其值越大越好,越大说明模型预测概率和真实发生概率一致性越高。由于梯度下降法是验证最小化损失函数目标进行的,因此我们对对数似然函数乘以‑1。
J
(
w
)
=
−
∑
i
[
y
i
log
p
(
x
i
)
1
−
p
(
x
i
)
+
log
(
1
−
p
(
x
i
)
)
]
J(w) = -\sum_i \left[y^i \log \frac{p(x^i)}{1 - p(x^i)} + \log (1 - p(x^i))\right]
J(w)=−i∑[yilog1−p(xi)p(xi)+log(1−p(xi))]
求关于参数的梯度,根据求导法则可得:
g
=
∂
J
∂
w
=
∑
i
(
p
(
x
i
)
−
y
i
)
⋅
x
i
g = \frac{\partial J}{\partial w} = \sum_i \left(p(x^i) - y^i\right) \cdot x^i
g=∂w∂J=i∑(p(xi)−yi)⋅xi
有了梯度,根据上节课我们学习的梯度下降,就可以根据学习率α逐步迭代更新模型参数 w = w − α ⋅ g w = w - \alpha \cdot g w=w−α⋅g
分类问题常用评价指标
在二分类场景,模型所有的预测结果可以分为四类:
- TP(True positive),意思是模型预测为正样本(Positive),预测是正确的(True)
- FP(False positive),意思是模型预测为正样本(Positive),预测是错误的(False)
- TN(True negtive),意思是模型预测为负样本(negtive),预测是正确的(True)
- FN(False negtive),意思是模型预测为负样本(negtive),预测是错误的(False)
基于以上四类预测结果,我们可以定义指标:
指标 | 公式 | 含义 |
---|---|---|
准确率 | Accuracy = # T P + # T N # A L L \text{Accuracy} = \frac{\#TP + \#TN}{\#ALL} Accuracy=#ALL#TP+#TN | 所有预测结果中,预测正确的比例,值越大说明模型表现越好。 |
精准率 | Precision = # T P # T P + # F P \text{Precision} = \frac{\#TP}{\#TP + \#FP} Precision=#TP+#FP#TP | 所有预测的正样本中,正确的比例,值越大说明模型表现越好。 |
召回率 | Recall = # T P # T P + # F N \text{Recall} = \frac{\#TP}{\#TP + \#FN} Recall=#TP+#FN#TP | 所有正样本被正确预测的比例,值越大说明模型表现越好。 |
from sklearn.metrics import accuracy_score, precision_score, recall_score
y_true = [1, 1, 0, 1, 0]
y_pred = [0, 1, 0, 1, 0]
accuracy_score(y_true, y_pred)#0.8
precision_score(y_true, y_pred)#1.0
recall_score(y_true, y_pred)#0.6666666666666666
在一些极端场景下,准确率会失效,比如正负样本及其不均匀的情况:
y_true = [1, 1, 1, 1, 1, 0]
y_pred = [1, 1, 1, 1, 1, 1]
accuracy_score(y_true, y_pred) #0.8333333333333334
不过什么输入,模型都预测为正样本,导致模型本质上没有预测能力,但是依然能够取得很高的Accuracy。为了避免评估指标失效,我们可以同时查看precision 和 recall指标
precision_score(y_true, y_pred) #0.8333333333333334
recall_score(y_true, y_pred) # 1.0
也可以应用一个由recall,precision 一起组成的复合指标 f1‑score,该值越大,说明模型表现越好:
f
1
=
2
⋅
recall
⋅
precision
recall
+
precision
f1 = \frac{2 \cdot \text{recall} \cdot \text{precision}}{\text{recall} + \text{precision}}
f1=recall+precision2⋅recall⋅precision
from sklearn.metrics import f1_score
f1_score(y_true, y_pred) # 0.9090909090909091
p = precision_score(y_true, y_pred)
r = recall_score(y_true, y_pred)
2 * p * r / (p + r) #0.9090909090909091
项目案例
链接: Titanic Machine Learning from Disaster
# 导入所需的库
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import re
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import StandardScaler, PolynomialFeatures, OneHotEncoder
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score
%matplotlib inline
# 读取 Titanic 数据集
train = pd.read_csv("./titanic/train.csv") # 训练数据
test = pd.read_csv("./titanic/test.csv") # 测试数据
submission = pd.read_csv("./titanic/gender_submission.csv") # 示例提交文件
# 数据概览
print(train.head()) # 查看训练数据的前几行
print(test.head()) # 查看测试数据的前几行
print(train.isnull().sum()) # 检查训练数据的缺失值
# 填充缺失值
# 用中位数填充缺失的年龄数据
train['Age'] = train['Age'].fillna(train['Age'].median())
test['Age'] = test['Age'].fillna(test['Age'].median())
# 用众数填充缺失的登船港口数据
train['Embarked'] = train['Embarked'].fillna('S')
test['Embarked'] = test['Embarked'].fillna('S')
# 用票价的中位数填充缺失的票价数据
test['Fare'] = test['Fare'].fillna(test['Fare'].median())
# 数据预处理
# 将性别和登船港口转换为数值类型
train = pd.get_dummies(train, columns=['Sex', 'Embarked'], drop_first=True)
test = pd.get_dummies(test, columns=['Sex', 'Embarked'], drop_first=True)
# 删除不需要的列
train.drop(['Name', 'Ticket', 'Cabin'], axis=1, inplace=True)
test.drop(['Name', 'Ticket', 'Cabin'], axis=1, inplace=True)
# 提取目标变量和特征
train_target = train['Survived'] # 目标变量
train_features = train.drop(['Survived', 'PassengerId'], axis=1) # 特征
test_features = test.drop(['PassengerId'], axis=1) # 测试集特征
# 标准化特征
scaler = StandardScaler()
train_features = scaler.fit_transform(train_features)
test_features = scaler.transform(test_features)
# 逻辑回归模型
model = LogisticRegression() # 创建逻辑回归模型
model.fit(train_features, train_target) # 训练模型
# 模型评估
predictions = model.predict(train_features) # 在训练集上预测
print("Accuracy:", accuracy_score(train_target, predictions)) # 准确率
print("Precision:", precision_score(train_target, predictions)) # 精准率
print("Recall:", recall_score(train_target, predictions)) # 召回率
print("F1 Score:", f1_score(train_target, predictions)) # F1 分数
# 在测试集上进行预测
test_predictions = model.predict(test_features)
# 生成提交文件
submission['Survived'] = test_predictions
submission.to_csv("./submission.csv", index=False) # 保存结果到 CSV 文件
print("结果已保存至 submission.csv")
拓展内容
需要注意的是,逻辑回归虽然存在sigmoid函数将输出结果映射到0~1区间,但本质依然是一个线性模型,因为模型的分类决策边界是一个平面,而不是曲面或其他,以下图为例,中间的蓝色直线就是我们的分类(超)平面,位于平面上方的点为正样本,下方的点为负样本,这个分类(超)平面可以用一个线性方程表示出来。
作业
- 分类问题中,在正负样本不均衡的情况下,我们如何评价模型?
- 在Titanic Machine Learning from Disaster比赛提交逻辑回归建模预测结果,需要得分高于0.75