拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

线性判别分析LDA实战:二分类与多分类模型实现及特征可解释性解析

线性判别分析LDA实战:二分类与多分类模型实现及特征可解释性解析

写这篇文章的起因,是我最近在整理一个文本分类项目时,发现很多同学对LDA的印象还停留在"降维算法"上,一说分类就是逻辑回归、随机森林、XGBoost。其实线性判别分析(Linear Discriminant Analysis)在二分类和多分类任务里是被严重低估的,尤其是那种"多特征输入、单输出"的结构化表格数据,LDA不仅能做分类,还能帮你分析哪些特征真正区分了类别,一句话总结就是:又懂分类,又懂解释。这篇文章我就围绕一个完整的LDA二分类 + 多分类模型实现来拆,代码注释详细、换数据就能跑,重点把每一步的"为什么"讲透,适合正在做分类任务、想快速出一个可解释性强的baseline模型、或者被LDA原理困扰过的朋友参考。

1. 先搞清楚LDA到底解决什么问题

1.1 从Fisher判别说起:LDA不是简单的降维

很多教程把LDA和PCA放进同一章讲,因为两者都做投影、都降维。但它们的核心逻辑完全不同:PCA找的是方差最大的方向,不管数据属于哪个类别,是一种"无监督"视角;LDA找的是"让不同类别的中心尽量分开、每个类别内部的点尽量聚拢"的方向,本质上是带着标签去做投影的,是一种"有监督"判别方法。

让我用生活化的类比解释一下。假设你要区分两类水果——苹果和梨,你手里有两个特征:重量和甜度。PCA可能会告诉你"重量和甜度的综合评分方差最大"的方向,但这个方向未必能把苹果和梨分开;LDA则会计算出一个方向,在这个方向上苹果和梨的中心距离尽可能远,且各自内部的差异尽可能小。这个方向就是你做分类决策的"最有利投影轴"。

在二分类场景下,LDA做的其实是Fisher判别:找一个线性组合 $y = w_1 x_1 + w_2 x_2 + ... + w_n x_n$,使得投影后两类的类间散度(between-class scatter)与类内散度(within-class scatter)之比最大化。数学上就是最大化Fisher准则:

$J(w) = \frac{w^T S_B w}{w^T S_W w}$

其中 $S_B$ 是类间散度矩阵,$S_W$ 是类内散度矩阵。这个比值越大,说明投影后的类别越可分。

这个思想也直接解释了为什么LDA适合做"多特征输入单输出"的分类任务——它本质上是在回答"给定这些特征,怎么给每个样本打一个综合分,让这个分数在类别之间差异最大"。这个综合分就是一个线性表达式,业务人员能看懂,你也能从系数大小判断哪个特征贡献最大。

1.2 二分类和多分类的物理意义差异

LDA做二分类时,Fisher判别寻找一个投影方向,将高维特征映射到一维,然后在一维空间里找一个阈值完成分割。这个阈值通常按两类高斯分布的等后验概率点计算,源码里表现为使用类别的先验概率和投影后的均值、方差求决策边界。

做多分类时,情况更丰富一点。假设有K个类别,LDA会寻找最多 K-1 个判别方向(线性判别向量组),将高维数据投影到一个不超过K-1维的空间里再做分类。为什么是K-1?数学上的解释是:K个类别的均值点最多张成一个K-1维的仿射子空间。举个例子:3个类别的中心在三维空间里确定一个平面(2维),所以最多需要2个判别方向。

这意味着多分类LDA不仅给出了分类结果,还给了你一个可视化的机会——把样本投影到2维判别平面上查看类别分布情况,这在探索性数据分析阶段非常有用。项目标题里的"多特征输入单输出",落到实际就是:输入可能是几十维特征,输出只有一个类别标签(无论是二分类还是多分类),LDA天然契合这个结构。

1.3 LDA对数据的基本假设

用LDA前必须知道它的脾气,不然结果容易翻车。LDA有三个主要假设:

  • 各类别特征服从多元高斯分布
  • 各类别的协方差矩阵相同(同协方差)
  • 特征之间相关性不是太极端

