完成代码
#第七章 判别分析算法
#7.2.1 载入分析所需要的模块和函数
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
from sklearn.discriminant_analysis import QuadraticDiscriminantAnalysis
from sklearn.metrics import confusion_matrix
from sklearn.metrics import classification_report
from sklearn.metrics import cohen_kappa_score
from mpl_toolkits.mplot3d import Axes3D
from sklearn.datasets import make_classification
from sklearn.decomposition import PCA
#7.2.2 线性判别分析降维优势展示
#绘制三维数据的分布图
X, y = make_classification(n_samples=500, n_features=3, n_redundant=0,
n_classes=3, n_informative=2, n_clusters_per_class=1,
class_sep=0.5, random_state=100)#生成三类三维特征的数据
plt.rcParams['axes.unicode_minus']=False# 解决负号不显示问题
fig = plt.figure()
ax = Axes3D(fig, rect=[0, 0, 1, 1], elev=20, azim=20)
ax.scatter(X[:, 0], X[:, 1], X[:, 2], marker='o', c=y)
#使用PCA进行降维
pca = PCA(n_components=2)
pca.fit(X)
print(pca.explained_variance_ratio_)
print(pca.explained_variance_)
X_new = pca.transform(X)
plt.scatter(X_new[:, 0], X_new[:, 1], marker='o', c=y,s=50)
plt.show()
#使用LDA进行降维
lda = LinearDiscriminantAnalysis()
lda.fit(X, y)
X_new = lda.transform(X)
plt.scatter(X_new[:, 0], X_new[:, 1], marker='o', c=y)
plt.show()#降维后样本特征信息之间的关系得以保留
#7.2.3 数据读取及观察
data=pd.read_csv(r'数据7.1.csv')
data.info()
len(data.columns)
data.columns
data.shape
data.dtypes
data.isnull().values.any()
data.isnull().sum()
data.head()
data.V1.value_counts()
#7.3 特征变量相关性分析
X = data.drop(['V1'],axis=1)#设置特征变量,即除V1之外的全部变量
y = data['V1']#设置响应变量,即V1
X.corr()
sns.heatmap(X.corr(), cmap='Blues', annot=True)
#7.4 使用样本示例全集开展线性判别分析
#7.4.1 模型估计及性能分析
# 使用样本示例全集开展LDA
model = LinearDiscriminantAnalysis()#使用LDA算法
model.fit(X, y)#使用fit方法进行拟合
model.score(X, y)
model.priors_
model.means_
np.set_printoptions(suppress=True)#不以科学计数法显示,而是直接显示数字
model.coef_#输出模型系数
model.intercept_#输出模型截距项
model.explained_variance_ratio_#输出可解释方差比例
model.scalings_
lda_scores = model.fit(X, y).transform(X)
lda_scores.shape
lda_scores[:5, :]
LDA_scores = pd.DataFrame(lda_scores, columns=['LD1', 'LD2'])
LDA_scores['网点类型'] = data['V1']
LDA_scores.head()
d = {0: '未转型网点', 1: '一般网点', 2: '精品网点'}
LDA_scores['网点类型'] = LDA_scores['网点类型'].map(d)
LDA_scores.head()
plt.rcParams['axes.unicode_minus']=False# 解决图表中负号不显示问题
plt.rcParams['font.sans-serif'] = ['SimHei']#解决图表中中文显示问题。
sns.scatterplot(x='LD1', y='LD2', data=LDA_scores, hue='网点类型')
#7.4.2 运用两个特征变量绘制LDA决策边界图
#安装mlxtend
#pip --default-timeout=123 install mlxtend#大家在运行时把前面的“#”去掉,可能时间较长,需耐心等待
from mlxtend.plotting import plot_decision_regions#导入plot_decision_regions
X2 = X.iloc[:,0:2]#仅选取V2存款规模、V3EVA作为特征变量
model = LinearDiscriminantAnalysis()#使用LDA算法
model.fit(X2, y)#使用fit方法进行拟合
model.score(X2, y)
model.explained_variance_ratio_
plot_decision_regions(np.array(X2), np.array(y), model)
plt.xlabel('存款规模')#将x轴设置为'存款规模'
plt.ylabel('EVA')#将y轴设置为'EVA'
plt.title('LDA决策边界')#将标题设置为'LDA决策边界'
#7.5 使用分割样本开展线性判别分析
X_train, X_test, y_train, y_test = train_test_split(X,y,test_size=0.3, stratify=y, random_state=123)
model = LinearDiscriminantAnalysis()#使用LDA算法
model.fit(X_train, y_train)#基于训练样本使用fit方法进行拟合
model.score(X_test, y_test)#基于测试样本计算模型预测的准确率
prob = model.predict_proba(X_test)
prob[:5]
pred = model.predict(X_test)
pred[:5]
confusion_matrix(y_test, pred)#输出测试样本的混淆矩阵
print(classification_report(y_test, pred))
cohen_kappa_score(y_test, pred)
#7.6 使用分割样本开展二次判别分析
#7.6.1 模型估计
model = QuadraticDiscriminantAnalysis()#使用QDA算法
model.fit(X_train, y_train)#基于训练样本使用fit方法进行拟合
model.score(X_test, y_test)#计算模型预测的准确率
prob = model.predict_proba(X_test)
prob[:5]
pred = model.predict(X_test)
pred[:5]
confusion_matrix(y_test, pred)
print(classification_report(y_test, pred))
cohen_kappa_score(y_test, pred)#计算cohen_kappa得分
#7.6.2 运用两个特征变量绘制QDA决策边界图
X2 = X.iloc[:, 0:2]
model = QuadraticDiscriminantAnalysis()
model.fit(X2, y)
model.score(X2, y)
plot_decision_regions(np.array(X2), np.array(y), model)
plt.xlabel('存款规模')#将x轴设置为'存款规模'
plt.ylabel('EVA')#将y轴设置为'EVA'
plt.title('QDA决策边界')#将标题设置为'QDA决策边界'
#绘图
数据准备
以“数据7.1”文件中的数据为例进行讲解。“数据7.1”文件记录的是某商业银行在山东地区的部分支行的经营数据(虚拟数据,不涉及商业秘密),案例背景是该商业银行正在推动支行开展转型,实现所有支行的做大做强。
数据文件中的变量包括这些商业银行全部支行的V1(转型情况)、V2(存款规模)、V3(EVA)、V4(中间业务收入)、V5(员工人数)。V1(转型情况)又分为3个类别:“0”表示“未转型网点”,“1”表示“一般网点”,“2”表示“精品网点”。“数据7.1”文件中的数据内容如图所示。
下面以V1(转型情况)为响应变量,以V2(存款规模)、V3(EVA)、V4(中间业务收入)、V5(员工人数)为特征变量,构建线性判别分析(Linear Discriminant Analysis, LDA)模型。
1 导入分析所需要的模块和函数
在进行分析之前,首先导入分析所需要的模块和函数,读取数据集并进行观察。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
from sklearn.discriminant_analysis import QuadraticDiscriminantAnalysis
from sklearn.metrics import confusion_matrix
from sklearn.metrics import classification_report
from sklearn.metrics import cohen_kappa_score
from mpl_toolkits.mplot3d import Axes3D
from sklearn.datasets import make_classification
from sklearn.decomposition import PCA
2 线性判别分析降维优势展示
前面提到线性判别分析不仅可以用来进行任务分类,还可以进行降维处理。由于线性判别分析降维的依据是贝叶斯规则,充分利用了既有分类信息,因此在降维时可以很好地保存样本特征和类别的信息关联。
下面我们先通过生成的数据进行演示,对比线性判别分析降维和PCA降维。
1.绘制三维数据的分布图
首先生成一组三维数据,并通过绘制图形的方式观察其特征。
#绘制三维数据的分布图
X, y = make_classification(n_samples=500, n_features=3, n_redundant=0,
n_classes=3, n_informative=2, n_clusters_per_class=1,
class_sep=0.5, random_state=100)#生成三类三维特征的数据
plt.rcParams['axes.unicode_minus']=False# 解决负号不显示问题
fig = plt.figure()
ax = Axes3D(fig, rect=[0, 0, 1, 1], elev=20, azim=20)
ax.scatter(X[:, 0], X[:, 1], X[:, 2], marker='o', c=y)
2.使用PCA进行降维
#使用PCA进行降维
pca = PCA(n_components=2)
pca.fit(X)
print(pca.explained_variance_ratio_)
print(pca.explained_variance_)
-
使用主成分分析(Principal Component Analysis,PCA)进行数据降维。
-
pca = PCA(n_components=2)
:- 创建一个
PCA
对象,PCA
是 scikit-learn 库中用于主成分分析的类。 n_components=2
参数指定将数据降维到 2 个主成分。这意味着经过 PCA 处理后,原始数据将被转换为只有两个特征的新数据集。
- 创建一个
-
pca.fit(X)
:- 使用输入数据
X
来拟合 PCA 模型。X
通常是一个二维数组,其中每一行代表一个样本,每一列代表一个特征。 - 在这个步骤中,PCA 算法会计算数据的协方差矩阵,并确定能够最大程度地保留数据方差的主成分方向。
- 使用输入数据
-
print(pca.explained_variance_ratio_)
:- 打印出每个主成分解释的方差比例。
explained_variance_ratio_
是一个属性,它是一个数组,其中每个元素表示相应主成分解释的方差占总方差的比例。例如,如果有两个主成分,这个数组可能是[0.7, 0.2]
,表示第一个主成分解释了 70% 的方差,第二个主成分解释了 20% 的方差。
-
print(pca.explained_variance_)
:- 打印出每个主成分解释的方差值。
explained_variance_
是一个属性,它是一个数组,其中每个元素表示相应主成分解释的方差大小。方差越大,说明该主成分在数据中的重要性越高。
结果:
可以发现第一主成分能够解释的方差比例为50.10%,第二主成分能够解释的方差比例为35.12%,提取的两个主成分能够涵盖初始变量中的大部分信息。
使用PCA降维后的散点图:
从图中可以发现两点:
一是PCA分析将原始的三维特征数据成功降维成了二维数据,在图形上的直观表现就是将立体化的数据展现到了一个平面上,横轴和纵轴分别是第一主成分和第二主成分,各个散点反映的是样本;
二是PCA分析降维方法并未保留样本特征和类别的信息关联,体现在各种类型的样本散点混合在一起。
3.使用LDA进行降维
#使用LDA进行降维
lda = LinearDiscriminantAnalysis()
lda.fit(X, y)
X_new = lda.transform(X)
plt.scatter(X_new[:, 0], X_new[:, 1], marker='o', c=y)
plt.show()#降维后样本特征信息之间的关系得以保留
-
使用线性判别分析(Linear Discriminant Analysis,LDA)进行数据降维。
-
lda = LinearDiscriminantAnalysis()
:- 创建一个
LinearDiscriminantAnalysis
对象,这是 scikit-learn 库中用于线性判别分析的类。
- 创建一个
-
lda.fit(X, y)
:- 使用输入数据
X
和对应的类别标签y
来拟合 LDA 模型。 X
通常是一个二维数组,其中每一行代表一个样本,每一列代表一个特征。y
是一个一维数组,包含每个样本的类别标签。- 在这个步骤中,LDA 算法会计算类内散度矩阵和类间散度矩阵,并确定能够最大程度地分离不同类别数据的投影方向。
- 使用输入数据
-
X_new = lda.transform(X)
:- 使用已经拟合好的 LDA 模型对输入数据
X
进行降维变换,得到降维后的新数据X_new
。 X_new
的维度通常会小于原始数据X
的维度,具体取决于 LDA 模型的设置。
- 使用已经拟合好的 LDA 模型对输入数据
-
plt.scatter(X_new[:, 0], X_new[:, 1], marker='o', c=y)
:- 使用
matplotlib
的scatter
函数绘制降维后的数据点。 X_new[:, 0]
和X_new[:, 1]
分别表示降维后数据的第一维和第二维特征。marker='o'
设置数据点的标记样式为圆形。c=y
根据类别标签y
为数据点设置不同的颜色。
- 使用
-
plt.show()
:- 显示绘制的图形,展示降维后样本特征信息之间的关系。
3 数据读取及观察
data=pd.read_csv(r'数据7.1.csv')
data.info()
len(data.columns)
data.columns
data.shape
data.dtypes
data.isnull().values.any()
data.isnull().sum()
data.head()
data.V1.value_counts()
即数据集中共有48个样本(48 entries, 0 to 47)、5个变量(total 5columns)。5个变量分别是V1~V5,均包含48个非缺失值(48non-null),其中V1、V5的数据类型为整型(int64),V2、V3、V4的数据类型为浮点型(float64)。数据文件中共有3个浮点型(float64)变量、2个整型(int64)变量,数据内存为2.0KB。
即“0”表示“未转型网点”,样本个数为25个;“1”表示“一般网点”,样本个数为18个;“2”表示“精品网点”,样本个数为5个。
以V1(转型情况)为响应变量,以V2(存款规模)、V3(EVA)、V4(中间业务收入)、V5(员工人数)为特征变量,构建线性判别分析(Linear Discriminant Analysis, LDA)模型。
3 特征变量相关性分析
X = data.drop(['V1'],axis=1)#设置特征变量,即除V1之外的全部变量
y = data['V1']#设置响应变量,即V1
X.corr()
sns.heatmap(X.corr(), cmap='Blues', annot=True)
-
X = data.drop(['V1'], axis=1)
:- 这里从名为
data
的数据集(可能是一个pandas
的DataFrame
)中删除名为'V1'
的列,并将剩余的列赋值给变量X
,作为特征变量集合。使用drop
方法时,axis=1
表示按列进行删除操作。
- 这里从名为
-
y = data['V1']
:- 从
data
中提取名为'V1'
的列,并将其赋值给变量y
,作为响应变量。
- 从
-
X.corr()
:- 计算特征变量集合
X
中各列之间的相关性。这会返回一个相关性矩阵,其中每个元素表示相应两列之间的相关系数。
- 计算特征变量集合
-
sns.heatmap(X.corr(), cmap='Blues', annot=True)
:- 使用
seaborn
库的heatmap
函数绘制特征变量相关性的热力图。 X.corr()
作为参数传入,表示要绘制的相关性矩阵数据。cmap='Blues'
设置热力图的颜色映射为蓝色系。annot=True
表示在热力图的每个单元格中显示相关系数的具体数值。
- 使用
4 使用样本全集开展线性判别分析
# 使用样本示例全集开展LDA
model = LinearDiscriminantAnalysis()#使用LDA算法
model.fit(X, y)#使用fit方法进行拟合
model.score(X, y)
model.priors_
model.means_
np.set_printoptions(suppress=True)#不以科学计数法显示,而是直接显示数字
model.coef_#输出模型系数
model.intercept_#输出模型截距项
model.explained_variance_ratio_#输出可解释方差比例
model.scalings_
-
使用全部样本数据进行线性判别分析(LDA)。
-
model = LinearDiscriminantAnalysis()
:- 创建一个
LinearDiscriminantAnalysis
对象,即初始化一个 LDA 模型。
- 创建一个
-
model.fit(X, y)
:- 使用特征变量
X
和响应变量y
对 LDA 模型进行拟合。在这个过程中,模型会计算类内散度矩阵和类间散度矩阵,并确定能够最大程度地分离不同类别数据的投影方向。
- 使用特征变量
-
model.score(X, y)
:- 计算模型在给定数据
X
和y
上的得分。
- 计算模型在给定数据
-
model.priors_
:- 返回每个类别的先验概率。先验概率是在没有看到任何数据之前对不同类别出现的概率的估计。
-
model.means_
:- 返回每个类别的特征均值向量。这可以帮助我们了解不同类别的数据在特征空间中的中心位置。
-
np.set_printoptions(suppress=True)
:- 设置
numpy
的打印选项,使得输出不以科学计数法显示,而是直接显示数字。这可以使输出更加易读。
- 设置
-
model.coef_
:- 返回模型的系数。在 LDA 中,系数表示投影方向,可以用于将原始数据投影到低维空间。
-
model.intercept_
:- 返回模型的截距项。在某些情况下,模型可能需要一个截距项来进行预测。
-
model.explained_variance_ratio_
:
- 返回每个线性判别(主成分)解释的方差比例。类似于主成分分析(PCA)中的解释方差比例,这个值可以帮助我们了解每个线性判别对数据方差的解释程度。
11.model.scalings_
:
- 返回特征的缩放因子。这些缩放因子可以用于将原始数据标准化,以便更好地进行模型拟合和预测。
计算模型预测准确率,运行结果为:0.8333333333333334,说明模型预测的准确率在 83.33%。
先验概率是指基于既有样本分类计算的分布概率,“未转型网点”的先验概率为52.08%,“一般网点”的先验概率为37.5%,“精品网点”的先验概率为10.42%。
未转型网点中,V2(存款规模)、V3(EVA)、V4(中间业务收入)、V5(员工人数)的均值分别为1802.276,562.3628,115.990712,40.84;
一般网点中,V2(存款规模)、V3(EVA)、V4(中间业务收入)、(V5员工人数)的均值分别为2608.84166667,895.94333333,284.68953333,37.27777778;
精品网点中,V2(存款规模)、V3(EVA)、V4(中间业务收入)、V5(员工人数)的均值分别为5163.62,1222.01,673.16048,38.2。
基于模型系数和常数项,我们可以写出线性分类函数方程,有多少个分类就有多少个线性分类函数。
● 未转型网点:
V1=-0.00091301×V2-0.00510986×V3-0.00132272×V4+0.00811066×V5+4.56877967
● 一般网点:
V1=0.00044724×V2+0.00318443×V3+0.00005389×V4-0.01101929×V5-4.33624197
● 精品网点:
V1=0.00295497×V2+0.01408534×V3+0.0064196×V4-0.00088386×V5-30.33779818
第一线性判元的可解释组间方差比例为0.98316198,第二线性判元可解释方差组间比例为0.01683802,或者说,第一线性判元对于样本类别的区分度很高。
输出线性判别系数(注意“线性判别系数”不同于前面所提的“分类函数系数”),
线性判别系数即线性判元对于特征变量的载荷,也是原理讲解部分提到的权重系数w,其中第一线性判元在V2(存款规模)、V3(EVA)、V4(中间业务收入)、V5(员工人数)上的载荷分别为-0.00070198、-0.00362065、-0.00128565、0.00304935,即运行结果的第一列;第二线性判元在V2(存款规模)、V3(EVA)、V4(中间业务收入)、V5(员工人数)上的载荷分别为-0.0001132、0.00263812、-0.00301653、-0.03282909,即运行结果的第二列。
5 运用两个特征变量绘制LDA决策边界图
首先需要安装mlxtend,代码如下:
pip --default-timeout=123 install mlxtend
如果安装不成功可尝试以下代码:
conda install mlxtend --channel conda-forge
from mlxtend.plotting import plot_decision_regions#导入plot_decision_regions
X2 = X.iloc[:,0:2]#仅选取V2存款规模、V3EVA作为特征变量
model = LinearDiscriminantAnalysis()#使用LDA算法
model.fit(X2, y)#使用fit方法进行拟合
model.score(X2, y)
model.explained_variance_ratio_
plot_decision_regions(np.array(X2), np.array(y), model)
plt.xlabel('存款规模')#将x轴设置为'存款规模'
plt.ylabel('EVA')#将y轴设置为'EVA'
plt.title('LDA决策边界')#将标题设置为'LDA决策边界'
第一线性判元的可解释组间方差比例为0.98904178,第二线性判元可解释方差组间比例为0.01095822,或者说第一线性判元对于样本类别的区分度很高。
从图中可以发现,使用LDA方法的决策边界是直线,两条直线将所有参与分析的样本分为三个类别,最右侧区域为精品网点区域,特点是存款规模足够高,或者EVA足够高且存款不能太低;中间区域是一般网点区域,特点是存款规模或EVA有一方面表现相对较好,可以是EVA很高但存款规模很低,也可以是存款规模比较高(但还没有达到精品网点的标准)但EVA相对较低,也可以是存款规模和EVA都处于中等水平;左下方区域是未转型网点区域,特点是EVA与存款规模同时较低。