8.1 基础知识
8.1.1 偏差-方差权衡
记\(y=f(x)+\varepsilon, \; E(\varepsilon)=0\),\(f\)表示真实模型,\(\hat f\)是模型某次训练得到的结果,\(E(\hat f)\)表示训练模型的期望表现。
\[ \begin{aligned} E[(\hat f-y)^2] &= E[(\hat f - E(\hat f) + E(\hat f)-y)^2] \\ &= E[(\hat f - E(\hat f))^2] + E[(E(\hat f)-y)^2] + 2E[(\hat f - E(\hat f))(E(\hat f)-y)] \\ &= E[(\hat f - E(\hat f))^2] + E[(E(\hat f)-y)^2] \\ &= E[(\hat f - E(\hat f))^2] + E[(E(\hat f)-f-\varepsilon)^2] \\ &= E[(\hat f - E(\hat f))^2] + E[(E(\hat f) - f)^2] + \varepsilon^2 \end{aligned} \]
故模型的期望泛化错误率可拆解为方差+偏差+噪声
8.1.2 评价指标
- 分类问题
- 准确率
\[ Accuracy = \frac{TP + TN}{TP + TN + FP +FN} \]
- 精确率(查准率):有没有误报
\[ Precision = \frac{TP}{TP+FP} \]
- 召回率(查全率):有没有漏报
\[ Recall = \frac{TP}{TP+FN} \]
- F1与\(F_\beta\)
\[ F1 = \frac{2*Precision*Recall}{Precision + Recall} \\ F_\beta = \frac{(1+\beta^2)*Precision*Recall}{\beta^2*Precision + Recall} \]
\(0<\beta<1\)时精确率有更大影响,\(\beta>1\)时召回率有更大影响
- ROC曲线与AUC:横轴假阳率FPR,纵轴真阳率TPR,全局性能评估
\[ TPR = \frac{TP}{TP+FN} \\ FPR = \frac{FP}{FP+TN} \]
- PR曲线与AUC:横轴召回率,纵轴精确率,更关注正样本预测质量
当存在类别不平衡情况时,PR曲线相较ROC曲线更敏感,能捕捉到异常
代价曲线:引入误判代价
宏平均:对于多个混淆矩阵,先计算各个混淆矩阵的指标,再求平均
微平均:对于多个混淆矩阵,先平均各个混淆矩阵,再求指标
- 回归问题
均方误差:对异常值敏感
均方根误差:量纲与目标变量一致
平均绝对误差:对异常值不敏感
\(R^2\)与\(R^2_{adj}\)
- 其他
- AIC
\[ AIC = -2L(\hat \theta)_{max} + 2k \]
k是参数数量
- BIC
\[ BIC = -2L(\hat \theta)_{max}+ k\ln(n) \]
8.1.3 特征工程
特征工程:从原始数据中创建、选择、变换或组合特征,以提高机器学习模型性能的过程。
8.1.3.1 探索性数据分析
了解数据在分布、类型、统计量、缺失值、异常值、实际含义等方面的基本信息。
方法:
数据可视化
注意辛普森悖论,引入分层变量进行探索
描述性统计
专家的先验知识
相关性分析
皮尔逊相关系数、斯皮尔曼秩相关系数(非参)、肯德尔秩相关系数(非参,有序变量)、列联表检验
8.1.4 pandas与sklearn
8.1.4.2 数据预处理
- 缺失值处理
# 各列缺失值数量
df.count()
df.isnull().sum()
# 各列缺失值比例
df.isnull().mean() * 100
# 缺失值可视化
import missingno as msno
import matplotlib.pyplot as plt
msno.matrix(df) # 矩阵图:直观展示缺失值在数据中的分布
plt.show()
msno.bar(df) # 条形图:按列展示完整数据比例
plt.show()
# 删除缺失值
df = df.dropna() # 删除包含任何缺失值的行
df = df.dropna(axis=1, how='all') # 删除全是缺失值的列
# 填充缺失值
df_filled = df.fillna(0) # 用固定值填充
df['A'] = df['A'].fillna(df['A'].mean()) # 均值
df['B'] = df['B'].fillna(df['B'].median()) # 中位数
df = df.ffill() # 前向填充
df = df.bfill() # 后向填充
df = df.interpolate() # 用插值法填充(更平滑的填充方式)
- 异常值处理
# Z-score
from scipy import stats
z_scores = np.abs(stats.zscore(df['A']))
outliers = df[z_scores >= 3]
# 四分位距
Q1 = df['A'].quantile(0.25)
Q3 = df['A'].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
outliers = df[(df['A'] < lower_bound) | (df['A'] > upper_bound)]
# 异常值处理
df = df[z_scores < 3] # 三倍标准差内
df['A'] = df['A'].clip(lower=lower_bound, upper=upper_bound)
- 标准化
from sklearn.preprocessing import StandardScaler
# from sklearn.preprocessing import MinMaxScaler
# 选取数值列
numeric_cols = df.select_dtypes(include=['number']).columns
# 标准化并替换
scaler = StandardScaler() # scaler = MinMaxScaler()
df[numeric_cols] = scaler.fit_transform(df[numeric_cols])
- 编码
# 独热编码
df = pd.get_dummies(df)
# 也可考虑from sklearn.preprocessing import OneHotEncoder
# 哑变量编码
df = pd.get_dummies(df, drop_first=True)
# 频率编码
frequency = df['A'].value_counts(normalize=True)
df['A'] = df['A'].map(frequency)
# 有序变量编码
df['评分'] = pd.Categorical(
df['评分'],
categories=['低', '中', '高', '极高'],
ordered=True
)
df['评分编码'] = df['评分'].cat.codes
# 自定义编码
edu_map = {'小学': 1, '中学': 2, '大学': 3, '硕士': 4, '博士': 5}
df['edu'] = df['edu'].map(edu_map)
8.1.4.3 分割数据集
from sklearn.model_selection import train_test_split
# 训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 训练集和验证集
X_train, X_val, y_train, y_val = train_test_split(X_train, y_train, test_size=0.25, random_state=42)
# 分层分割
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42, stratify= categorical_var)
# 交叉验证
from sklearn.model_selection import KFold
kf = KFold(n_splits=10, shuffle=True, random_state=42)
for train_index, test_index in kf.split(X, y):
# 获取分割后的训练集和测试集
X_train, X_test = X[train_index], X[test_index]
y_train, y_test = y[train_index], y[test_index]
...
# 也可使用cross_val_score及cross_validate来简化交叉验证流程
cross_val_score(model, X, y, cv=5, scoring='accuracy') # 单个评估指标
cross_validate(model, X, y, cv=5, scoring=['accuracy', 'f1_macro'], return_train_score=True) # 多个评估指标