实际项目里,完全满足这些假设的数据少之又少,但LDA对这些假设的偏离有一定容忍度。真正要注意的是特征尺度问题——LDA的判别方向严重依赖特征的量纲,如果某个特征的单位是"毫米",另一个是"万元",量纲大的特征会天然占主导。所以数据标准化在LDA里不是可选项,是必选项,这一点我稍后实操环节会重点演示。

另一个值得说的是:LDA是线性模型,它解决的是线性可分问题。如果数据呈现明显的非线性决策边界(比如环形、月牙形),LDA的表现会远不如随机森林或XGBoost。但我个人在实践中的体会是,很多业务场景的数据经过特征工程后,在特征空间里就是近似线性可分的,尤其是有序别变量、数值型指标构成的表格数据。先用LDA打底,再上复杂模型,这个思路在工业界非常常见。

2. 环境搭建与数据规范:多特征输入单输出的标准准备流程

2.1 工具选型:为什么用scikit-learn的LinearDiscriminantAnalysis

实现LDA不是什么难事,手写矩阵运算也就几十行代码,但生产环境我强烈建议直接用scikit-learn的LinearDiscriminantAnalysis。原因很简单:它封装了完整的求解流程,包括特征值分解、类内散度矩阵的收缩估计(shrinkage)、多种求解器切换,这些细节如果自己实现,容易在数值稳定性上踩坑。

接下来的代码示例基于Python 3.8+、scikit-learn 1.2+、pandas、numpy、matplotlib。项目结构建议这样组织:

lda_classifier/ ├── data/ │ └── raw_data.csv # 原始数据,一行一个样本 ├── main.py # 主程序,训练+评估 ├── preprocess.py # 数据清洗与标准化 └── requirements.txt # 依赖清单

requirements.txt核心依赖就这几行:

pandas>=1.5.0 numpy>=1.23.0 scikit-learn>=1.2.0 matplotlib>=3.6.0 seaborn>=0.12.0

2.2 数据的标准形态:一行为样本,一列为特征,最后一列为标签

"多特征输入单输出"的数据形态其实非常标准:每行一个样本,每列一个特征,最后一列是类别标签。拿到原始数据后,先不要急着建模,先做一个基础的探查:

import pandas as pd df = pd.read_csv("data/raw_data.csv") print(df.shape) print(df.head()) print(df["label"].value_counts())

这里要留意几个问题:

  • 特征列是否全部为数值类型?如果有字符串特征,要么做one-hot编码,要么改用其他支持类别特征的模型。
  • 标签列是否编码为连续的0, 1, 2...?sklearn的LDA支持字符串标签,但编码成整数更高效,也方便后续画混淆矩阵。
  • 有没有缺失值?LDA不能处理缺失值,需要填充或删除。

数据探查做完后,执行特征与标签分离:

X = df.drop("label", axis=1).values # 特征矩阵 y = df["label"].values # 标签向量 print("特征矩阵形状:", X.shape) print("标签数量:", len(y))

2.3 数据标准化:这一步决定LDA的下限

我在前面说过,LDA对量纲敏感,所以标准化是必须动作。常用的标准化工具有两种:

  • StandardScaler:将每个特征变为均值0、方差1
  • MinMaxScaler:将每个特征缩放到[0, 1]区间

LDA本身不依赖距离计算,理论上周中化处理更合适。但实践中我更喜欢StandardScaler,因为它保留了数据分布的形态,对异常值的处理比MinMaxScaler更稳健。

from sklearn.preprocessing import StandardScaler scaler = StandardScaler() X_scaled = scaler.fit_transform(X)

注意这里的fit_transform只能用在训练集上。测试集和未来新数据要用同一个scaler做transform,否则训练集和测试集的数据分布不一致,模型评估结果会虚高或失真。

2.4 数据集划分:先划分再标准化,顺序不能反

这是个经典低级错误:有人先对整个数据集做标准化,再切分训练集和测试集。这样做会把测试集的统计信息"泄露"到训练过程里,导致评估结果乐观偏差,上线后实际效果打折。

正确顺序是:

  1. 先用train_test_split切分得到 X_train, X_test, y_train, y_test
  2. 在 X_train 上fit标准化器,然后transform训练集和测试集
  3. 后续模型训练只接触训练集
from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split( X_scaled, y, test_size=0.2, random_state=42, stratify=y ) scaler = StandardScaler() X_train = scaler.fit_transform(X_train) X_test = scaler.transform(X_test)

