核心问题:如何预测定性的类别标签?
在金融实务中,许多关键决策本质上是分类问题 :
一家上市公司明年会不会被 ST 风险警示 ?
一笔贷款申请是否会 违约 ?
明天的股价会 涨 还是 跌 ?
这些问题的响应变量 \(Y\) 是定性的 (qualitative),而非连续的数值。
本章将系统介绍从逻辑回归到判别分析、朴素贝叶斯等主流分类方法。
同学们好。前面几章我们学习了回归方法,用于预测连续数值。但在金融实务中,很多决策本身就是二选一或多选一的分类问题。比如银行审核一笔贷款是批准还是拒绝,基金经理判断明天市场是涨还是跌。今天我们就来系统学习分类方法的理论与实践。
分类问题的现实意义:从信贷审批到量化交易 {{#sec-classification-realworld}}
分类方法在金融行业中的应用远比想象中广泛:
信贷审批
批准/拒绝
控制坏账率
ST 预警
ST/非ST
投资避雷
欺诈检测
正常/欺诈
风险防控
行业轮动
看好/看空
资产配置
客户分层
高/中/低价值
精准营销
核心挑战 :与回归预测连续数值不同,分类的输出是离散的决策 ,错误分类的代价往往是不对称的(误判一笔坏账远比错失一笔好客户代价更大)。
在金融行业里,分类无处不在。银行每天要处理成千上万的贷款申请,每一笔都是一个分类决策。这些决策的错误代价是不对称的——如果把一个坏客户错判为好客户,银行可能损失整笔贷款本金;但如果把好客户错判为坏客户,只是损失了利息收入。这种不对称性是分类问题的重要特征。
分类 vs. 回归:响应变量的本质区别
响应变量 \(Y\)
定量(连续)
定性(离散类别)
输出
预测值 \(\hat{Y}\)
类别标签 \(\hat{Y}\) 或概率 \(\hat{P}(Y=k\mid X)\)
常用方法
OLS、Ridge、Lasso
逻辑回归、LDA、QDA、朴素贝叶斯
损失函数
MSE
交叉熵、0-1 损失
金融应用
股票收益率预测
违约判别、ST 预警、涨跌方向
分类方法通常先估计条件概率 \(P(Y = k \mid X = x)\) ,再依据概率做出分类决策。
这张表梳理了回归与分类的核心区别。回归预测的是一个连续的数字——比如收益率是3%还是5%。分类预测的是一个类别标签——比如”违约”还是”不违约”。方法论上,分类通常分两步:第一步估计条件概率,第二步根据概率选择类别。
分类的两步策略:先估概率,再做决策 {{#sec-two-step-strategy}}
几乎所有分类方法都遵循相同的两步策略 :
第一步:估计条件概率
\[ \large{{ \hat{{P}}(Y = k \mid X = x) \quad \text{{for each class }} k }} \]
第二步:根据概率做出决策
\[ \large{{ \hat{{Y}} = \arg\max_k \hat{{P}}(Y = k \mid X = x) }} \]
为什么不直接输出类别标签?因为概率蕴含了更丰富的信息:
概率 = 0.51 和 概率 = 0.99 都会被分到同一类,但后者的把握大得多
在金融风控中,概率本身就是风险度量 ——比如违约概率 PD
调整分类阈值 可以灵活权衡漏判率与误判率
分类的核心逻辑分为两步:先估概率、再做决策。这两步是分开的,我们可以独立调整。第一步用统计模型估计概率,第二步用阈值做决策。默认阈值是0.5,但在不平衡场景中往往需要调低。
为什么不能直接用线性回归做分类?
线性回归应用于分类会产生三个根本问题:
问题一:编码方式影响结果
若响应变量有三类(如”低风险=1、中风险=2、高风险=3”),线性回归隐含假设了”高风险与中风险的距离 = 中风险与低风险的距离”,但换成 1/2/3 → 1/3/5 编码会得到完全不同的结果。
问题二:预测值超出合理范围
线性回归的预测值 \(\hat{Y}\) 可以是任意实数,可能输出 \(-0.3\) 或 \(1.5\) ——这些值无法被解释为概率。
问题三:多分类困难
多于两类时,线性回归无法自然地建模多类之间的关系。
有同学可能会问:为什么不直接把类别编码成数字,然后用回归呢?答案是不行,原因有三。第一,编码方式不是唯一的,不同编码给出不同结果。第二,线性回归的预测值没有上下界,可能得到负数或大于1的值,无法解释为概率。第三,多分类时线性回归完全失效。
从线性回归到逻辑回归:关键的”跳板” {{#sec-bridge-to-logistic}}
线性回归做分类的根本问题在于:输出没有边界约束 。
我们需要一种函数,能将 \((-\infty, +\infty)\) 的线性预测值映射到 \((0, 1)\) 的概率空间。
解决方案:链接函数(Link Function)
线性回归
恒等函数 \(g(x) = x\)
\((-\infty, +\infty)\)
无约束
逻辑回归
Logit 函数
\((0, 1)\)
S 形曲线
Probit 模型
\(\Phi^{{-1}}\)
\((0, 1)\)
正态CDF
逻辑回归选择了 Sigmoid 函数 (即 Logistic 函数)作为链接函数的逆变换,这是最自然、最优雅的选择。
理解逻辑回归的关键在于”链接函数”的概念。线性回归用的是恒等链接——输入什么就输出什么。但分类需要概率,必须在0和1之间。逻辑回归用Sigmoid函数做了一个巧妙的变换,把整个实数轴”压缩”到了0和1之间。
逻辑回归:用 Sigmoid 函数约束概率
逻辑回归(Logistic Regression)使用 Sigmoid 函数 将线性预测值映射到 \((0,1)\) :
\[ \large{ p(X) = \frac{e^{\beta_0 + \beta_1 X_1 + \cdots + \beta_p X_p}}{1 + e^{\beta_0 + \beta_1 X_1 + \cdots + \beta_p X_p}} } \]
关键性质:
当 \(\beta_0 + \beta^\top X \to +\infty\) 时,\(p(X) \to 1\)
当 \(\beta_0 + \beta^\top X \to -\infty\) 时,\(p(X) \to 0\)
输出值始终在 \((0, 1)\) 范围内,天然可解释为概率
Sigmoid 函数的几何直觉 {{#sec-sigmoid-geometry}}
Sigmoid 函数 \(\sigma(z) = \frac{{1}}{{1+e^{{-z}}}}\) 具有以下关键几何性质:
形状特征:
在 \(z = 0\) 处通过 \((0, 0.5)\) —— 50/50 的不确定点
\(z > 0\) 时概率大于 0.5,\(z < 0\) 时概率小于 0.5
曲线在 \(z = 0\) 处最陡,远离原点后逐渐平坦
导数的优美性质:
\[ \large{{ \sigma'(z) = \sigma(z) \cdot (1 - \sigma(z)) }} \]
这意味着:
当预测概率接近 0.5 时,梯度最大 → 模型”最不确定”,学习最快
当预测概率接近 0 或 1 时,梯度趋近于零 → 模型”很确定”,不再调整
这与人类学习的直觉完全一致!
Sigmoid函数有一个非常优美的性质:它的导数等于自身乘以1减自身。这不仅简化了数学推导,还蕴含了深刻的直觉——模型在最不确定的地方学习最快,在最确定的地方保持稳定。这个性质也是深度学习中激活函数设计的灵感来源。
从概率到对数几率:Log-Odds 的线性结构
对 \(p(X)\) 做变换,可以得到对数几率 (log-odds / logit):
\[ \large{ \log\frac{p(X)}{1-p(X)} = \beta_0 + \beta_1 X_1 + \cdots + \beta_p X_p } \]
左边称为 logit 变换 ,将 \((0,1)\) 映射到 \((-\infty, +\infty)\)
右边是标准的线性结构,系数 \(\beta_j\) 的含义:\(X_j\) 增加一单位,对数几率增加 \(\beta_j\)
\(\exp(\beta_j)\) 称为几率比 (odds ratio),是金融风控中的核心可解释性指标
逻辑回归虽然用了非线性的Sigmoid函数,但本质上它建模的是对数几率的线性关系。每个系数beta的含义非常清晰:某个特征增加一个单位,分类的对数几率增加beta个单位。这种可解释性在金融风控中至关重要,因为监管机构要求银行能解释模型为什么拒绝了一笔贷款。
几率比的实际解读:金融风控中的核心指标 {{#sec-odds-ratio-interpretation}}
在金融风控报告中,系数的解读通常通过几率比 (Odds Ratio)进行:
\[ \large{{ OR_j = e^{{\beta_j}} }} \]
解读规则:
\(OR_j > 1\) :\(X_j\) 增加一单位,“事件发生”的几率增大
\(OR_j < 1\) :\(X_j\) 增加一单位,“事件发生”的几率减小
\(OR_j = 1\) :\(X_j\) 对结果无影响
风控应用示例:
资产负债率
+2.1
8.17
负债率每升1%,违约几率变为原来的8.17倍
ROA
-3.5
0.03
ROA每升1%,违约几率降至原来的3%
对数总资产
-0.8
0.45
规模每扩大1个数量级,违约几率减半
几率比是银行风控报告中的核心指标。监管机构会要求银行说明:为什么这个客户被拒绝了?用几率比就能清楚解释——比如”该客户的资产负债率每增加1个百分点,违约的几率就变为原来的8倍多”。这种可解释性是逻辑回归在金融行业保持统治地位的根本原因。
最大似然估计:逻辑回归的参数学习
逻辑回归通过最大似然估计 (MLE)求解参数,而非最小化残差平方和。
似然函数为:
\[ \large{ L(\beta) = \prod_{i=1}^{n} p(x_i)^{y_i} [1 - p(x_i)]^{1-y_i} } \]
取对数并求梯度:
\[ \large{ \nabla \ell(\beta) = \sum_{i=1}^{n} (y_i - p_i) x_i } \]
当 \(y_i = 1\) 且 \(p_i\) 偏小时,梯度为正 → 增大 \(\beta\) 以提高 \(p_i\)
当 \(y_i = 0\) 且 \(p_i\) 偏大时,梯度为负 → 减小 \(\beta\) 以降低 \(p_i\)
这一梯度形式与 OLS 的 \((y_i - \hat{y}_i)x_i\) 在结构上完全对应
逻辑回归不使用最小二乘法,而是用最大似然估计。直觉上很简单:我们要找到一组参数,使得观测到的数据出现的概率最大。似然函数的梯度有一个非常优雅的形式:它正好等于”真实标签减去预测概率”再乘以特征向量。这和OLS中”真实值减去预测值”乘以特征的结构完全对应。
MLE vs. OLS:两种参数估计的哲学对比 {{#sec-mle-vs-ols}}
目标函数
最小化残差平方和 \(\sum(y_i - \hat{{y}}_i)^2\)
最大化似然函数 \(\prod p_i^{{y_i}}(1-p_i)^{{1-y_i}}\)
解析解
有 :\(\hat{{\beta}} = (X^\top X)^{{-1}}X^\top y\)
无 :需要迭代优化
优化算法
直接矩阵求逆
牛顿-拉夫森 / IRLS
收敛保证
一步到位
需要迭代,可能不收敛
不收敛原因
—
完全可分、多重共线性
补充说明:完全可分问题
如果存在一个超平面能完美分开两类数据,MLE 会将系数推向 \(\pm\infty\) ,无法收敛。此时需要添加正则化项(如 L1/L2 惩罚)。
这是一个重要的对比。线性回归有解析解,一步就能算出来。但逻辑回归没有解析解,必须用迭代算法。在实际使用中,你可能会遇到逻辑回归不收敛的情况——最常见的原因是”完全可分”,即数据太好分了,模型想把系数推到无穷大。解决办法是加正则化。
交叉熵损失:MLE 的另一副面孔 {{#sec-cross-entropy}}
对数似然函数取负号后,就是深度学习中著名的交叉熵损失 (Cross-Entropy Loss):
\[ \large{{ \text{{CE}} = -\frac{{1}}{{n}} \sum_{{i=1}}^{{n}} \Big[ y_i \log p_i + (1-y_i) \log(1-p_i) \Big] }} \]
直觉理解:
当 \(y_i = 1\) 且 \(p_i \to 0\) 时,\(-\log(p_i) \to +\infty\) → 惩罚极大
当 \(y_i = 1\) 且 \(p_i \to 1\) 时,\(-\log(p_i) \to 0\) → 完美预测
交叉熵衡量的是预测概率分布与真实标签分布之间的”距离”
因此,最大化对数似然 = 最小化交叉熵 = 最小化预测分布与真实分布的差异 。
这是统计学与深度学习的完美桥梁。
这里有一个非常重要的联系:逻辑回归中的最大似然估计和深度学习中的交叉熵损失本质上是同一件事。只不过一个是最大化、一个是最小化,差一个负号。理解了这一点,你就理解了从传统统计到深度学习的最关键桥梁。
A 股实证:逻辑回归预测股价涨跌方向
使用浦发银行(600000.XSHG) 的日线行情数据,构造滞后收益率特征预测次日涨跌:
特征 :前三日收益率 \(\text{Lag}_1, \text{Lag}_2, \text{Lag}_3\)
响应变量 :次日涨跌方向(\(Y=1\) 表示上涨)
模型 :statsmodels.Logit
浦发银行逻辑回归实证(续)
# 筛选浦发银行的交易数据
pudong_bank_df = stock_price_df[stock_price_df['order_book_id' ] == '600000.XSHG' ].copy() # 提取浦发银行数据
pudong_bank_df = pudong_bank_df.sort_values('date' ) # 按日期排序确保时序正确
pudong_bank_df['daily_return' ] = pudong_bank_df['close' ].pct_change() # 计算日收益率
# 构造滞后特征:前1/2/3日收益率
pudong_bank_df['lag_1' ] = pudong_bank_df['daily_return' ].shift(1 ) # 前1日收益率
pudong_bank_df['lag_2' ] = pudong_bank_df['daily_return' ].shift(2 ) # 前2日收益率
pudong_bank_df['lag_3' ] = pudong_bank_df['daily_return' ].shift(3 ) # 前3日收益率
# 构造二分类响应变量:涨=1,跌=0
pudong_bank_df['is_up' ] = (pudong_bank_df['daily_return' ] > 0 ).astype(int ) # 当日收益率>0标记为上涨
pudong_bank_df = pudong_bank_df.dropna(subset= ['lag_1' , 'lag_2' , 'lag_3' , 'is_up' ]) # 删除缺失值
# 构建特征矩阵并添加截距项
feature_matrix = sm.add_constant(pudong_bank_df[['lag_1' , 'lag_2' , 'lag_3' ]]) # 添加常数列作为截距
response_vector = pudong_bank_df['is_up' ] # 提取响应变量
# 拟合逻辑回归模型
logit_model = sm.Logit(response_vector, feature_matrix).fit(disp= 0 ) # 使用MLE拟合逻辑回归
logit_model.summary2().tables[1 ] # 展示系数估计表
const
-0.091713
0.028113
-3.262326
0.001105
-0.146813
-0.036613
lag_1
-2.545384
1.345245
-1.892134
0.058473
-5.182016
0.091247
lag_2
-0.763111
1.341220
-0.568967
0.569378
-3.391854
1.865633
lag_3
0.553342
1.340937
0.412653
0.679861
-2.074847
3.181531
从结果可以看到,滞后收益率的系数大多不显著。这其实印证了金融学中的有效市场假说——历史价格中的信息已经被市场消化,用过去几天的涨跌来预测明天的方向是非常困难的。但逻辑回归的框架本身是正确的,我们随后会看到它在其他场景(比如ST预警)中表现要好得多。
贝叶斯定理:分类的概率论基础
贝叶斯定理是生成式分类方法的理论基石:
\[ \large{ P(Y = k \mid X = x) = \frac{P(X = x \mid Y = k) \cdot P(Y = k)}{P(X = x)} } \]
后验概率
\(P(Y=k\mid X)\)
观测到特征后的类别概率
似然
\(P(X\mid Y=k)\)
类别 \(k\) 下特征的分布
先验概率
\(P(Y=k)\)
各类别出现的频率
边际概率
\(P(X)\)
特征的整体分布(归一化常数)
判别式 vs. 生成式 :逻辑回归直接建模后验 \(P(Y\mid X)\) ;而 LDA/QDA 通过建模似然 \(P(X\mid Y)\) 与先验 \(P(Y)\) ,再用贝叶斯定理间接得到后验。
现在我们换一个角度来看分类问题。贝叶斯定理告诉我们:给定特征X后,类别Y的概率等于似然乘以先验再除以边际概率。这给出了两种不同的建模路径:判别式方法直接建模后验概率,而生成式方法先建模似然和先验,再反推后验。各有优劣。
判别式 vs. 生成式:两种建模哲学 {{#sec-discriminative-vs-generative}}
理解这两种范式是掌握分类方法的关键:
判别式方法 (Discriminative)—— “直接画边界”
直接学习决策边界 \(P(Y \mid X)\)
不关心数据是怎么生成的
代表:逻辑回归、SVM、神经网络
生成式方法 (Generative)—— “理解数据的来源”
先学习每个类别的数据生成过程 \(P(X \mid Y)\)
再通过贝叶斯定理反推 \(P(Y \mid X)\)
代表:LDA、QDA、朴素贝叶斯
类比理解:
判别式像海关检查员 :只关心护照和人是否匹配(边界判定)
生成式像人口学家 :先研究不同国家人群的特征分布,再判断这个人最可能来自哪国
判别式和生成式是机器学习中两种根本不同的世界观。判别式方法务实高效,直接画决策边界。生成式方法更有”野心”,它试图理解每个类别的数据是怎么产生的。这两种思路各有千秋——判别式通常分类精度更高,但生成式可以处理缺失数据、可以生成新样本、而且在小样本下更稳定。
LDA:线性判别分析
线性判别分析(LDA) 假设每个类别的特征服从多元正态分布 且协方差矩阵相同 :
\[ \large{ X \mid Y = k \sim N(\mu_k, \Sigma) } \]
在此假设下,判别函数为线性形式:
\[ \large{ \delta_k(x) = x^\top \Sigma^{-1} \mu_k - \frac{1}{2} \mu_k^\top \Sigma^{-1} \mu_k + \log \pi_k } \]
\(\mu_k\) :类别 \(k\) 的均值向量
\(\Sigma\) :共享的协方差矩阵
\(\pi_k = P(Y=k)\) :先验概率
决策规则:将 \(x\) 分配到使 \(\delta_k(x)\) 最大的类别 \(k\)
LDA假设各类别的数据都服从正态分布,而且共享相同的协方差矩阵。这个假设看起来很强,但它带来的好处是:判别函数变成了线性的,决策边界是一条直线或超平面。在小样本情况下,LDA比逻辑回归更稳定,因为它的参数更少。
LDA 的几何直觉:寻找最佳投影方向 {{#sec-lda-geometry}}
LDA 的核心思想可以用一句话概括:寻找一个方向,使得投影后两类数据分得最开 。
Fisher 准则:
\[ \large{{ J(w) = \frac{{|w^\top \mu_1 - w^\top \mu_2|^2}}{{w^\top \Sigma_w w}} = \frac{{\text{{类间散度}}}}{{\text{{类内散度}}}} }} \]
分子 (类间散度):两类均值的投影距离 → 越大越好
分母 (类内散度):每类内部的投影方差 → 越小越好
最优投影方向:\(w^* = \Sigma_w^{{-1}}(\mu_1 - \mu_2)\)
直觉 :好的投影就像好的”观察角度”——让不同群体的特征差异最大化,同时让同一群体内部的差异最小化。
LDA的几何含义非常直观。想象你在一个房间里看两群人——高个子一群、矮个子一群。你从不同角度看他们,有些角度两群人完全混在一起,有些角度则分得很清楚。LDA就是在寻找那个”最佳观察角度”,数学上就是使Fisher准则最大化的投影方向。
QDA:允许不同协方差的二次判别
二次判别分析(QDA) 放松了 LDA 的等协方差假设,允许每个类别有自己的协方差矩阵:
\[ \large{ X \mid Y = k \sim N(\mu_k, \Sigma_k) } \]
判别函数变为二次形式 :
\[ \large{ \delta_k(x) = -\frac{1}{2} x^\top \Sigma_k^{-1} x + x^\top \Sigma_k^{-1} \mu_k + C_k } \]
协方差假设
\(\Sigma_1 = \Sigma_2 = \Sigma\)
\(\Sigma_1 \neq \Sigma_2\)
决策边界
线性
二次曲线
参数数量
较少
较多
适用场景
小样本、类分布相似
大样本、类分布差异大
QDA是LDA的推广。它允许不同类别有不同的协方差矩阵。代价是参数量增加了——在p维空间中,QDA需要估计的协方差元素是LDA的K倍。这就是经典的偏差-方差权衡:QDA更灵活但也更容易过拟合,特别是在样本量不够大的时候。
LDA vs. QDA:偏差-方差权衡的经典案例 {{#sec-lda-qda-tradeoff}}
LDA 和 QDA 的选择是偏差-方差权衡 的教科书级案例:
LDA(高偏差,低方差)
假设所有类共享同一协方差矩阵
需要估计的参数:\(K\) 个均值 + \(1\) 个协方差 → \(O(Kp + p^2)\)
当真实边界确实是线性时,LDA 最优
小样本友好
QDA(低偏差,高方差)
允许每个类有自己的协方差矩阵
需要估计的参数:\(K\) 个均值 + \(K\) 个协方差 → \(O(Kp + Kp^2)\)
当类别分布差异大时,QDA 更准确
需要足够的样本量
经验法则 :当每个类的样本量 \(n_k\) 远大于特征维度 \(p\) 时,选 QDA;否则选 LDA。
LDA和QDA的关系就是偏差-方差权衡的缩影。LDA限制更强,可能有偏,但估计更稳定。QDA更灵活,偏差更小,但参数多了K倍,方差也大了。在金融数据中,我们通常样本量有限而特征较多,所以LDA往往是更安全的选择。
朴素贝叶斯:高维分类的实用利器
朴素贝叶斯 (Naive Bayes)做了一个大胆假设:给定类别后,特征之间相互独立 。
\[ \large{ P(X_1, \ldots, X_p \mid Y = k) = \prod_{j=1}^{p} P(X_j \mid Y = k) } \]
优势:
参数量从 \(O(p^2)\) 降到 \(O(p)\) ,大幅降低过拟合风险
计算速度极快,适合高维数据(如文本分类)
在许多实际场景中,分类效果出奇地好
局限:
独立性假设通常不严格成立
概率估计的准确性较差(但排序性能好,AUC 可能不受影响)
朴素贝叶斯的”朴素”在于它假设特征之间独立。这在现实中几乎不成立——比如公司的ROA和资产负债率肯定是有关联的。但令人惊讶的是,即使独立性假设不成立,朴素贝叶斯的分类效果往往仍然不错。这是因为分类只需要正确地排序后验概率,而不需要概率的绝对值完全准确。
朴素贝叶斯为何”朴素但有效”? {{#sec-nb-paradox}}
朴素贝叶斯的独立性假设几乎不成立,但它仍然有效。这个悖论的解释:
分类 ≠ 概率估计
分类只需要 \(P(Y=1\mid X)\) 和 \(P(Y=0\mid X)\) 的相对大小 正确
即使绝对概率值不准确,只要排序(ranking)不变,分类结果就是对的
维度灾难的天敌
在 \(p\) 维空间中,朴素贝叶斯只需估计 \(p\) 个一维分布
而完整模型需要估计 \(p\) 维联合分布 → 参数量呈指数增长
当 \(p\) 很大时(如文本分类中成千上万的词),朴素贝叶斯的”错误假设”反而比”正确模型但估不准”要好得多
金融应用 :上市公司研报情感分析(数千个词汇特征)、异常交易行为检测
朴素贝叶斯被称为”the most successful failure in machine learning”——最成功的失败模型。它的假设明显错误,但分类效果却出奇地好。关键在于:分类只需要概率的排序正确,而不需要概率的绝对值准确。在高维场景下,正确但复杂的模型反而因为参数太多而估不准,朴素贝叶斯的简单假设反而成了优势。
六种分类方法全景对比
逻辑回归
线性
好
强
中
需正则化
LDA
线性
中
中
好
中
QDA
二次
中
弱
差
差
朴素贝叶斯
非线性
差
中
好
好
KNN
非线性
差
弱
中
差
SVM
非线性
差
弱
中
中
金融实务指导 :
风控报审 → 逻辑回归(监管要求可解释)
小样本早期预警 → LDA
高维文本情感 → 朴素贝叶斯
这张表是本章的精华之一。六种方法各有千秋。金融行业的选择通常不仅仅看准确率——监管合规性和可解释性往往更关键。比如在中国的银行信贷审批中,逻辑回归是最主流的选择,因为监管要求模型必须能解释为什么拒绝了一个客户。
如何选择分类方法?一张决策流程图 {{#sec-method-selection}}
在实际项目中,选择分类方法的决策逻辑:
第一步:数据特征评估
样本量 \(n\) vs. 特征维度 \(p\) 的比值
类别是否平衡?
是否需要概率输出?
第二步:根据场景选择
监管要求可解释
逻辑回归
系数/几率比直接可解释
小样本 + 低维
LDA
参数少,稳定
大样本 + 非线性
QDA / SVM-RBF
灵活捕捉非线性
高维文本/稀疏数据
朴素贝叶斯
\(O(p)\) 参数量
探索性分析
KNN
无模型假设
第三步:交叉验证确认
不要仅凭理论选择——必须用交叉验证在你的数据 上验证各方法的表现。
方法选择不是一成不变的。在中国的金融实务中,逻辑回归是绝对的主流,因为银保监会要求风控模型必须可解释。但在量化投资领域,SVM和集成方法更受欢迎,因为那里更看重预测精度。
A 股 ST 预警实证:八种模型性能比较
基于本地 A 股财务数据构建 ST(特别处理)预测模型:
特征 :ROA(资产收益率)、资产负债率、对数总资产
标签 :公司是否被 ST(0=正常,1=ST)
方法 :逻辑回归、LDA、QDA、朴素贝叶斯、KNN(K=5)、KNN(K=20)、SVM线性核、SVM-RBF核
import pandas as pd # 导入pandas用于数据处理
import numpy as np # 导入numpy用于数值计算
import os # 导入os用于路径操作
import matplotlib.pyplot as plt # 导入matplotlib用于绑图
# 根据操作系统自动选择数据路径
DATA_ROOT = 'C:/qiufei/data' if os.name == 'nt' else '/home/ubuntu/r2_data_mount/qiufei/data' # 数据根目录
FINANCE_PATH = os.path.join(DATA_ROOT, 'stock/financial_statement.h5' ) # 财务报表数据路径
BASIC_PATH = os.path.join(DATA_ROOT, 'stock/stock_basic_data.h5' ) # 股票基本信息路径
financial_data_df = pd.read_hdf(FINANCE_PATH) # 读取财务报表数据
basic_info_df = pd.read_hdf(BASIC_PATH) # 读取股票基本信息
最后我们来做一个完整的实证案例。我们要用上市公司的财务数据来预测ST风险。在中国A股市场,ST是”特别处理”的标记,意味着公司存在财务异常。这是一个典型的不平衡二分类问题——ST公司只占全部上市公司的很小比例。
不平衡数据的挑战:准确率的”陷阱” {{#sec-imbalanced-data}}
在 ST 预警任务中,正常公司占比约 95%,ST 公司仅占 5%。
准确率悖论 :
一个什么都不做 的模型——永远预测”非ST”——准确率就能达到 95%!
准确率
95%
98%
召回率(ST)
0%
85%
商业价值
零
极高
因此,在不平衡场景下必须关注:
混淆矩阵 (Confusion Matrix):详细展示各类的分类情况
召回率 (Recall):真正的 ST 被识别出了多少?
精确率 (Precision):预测为 ST 的公司中有多少是真的?
AUC :不受阈值选择影响的综合指标
不平衡数据是金融分类中最常遇到的问题。在信贷违约预测中,坏账率通常不到5%。在ST预警中也是一样。如果你只看准确率,会被严重误导——一个永远预测”不违约”的模型准确率可能高达95%以上,但它毫无价值。必须深入看混淆矩阵和各类指标。
ST 预警实证:数据准备与特征工程
# 筛选2023年年报数据用于分析
financial_data_df = financial_data_df[financial_data_df['quarter' ] == '2023q4' ].copy() # 选取2023年年报
# 合并财务数据与ST标记
join_key = 'order_book_id' # 以股票代码作为合并键
merged_financial_data = pd.merge( # 内连接合并两张表
financial_data_df,
basic_info_df[[join_key, 'special_type' ]],
on= join_key, how= 'inner'
)
# 构造三个核心财务特征
merged_financial_data['roa' ] = merged_financial_data['net_profit' ] / merged_financial_data['total_assets' ] # ROA:衡量资产创利能力
merged_financial_data['debt_to_assets' ] = merged_financial_data['total_liabilities' ] / merged_financial_data['total_assets' ] # 资产负债率:衡量杠杆水平
merged_financial_data['log_size' ] = np.log10(merged_financial_data['total_assets' ] + 1 ) # 对数总资产:控制规模效应
# 数据清洗:去除异常值和缺失值
merged_financial_data = merged_financial_data.replace([np.inf, - np.inf], np.nan).dropna(subset= ['roa' , 'debt_to_assets' , 'log_size' ]) # 替换无穷值并删除缺失
merged_financial_data = merged_financial_data[(merged_financial_data['debt_to_assets' ] >= 0 ) & (merged_financial_data['debt_to_assets' ] <= 2 )] # 资产负债率限制在合理范围
merged_financial_data = merged_financial_data[merged_financial_data['total_assets' ] > 1e6 ] # 排除总资产过小的异常记录
ST 预警实证:模型训练与交叉验证
from sklearn.model_selection import train_test_split, cross_val_score # 导入数据切分与交叉验证工具
from sklearn.linear_model import LogisticRegression # 导入逻辑回归
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis, QuadraticDiscriminantAnalysis # 导入LDA和QDA
from sklearn.naive_bayes import GaussianNB # 导入朴素贝叶斯
from sklearn.neighbors import KNeighborsClassifier # 导入K近邻
from sklearn.svm import SVC # 导入支持向量机
from sklearn.preprocessing import StandardScaler # 导入标准化工具
# 构造ST标签:special_type含'ST'标记为1,否则为0
merged_financial_data['is_st' ] = merged_financial_data['special_type' ].fillna('Normal' ).str .contains('ST' ).astype(int ) # 根据special_type列判断是否为ST
features_matrix = merged_financial_data[['roa' , 'debt_to_assets' , 'log_size' ]].values # 提取特征矩阵
st_target_labels = merged_financial_data['is_st' ].values # 提取目标标签
# 分层抽样切分训练/测试集(70%/30%)
features_train, features_test, target_train, target_test = train_test_split( # 按ST比例分层抽样
features_matrix, st_target_labels, test_size= 0.3 , random_state= 42 , stratify= st_target_labels
)
# 特征标准化(对KNN和SVM至关重要)
scaler = StandardScaler() # 初始化标准化器
features_train_scaled = scaler.fit_transform(features_train) # 在训练集上拟合并转换
features_test_scaled = scaler.transform(features_test) # 用训练集参数转换测试集(防止数据泄露)
我们使用分层抽样将数据按70/30切分为训练集和测试集。分层抽样确保训练集和测试集中ST公司的比例相同。标准化对基于距离的方法如KNN和SVM非常重要——如果不做标准化,数值范围大的特征会主导距离计算。
ST 预警实证:八种模型评估结果
# 定义8种分类模型
models = { # 构建模型字典
'逻辑回归' : LogisticRegression(max_iter= 1000 ), # 逻辑回归,增大迭代次数防止不收敛
'LDA' : LinearDiscriminantAnalysis(), # 线性判别分析
'QDA' : QuadraticDiscriminantAnalysis(), # 二次判别分析
'朴素贝叶斯' : GaussianNB(), # 高斯朴素贝叶斯
'KNN(K=5)' : KNeighborsClassifier(n_neighbors= 5 ), # 5近邻
'KNN(K=20)' : KNeighborsClassifier(n_neighbors= 20 ), # 20近邻
'SVM线性' : SVC(kernel= 'linear' , probability= True ), # 线性核SVM
'SVM-RBF' : SVC(kernel= 'rbf' , probability= True ), # RBF核SVM
}
# 训练每个模型并记录结果
results = {} # 初始化结果字典
for name, model in models.items(): # 遍历所有模型
model.fit(features_train_scaled, target_train) # 拟合模型
test_score = model.score(features_test_scaled, target_test) # 测试集准确率
cv_scores = cross_val_score(model, features_train_scaled, target_train, cv= 5 ) # 5折交叉验证
results[name] = {'测试准确率' : test_score, 'CV均值' : cv_scores.mean(), 'CV标准差' : cv_scores.std()} # 存储结果
pd.DataFrame(results).T.round (4 ) # 转置并保留4位小数展示结果表
这张表展示了八种方法在ST预测上的表现。你会注意到所有方法的准确率都很高——这是因为样本严重不平衡,ST公司不到10%。所以即使什么都不做、全预测”非ST”,准确率也能达到90%以上。关键要看方法之间的相对差异和交叉验证的稳定性。
超越准确率:ROC 曲线与 AUC 的直觉 {{#sec-roc-auc}}
ROC 曲线 (Receiver Operating Characteristic)展示了分类器在不同阈值下的表现:
横轴 :假阳性率(FPR)= 被错误标为 ST 的正常公司比例
纵轴 :真阳性率(TPR)= 被正确识别的 ST 公司比例
对角线 :随机猜测的基准线
越靠左上角 :模型越好
AUC 的直觉解读 :
\[ \large{{ \text{{AUC}} = P(\hat{{p}}_{{\text{{ST}}}} > \hat{{p}}_{{\text{{非ST}}}}) }} \]
即:随机抽取一个 ST 公司和一个非 ST 公司,模型给 ST 公司更高风险评分的概率。
AUC = 0.5:和抛硬币一样
AUC = 0.7-0.8:可接受
AUC = 0.8-0.9:良好
AUC > 0.9:优秀
ROC曲线和AUC是评估分类器最重要的工具,特别是在不平衡数据场景中。AUC有一个非常直观的概率解释:如果你随机从正类和负类各抽一个样本,AUC就是模型能正确区分它们的概率。在金融风控中,AUC通常是模型选择的首要指标。
ST 预警可视化:测试集 vs. 交叉验证准确率
Code
# 配置中文字体
plt.rcParams['font.sans-serif' ] = ['Source Han Serif SC' , 'SimHei' , 'Arial Unicode MS' ] # 设置中文字体
plt.rcParams['axes.unicode_minus' ] = False # 解决负号显示问题
fig, ax = plt.subplots(figsize= (14 , 7 )) # 创建画布
methods = list (results.keys()) # 提取方法名列表
test_scores = [results[m]['测试准确率' ] for m in methods] # 各方法测试集准确率
cv_means = [results[m]['CV均值' ] for m in methods] # 各方法CV均值
cv_stds = [results[m]['CV标准差' ] for m in methods] # 各方法CV标准差
x = np.arange(len (methods)) # 分组柱状图的x轴位置
width = 0.35 # 柱子宽度
# 绘制分组柱状图
ax.bar(x - width/ 2 , test_scores, width, label= '测试集准确率' , color= 'steelblue' , alpha= 0.8 , edgecolor= 'black' ) # 测试集准确率柱
ax.bar(x + width/ 2 , cv_means, width, yerr= cv_stds, label= 'CV准确率(±1SD)' , color= 'coral' , alpha= 0.8 , edgecolor= 'black' , capsize= 5 ) # CV准确率柱(含误差线)
ax.set_xlabel('分类方法' , fontsize= 13 , fontweight= 'bold' ) # x轴标签
ax.set_ylabel('准确率' , fontsize= 13 , fontweight= 'bold' ) # y轴标签
ax.set_title('分类方法性能比较(ST 财务困境预测)' , fontsize= 14 , fontweight= 'bold' ) # 图标题
ax.set_xticks(x) # 设置x轴刻度位置
ax.set_xticklabels(methods, rotation= 45 , ha= 'right' ) # 设置刻度标签并旋转
ax.legend(fontsize= 11 , loc= 'lower right' ) # 添加图例
ax.set_ylim([0.7 , 1.0 ]) # 聚焦有效区间
ax.grid(True , alpha= 0.3 , axis= 'y' ) # 添加水平网格线
plt.tight_layout() # 自动调整布局
plt.show() # 显示图表
<Figure size 960x480 with 0 Axes>
从这张对比图可以清楚地看到,参数化方法如逻辑回归和LDA的测试集准确率和交叉验证准确率非常接近,说明泛化能力好。而KNN等非参数方法可能出现两者之间的差异,这是过拟合的信号。在不平衡数据场景下,简单的逻辑回归往往是最稳健的基线选择。
分类方法的实践检查清单 {{#sec-classification-checklist}}
在实际项目中应用分类方法时,请逐项检查:
数据层面 ✓
类别是否平衡?如果不平衡,是否使用了适当的评估指标(AUC/F1)?
特征是否需要标准化?(KNN、SVM 必须,逻辑回归/LDA 推荐)
是否有严重的多重共线性?(影响逻辑回归系数解释)
模型层面 ✓
是否需要概率校准?(朴素贝叶斯的概率通常偏极端)
阈值是否需要调整?(不平衡场景下 0.5 不一定最优)
是否做了交叉验证?(避免选择偏差)
业务层面 ✓
模型是否满足可解释性要求?(金融监管场景)
误分类的代价是否对称?(通常不是 → 考虑成本敏感学习)
模型是否在时间维度上稳定?(金融数据的分布会随时间漂移)
这张检查清单是你在实际项目中的”安全网”。很多学生在做课题时只关注模型的准确率,但在真实的金融场景中,数据质量、类别不平衡、可解释性、时间稳定性这些问题远比选用哪个算法更重要。
本章知识体系总结
最后我们用这张知识体系图来总结整章内容。分类方法分为两大范式:判别式方法直接建模后验概率,代表是逻辑回归和SVM;生成式方法通过建模似然和先验间接获得后验,代表是LDA、QDA和朴素贝叶斯。方法选择需要综合考虑样本量、维度、可解释性需求等因素。在金融实务中尤其要注意数据不平衡和概率校准的问题。