stratify=y参数也很关键,它保证划分后训练集和测试集中各类别比例与原始数据一致,特别是多分类且类别不均衡时,这个参数能避免某一类比在测试集里彻底消失。

3. 二分类模型实现:从参数到决策边界的完整拆解

3.1 核心调用:fit、predict、predict_proba

二分类是LDA最直接的应用场景。数据准备好了之后,模型训练代码非常简洁:

from sklearn.discriminant_analysis import LinearDiscriminantAnalysis lda_binary = LinearDiscriminantAnalysis(solver="svd") lda_binary.fit(X_train, y_train) y_pred = lda_binary.predict(X_test) y_prob = lda_binary.predict_proba(X_test)

solver="svd"是默认的求解器,它使用奇异值分解对数据进行低秩分解,数值稳定性好,不需要显式计算协方差矩阵的逆,在特征维度不是特别高(比如几千以内)时表现优秀。如果你的特征是高维稀疏数据,可以试试solver="lsqr"配合shrinkage="auto",因为svd模式下shrinkage参数不可用。

predict_proba返回的是一个n行2列的数组,第一列是类别0的概率,第二列是类别1的概率。二分类LDA的概率是基于投影后的一维特征,用贝叶斯公式结合类先验和高斯似然算出来的。注意LDA有一个强假设:各类别投影后的方差相同。这意味着概率估计可能过于自信——实际业务中如果两类方差差异悬殊,建议再用逻辑回归对比一下概率校准情况。

3.2 模型评估:准确率、精确率、召回率与AUC

分类模型不能只看准确率,尤其是正负样本不均衡时。二分类场景下我固定输出一套评估指标:

from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, roc_auc_score accuracy = accuracy_score(y_test, y_pred) precision = precision_score(y_test, y_pred) recall = recall_score(y_test, y_pred) f1 = f1_score(y_test, y_pred) auc = roc_auc_score(y_test, y_prob[:, 1]) print(f"准确率: {accuracy:.4f}") print(f"精确率: {precision:.4f}") print(f"召回率: {recall:.4f}") print(f"F1分数: {f1:.4f}") print(f"AUC: {auc:.4f}")

这几个指标的分工要说清楚:

  • 准确率是全局正确率,适合类别均衡场景
  • 精确率是"预测为正类的样本中有多少是真的正类",误报代价高的场景(比如风控拦截)重点看它
  • 召回率是"真正的正类样本中有多少被找出来了",漏报代价高的场景(比如疾病筛查)重点看它
  • F1是精确率和召回率的调和平均,两者都不想取舍时看它
  • AUC衡量的是模型的排序能力,不依赖分类阈值,适合评估模型本身的好坏

3.3 判别方向的含义:LDA系数告诉你特征的重要性

二分类LDA训练完成后,lda_binary.coef_是一个形状为(1, n_features)的数组,它就是我们前面说的投影向量w。系数的绝对值越大,对应特征对分类决策的贡献越大。

这里有一个非常实用的可视化方法:把系数画成水平条形图,按绝对值排序,一眼就能看出模型到底"靠什么"区分两个类别。

import matplotlib.pyplot as plt import numpy as np coef = lda_binary.coef_[0] feature_names = df.drop("label", axis=1).columns indices = np.argsort(np.abs(coef))[::-1] top_n = 15 plt.figure(figsize=(10, 8)) plt.barh(range(top_n), coef[indices][:top_n], color="steelblue") plt.yticks(range(top_n), [feature_names[i] for i in indices[:top_n]]) plt.xlabel("LDA系数") plt.title("特征对二分类决策的贡献度") plt.gca().invert_yaxis() plt.tight_layout() plt.savefig("lda_binary_coef.png", dpi=150)

注意这里的系数是在标准化后的特征空间里计算的,所以系数之间可以直接比大小。如果用的是未标准化数据,系数绝对值没有可比性,这一点很多资料不提,实际中却极其重要。

LDA系数还有一个隐含的业务价值:正系数表示该特征增大时样本更偏向正类,负系数表示更偏向负类。这在信贷风控、客户流失预测、医疗诊断等场景里可以直接转化为业务规则。举个例子,我做过一个客户流失预测项目,LDA系数最大的特征是"最近一次登录距今天数",系数为正,说明登录间隔越长,流失概率越高——这个结论直接拿到了运营部门做用户唤醒策略,比黑盒模型的Shapley值解释起来省力得多。

3.4 决策边界可视化:投影到一维后什么样

二分类LDA的最终决策其实是在一维坐标轴上完成的。你可以把训练样本投影到 w 方向上,然后画出两个类别的分布直方图,直观看到分离效果:

train_proj = X_train @ lda_binary.coef_.T plt.figure(figsize=(12, 4)) plt.hist(train_proj[y_train == 0], bins=30, alpha=0.7, label="类别0", color="skyblue") plt.hist(train_proj[y_train == 1], bins=30, alpha=0.7, label="类别1", color="salmon") plt.xlabel("LDA投影值") plt.ylabel("样本数") plt.legend() plt.title("训练集样本在LDA方向上的分布") plt.savefig("lda_binary_projection.png", dpi=150)

两个直方图重叠越小,说明分类边界越清晰。重叠部分的面积大致对应着分类错误的样本比例。这个可视化对非技术背景的同事特别友好,比一堆指标更直观。

4. 多分类LDA:K个类别如何一次性分开

4.1 多分类的求解:K-1个判别方向与分类规则

多分类LDA和二分类的区别在于:二分类只求一个最优投影方向,多分类则求一组最多K-1个判别方向。这些方向共同构成一个新的特征空间,样本在这个空间里的位置就是它的"判别特征向量"。

sklearn的LinearDiscriminantAnalysis在多分类下默认用svd求解,等价于先对数据做QR分解再对类间散度矩阵做特征值分解。最终得到的lda.scalings_矩阵形状为(n_features, n_components),每一列是一个判别方向。

分类规则方面,多分类LDA用的是一套"类条件高斯 + 共享协方差"的贝叶斯分类器。在新特征空间里,对每个类别分别计算样本点到类别中心的马氏距离,结合先验概率,选择后验概率最大的类别作为预测结果。

这就解释了为什么多分类LDA天然支持"单输出"——判断结果只有一个类别标签,每个类别之间是互斥的。

4.2 多分类完整代码:训练、预测、评估一条龙

多分类的代码和二分类基本一致,区别主要在评估环节。下面给出完整实现:

from sklearn.discriminant_analysis import LinearDiscriminantAnalysis from sklearn.metrics import classification_report, confusion_matrix, accuracy_score lda_multi = LinearDiscriminantAnalysis(solver="svd") lda_multi.fit(X_train, y_train) y_pred_multi = lda_multi.predict(X_test) acc_multi = accuracy_score(y_test, y_pred_multi) print(f"多分类准确率: {acc_multi:.4f}") print(classification_report(y_test, y_pred_multi))

classification_report会输出每个类别的精确率、召回率、F1分数,以及宏平均(macro avg)和加权平均(weighted avg)。当类别分布不均衡时,重点看macro avg和weighted avg的差异:差异越大,说明模型在小类别上的表现越差。

4.3 多分类混淆矩阵:核心热词代码详解

多分类模型比二分类更复杂,只看准确率远远不够,用一个混淆矩阵可以快速定位"哪些类别经常被混淆"。这里给出一个可以直接套用的Python代码:

import matplotlib.pyplot as plt from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay cm = confusion_matrix(y_test, y_pred_multi) disp = ConfusionMatrixDisplay(confusion_matrix=cm) disp.plot(cmap="Blues", values_format="d") plt.title("多分类LDA混淆矩阵") plt.savefig("lda_multi_confusion_matrix.png", dpi=150)

如果你更喜欢seaborn风格控制颜色和标注,也可以用下面这个版本:

import seaborn as sns import matplotlib.pyplot as plt import numpy as np cm = confusion_matrix(y_test, y_pred_multi) plt.figure(figsize=(8, 6)) sns.heatmap(cm, annot=True, fmt="d", cmap="Blues", xticklabels=lda_multi.classes_, yticklabels=lda_multi.classes_) plt.xlabel("预测标签") plt.ylabel("真实标签") plt.title("多分类LDA混淆矩阵") plt.tight_layout() plt.savefig("lda_multi_confusion_matrix_seaborn.png", dpi=150)

怎么读这个混淆矩阵?矩阵的第i行第j列表示真实类别i被预测成类别j的样本数。对角线越多、颜色越深越好。如果某个类别大量被预测成另一个特定类别,说明这两个类在特征空间里高度重叠,可以考虑增加特征、做特征交互,或者对数据做重采样增强这两个类别的区分度。

4.4 判别空间可视化:把多分类样本画在2D平面上

多分类LDA一个很大的优势是:如果类别数K >= 3,模型天然会产出K-1个判别方向。当K=3时,K-1=2,你可以把全部样本投影到二维平面上,画一个类似PCA的散点图,但聚类效果往往比PCA更好,因为LDA的方向是"为了区分类别"而优化的。

X_proj = lda_multi.transform(X_train) plt.figure(figsize=(8, 6)) for cls in np.unique(y_train): mask = y_train == cls plt.scatter(X_proj[mask, 0], X_proj[mask, 1], label=f"类别{cls}", alpha=0.7, s=30) plt.xlabel("判别方向1") plt.ylabel("判别方向2") plt.legend() plt.title("训练集在LDA判别空间中的分布") plt.savefig("lda_multi_projection.png", dpi=150)

这个图在实际项目中价值极高。假设你做的是设备故障诊断,原始特征有几十个,你很难理解这些特征和故障类型的关系。但投影到LDA判别平面后,你会看到不同故障类型各自聚成一团,这既是对模型的验证,也是对业务人员的直观解释。

如果你的数据有4个或更多类别,判别方向会超过2个,这时候可以画两两方向的散点图矩阵,或者用前两个方向做主视图,再补充一个t-SNE图作为对比。

5. 实战对比:LDA、逻辑回归与XGBoost的定位差异

5.1 什么时候LDA胜出,什么时候它明显不行

做分类任务时,算法选型是一个老生常谈的问题。我的建议是把LDA放在"解释性要求高、数据量不太大、线性近似成立"的三维坐标里来评估。

LDA明显胜出的时候:

  • 数据量小,几百到几千条样本。LDA估计参数时充分使用所有特征的类内散度信息,比树模型更高效
  • 特征维度中等(几十到几百),且特征间相关性不是特别强
  • 业务方需要解释"到底哪些特征在区分类别",LDA的系数天然可读
  • 需要快速出baseline,LDA训练几乎是瞬间完成

LDA明显不行的时候:

  • 特征维数远大于样本数(比如基因表达数据,几万特征几十个样本),协方差矩阵估计会崩,需要专门的改良版本如正则化LDA或先用PCA降维
  • 数据呈明显的非线性决策边界,比如周期性数据、交互效应显著的数据
  • 类别数量非常多且样本分布极度不均衡

5.2 与逻辑回归的关系:名字不同,亲缘很近

逻辑回归和LDA在分类机制上有相似之处,两者都学习线性决策边界。重要区别在于估计方式:逻辑回归直接建模类后验概率P(y|x),不对特征分布做假设;LDA先估计类条件分布P(x|y),再用贝叶斯公式反推后验概率,本质是生成式模型。

这个理论区别落地到实践中表现为:当数据满足LDA假定时(各类特征近似高斯、协方差相近),LDA比逻辑回归更高效、在小样本下更稳定;当数据分布明显偏斜、协方差差异大时,逻辑回归更稳健。

我在实际项目里经常两个模型都跑一遍,如果两者效果接近,优先用LDA因为可解释性好;如果差异明显,分析差异原因的过程往往能揭示数据的重要性质,比如某个类别的方差远大于另一个类别。

5.3 XGBoost是备选不是替代

热词里有"xgboost二分类模型",这说明很多人在选择分类算法时把XGBoost当成默认选项。XGBoost当然很强——它擅长捕捉非线性关系和特征交互,在大型数据集上通常碾压线性模型。但你要清楚它的代价:

  • 参数多(学习率、树深、样本采样、特征采样等),调参成本高,容易过拟合小样本
  • 模型可解释性较差,需要依赖SHAP等工具
  • 训练时间远高于LDA,在小数据上提升往往有限

我的经验法则是:样本量少于5000时,先跑LDA;如果LDA的AUC/F1已经达到业务指标,就没必要上XGBoost增加复杂度。如果LDA效果不够,再上XGBoost作为强基准,同时协同SHAP做特征解释。这个流程既高效又稳妥,也符合奥卡姆剃刀原则。

6. 常见问题与排查技巧实录

6.1 问题速查表

常见错误现象原因解决方法
准确率虚高训练集全对,测试集很差先整体标准化再划分,数据泄露先切分再标准化,确保测试集信息不参与训练
特征贡献无法比较系数值极大或极小未标准化,量纲主导使用StandardScaler标准化后重新训练
模型报错说无法收敛程序直接崩溃特征矩阵含NaN或无穷值用np.isfinite()检查,填充或删除异常值
多分类混淆矩阵显示某一类全错某个类别预测结果全部集中到另一类类别不均衡或特征无法区分重采样、调整类别权重、增加特征
概率结果过于自信predict_proba接近0或1LDA同协方差假设导致概率校准偏差交叉验证下比较逻辑回归的概率校准图
特征维度远多于样本数模型训练极慢或结果异常协方差矩阵奇异不可逆先降维(PCA/特征选择),或用带shrinkage的LDA

6.2 一通百通的调试清单

我每次跑LDA,不管什么数据,都会按这个清单走一遍:

  1. 先打印X的形状和y的类别分布,确认数据形态
  2. 检查X中是否有NaN、无穷值,用np.isnan(X).any()和np.isinf(X).any()扫一遍
  3. 确认标准化只基于训练集fit,测试集只transform
  4. 训练完成后,打印classification_report查看每个类别的精确率和召回率,而不是只看准确率
  5. 画出混淆矩阵,定位容易被混淆的类别对
  6. 检查LDA系数图的Top特征,判断是否符合业务常识——如果LDA认为"客户年龄"对"是否购买"毫无影响且系数几乎为0,而业务经验说影响很大,优先检查数据质量而不是质疑模型

6.3 效果不好时怎么改

如果LDA效果达不到你的预期,第一个动作不是换模型,而是回到特征本身。我踩过的坑里,下面几个方向最有效:

  • 检查特征是否真的对类别有区分度,用单变量F检验(f_classif)逐个看p值,剔除明显无区分度的特征
  • 考虑特征交互。LDA是线性模型,如果你确信特征A和特征B的组合才对类别有区分性,手动构造一个新特征A*B或A/B加入模型,往往能显著提升效果
  • 对类别不均衡数据尝试采样策略,比如SMOTE过采样少数类
  • 尝试LinearDiscriminantAnalysis(shrinkage="auto"),对协方差矩阵做收缩估计,缓解特征相关性和大方差造成的数值不稳定

6.4 和交叉验证结合:别相信单次划分的结果

单次train_test_split的结果波动可能很大,特别是在小样本场景下。我更推荐用交叉验证来评估LDA的真实水平:

from sklearn.model_selection import cross_val_score scores = cross_val_score(lda_multi, X_scaled, y, cv=5, scoring="accuracy") print(f"5折交叉验证准确率: {scores.mean():.4f} ± {scores.std():.4f}")

这里我把交叉验证放在了标准化之前,存在轻微的数据泄露(标准化器在每一折都接触了整份数据),但实际操作中这个问题对LDA影响较小,因为LDA对数据平移缩放不敏感。如果你追求严格的评估,可以把标准化器和模型放在一个Pipeline里:

from sklearn.pipeline import make_pipeline pipe = make_pipeline(StandardScaler(), LinearDiscriminantAnalysis()) scores = cross_val_score(pipe, X, y, cv=5, scoring="accuracy") print(f"Pipeline交叉验证准确率: {scores.mean():.4f} ± {scores.std():.4f}")

这样每一折都在训练折叠内部完成标准化和模型训练,评估结果更可信。

这个项目做完之后我有一个蛮深的体会:LDA这个模型看起来"传统",但它在工业scenario里远没有过时。它训练快、可解释性强、对小型结构化数据友好,还天然给出特征的判别方向,这些能力在今天很多"高大上"的模型里反而难找。用它做baseline,再决定是否需要复杂模型,这个流程我用过很多次,每次都帮我省下不少时间。如果你也正在做分类项目,我建议先把这个模型跑通,把所有指标、可视化、特征系数观察一遍,再决定下一步往哪里走——很多问题其实在跑完LDA后就有了答案。

返回列表