首页 > 其他分享 >机器学习方法(MATLAB)

机器学习方法(MATLAB)

时间:2024-07-14 11:22:17浏览次数:22  
标签:bondData 机器 crop 学习 FontSize MATLAB 聚类 cv bank

机器学习是一类算法的总称,利用历史数据对机器进行训练,而学习到某种方法或模式,并建立预测未来结果的模型。
机器学习分为两类学习方法:

  • 有监督学习,利用有标识的历史数据进行训练,实现对新数据的标识的预测。主要包括分类和回归。
  • 无监督学习,用于在历史数据中发现隐藏的模式或内在结构。主要包括聚类。

分类方法:

  • K-NN
  • 贝叶斯
  • 神经网络
  • logistic
  • 判别分析
  • SVM
  • 决策树

聚类方法:

  • K-means
  • 层次聚类
  • 神经网络
  • 高斯混合
  • 模糊C均值

分类方法

K-NN

K-近邻分类方法,通过每个训练样例到待分类样品的距离,取和待分类样本距离最近的k个样品,这k个样品中哪个类别占多数,则待分类样本就划分为那个类别。

把样例看成d维空间上的数据点,计算数据点之间的距离并比较

算法步骤:

  1. 初始化距离为最大值
  2. 计算未知样本和每个训练样本的距离dist
  3. 得到k个最近样本的最大距离maxdist
  4. 如果dist小于maxdist,则将该样本划为k-近邻样本
  5. 统计类别次数
  6. 选择类别

可以看到k-NN对k的值要求比较高,k的值过大或过小都会导致结果的不准确。实践中往往取若干次实验来确定k值,取分类误差率最小的k值。

案例



用K-NN算法建立该问题的分类器。
打开bank.mat

代码

clc,clear,close all
load bank.mat
%% 导入数据和数据预处理

%将分类变量转换成分类数组
names=bank.Properties.VariableNames;
category=varfun(@iscellstr,bank,'Output','uniform');
for i = find(category)
    bank.(names{i})=categorical(bank.(names{i}));
end

%跟踪分类变量
catPred=category(1:end-1);

%设置默认随机数生成方式,确保脚本中的结果是可以重现的
rng('default');

%数据可视化
figure(1)
gscatter(bank.balance,bank.duration,bank.y,'kk','xo');
xlabel('年平均余额','FontSize',12);
ylabel('上次接触时间','FontSize',12);
title('数据可视化图','FontSize',12);
set(gca,'linewidth',2);

%设置响应变量和预测变量
X=table2array(varfun(@double,bank(:,1:end-1))); %预测变量
Y=bank.y; %响应变量

disp('YES & NO的统计结果:');
tabulate(Y)

%将分类数组进一步转化为二进制数组,以便某些算法对分类变量的处理
XNum=[X(:,~catPred) dummyvar(X(:,catPred))];
YNum=double(Y)-1;

%% 随机选择40%的样本作为测试样本
cv=cvpartition(height(bank),'HoldOut',0.40);

%训练集
Xtrain=X(training(cv),:);
Ytrain=Y(training(cv),:);
XtrainNum=XNum(training(cv),:);
YtrainNum=YNum(training(cv),:);

%测试集
Xtest=X(test(cv),:);
Ytest=Y(test(cv),:);
XtestNum=XNum(test(cv),:);
YtestNum=YNum(test(cv),:);

disp('训练集:')
tabulate(Ytrain);
disp('测试集:')
tabulate(Ytest);


%% 训练K-NN分类器
knn=ClassificationKNN.fit(Xtrain,Ytrain,'Distance','seuclidean','NumNeighbors',5);

%进行预测
[Y_knn,Yscore_knn]=knn.predict(Xtest);
Yscore_knn=Yscore_knn(:,2);

%计算混淆矩阵
disp('最近邻方法分类结果: ')
C_knn=confusionmat(Ytest,Y_knn);
disp(C_knn)

主要的工作都是在处理数据


names=bank.Properties.VariableNames;bank.Properties.VariableNames是bank的属性,表示bank中的变量名列表,赋值之后names就是含有bank中变量名的列表

category=varfun(@iscellstr,bank,'Output','uniform');
MATLAB函数varfun,将输入的数组的每个元素执行相同的操作,将函数作用于数组,并将结果储存于另一个数组中。
iscellstr函数,如果是字符串型,返回bool值1,否则返回0,
这条语句指的是,对于bank中的Output属性,如果是字符串类型的属性,返回1,否则返回0

可以看到1,6,10,12,13,14,15这些属性不是字符串型,所以category的值为[0,1,1,1,1,0,1,1,1,0,1,0,0,0,0,1,1]

for i = find(category)
    bank.(names{i})=categorical(bank.(names{i}));
end

find()函数返回一个向量,表示值为1的索引。
也就是将这些字符串类型的变量进行操作。
categorical()函数将输入转换成具有类别的分类变量,比如原本job是'unknown','admin','teacher'这些字符串,转换后变成了unknown,admin,teacher这些表示类别的变量。

catPred=category(1:end-1);因为bank.mat中的最后一列是y值,YES和NO,所以表示属性的变量在 1:end-1

rng('default');rng()用于设置随机数生成的种子,'default'表示用默认方法生成随机数。

figure(1)
gscatter(bank.balance,bank.duration,bank.y,'kk','xo');
xlabel('年平均余额','FontSize',12);
ylabel('上次接触时间','FontSize',12);
title('数据可视化图','FontSize',12);
set(gca,'linewidth',2);

数据可视化
做balance和y,duration和y的点图
'kk'是设置颜色,黑黑,'xo'是散点的形状为x和o
FontSize是设置标题的字体大小

X=table2array(varfun(@double,bank(:,1:end-1))); %预测变量
Y=bank.y; %响应变量

再次使用varfun函数,将bank的第1-16列转换成double型变量,可以看到原来的分类变量现在变成了用数字表示的形式

Y=bank.y为相应变量,也就是输出变量

tabulate(Y)是统计Y中每个分类的数量,并且显示结果

XNum=[X(:,~catPred) dummyvar(X(:,catPred))];
YNum=double(Y)-1;

X(:,~catPred)是提取出X中catPred为0的列
X(:,catPred)是提取出X中catPred为1的列(字符串转成分类变量再转成double的那些列)
dummyvar()的作用是将分类变量转换为虚拟变量,虚拟变量表示分类变量中的每一个二进制特征。

cv=cvpartition(height(bank),'HoldOut',0.40);
cvpatition表示将数据划分成训练集和测试集,'HoldOut'是划分的方法,称为留出法,0.4表示选择40%作为测试集,储存在cv数组中,看一下cv的结构:

%训练集
Xtrain=X(training(cv),:);
Ytrain=Y(training(cv),:);
XtrainNum=XNum(training(cv),:);
YtrainNum=YNum(training(cv),:);

%测试集
Xtest=X(test(cv),:);
Ytest=Y(test(cv),:);
XtestNum=XNum(test(cv),:);
YtestNum=YNum(test(cv),:);

training(cv)test(cv)返回的是向量,向量内容是训练集和测试集的索引(一串01序列,1的位置标记为相应的集)
XtrainYtrain包含的是相应的训练集,而XtrainNumYtrianNum表示的是对应的二进制数组的相应位置。(XNum和YNum是转换成虚拟变量和数值变量后的矩阵)
测试集的处理同理

disp('训练集:')
tabulate(Ytrain);
disp('测试集:')
tabulate(Ytest);

tabulate()统计一下结果

knn=ClassificationKNN.fit(Xtrain,Ytrain,'Distance','seuclidean','NumNeighbors',5);
ClassificationKNN是用KNN算法构建分类集,fit方法是用于拟合分类的函数,拟合的集合是Xtrain和Ytrain,'Distance'是指定度量的字符串,'seuclidean'指定距离的计算是欧几里得离,'NumNeighbor',5指定邻居选择为5个,最后将拟合的分类器储存在knn变量中

[Y_knn,Yscore_knn]=knn.predict(Xtest);
Yscore_knn=Yscore_knn(:,2);

用训练好的KNN分类器对Xtest测试集进行分类,利用knn的predict方法即可。
返回的结果是一个矩阵,Y_knn是类别标签的预测值,yes和no,Yscore_knn是样本的类别的概率估计(分别是no的概率和yes的概率)

disp('最近邻方法分类结果: ')
C_knn=confusionmat(Ytest,Y_knn);
disp(C_knn)

confusionmat()计算混淆矩阵

混淆矩阵(Confusion Matrix)是机器学习中的一个概念,用于评估分类模型在预测类别时的准确性和召回率。混淆矩阵可以用来说明模型在预测过程中将真实类别与预测类别之间的混淆情况。
混淆矩阵的行表示真实类别,列表示预测类别。混淆矩阵的元素表示真实类别为行类别,预测类别为列类别的样本数量。
混淆矩阵的指标包括:

  1. 准确率(Accuracy):模型预测正确的样本数与总样本数的比值。
  2. 精确率(Precision):模型预测为正类的样本中,真实类别为正类的样本比例。
  3. 召回率(Recall):模型预测为正类的样本中,真实类别为正类的样本比例。
  4. F1分数(F1-score):结合了精确率和召回率的指标,用于衡量模型在预测上的表现。

K-NN方法在类别决策时,只与极少量的相邻样本有关,这种方法可以较好的避免样本的不平衡问题。
适合样本容量大的自动分类问题,对于容量小的问题,很容易产生误分。

贝叶斯分类

贝叶斯分类是一类基于贝叶斯原理的分类算法的总称。

贝叶斯定理可以告诉我们如何利用新证据修改已有的看法(这个解释不错)

\(P(Y|X)=\frac{P(X|Y)P(Y)}{P(X)}\)
朴素贝叶斯
对于给出的待分类项,求解在此项出现的条件下各个类别出现的概率。哪个最大,就认为此待分类项属于哪个类别。

比如在街上看到一个内个,你会猜他是来自非洲的,因为非洲的内个最多,这就是朴素贝叶斯的思想,在没有其他可用信息的情况下,选择条件概率最大的类别

朴素贝叶斯分类器建立在类条件独立的基础上
此时可以有:\(P(X|C_i) = \prod_{k=1}^{m}P(X_k|C_i)\)
所以,对于一个位置类别的X可以计算出X属于每一个类别Ci的概率\(P(X|C_i)P(C_i)\),然后再求出最大的概率作为其类别。
步骤:

  1. 有待分类项x={a1,a2,a3,a4,...,am},a是x的特征属性
  2. 类别集合C=
  3. 计算P(y1|x), ...
  4. 若P(yk|x)最大,则x∈yk


贝叶斯分类器的质量很大程度上由特征属性,特征属性划分以及训练样本质量决定,,如果属性之间是相关的,那么条件独立的假设已经不成立了。

代码

案例同上

clc,clear,close all
load bank.mat

names=bank.Properties.VariableNames;
category=varfun(@iscellstr,bank,'Output','uniform');
for i=find(category)
    bank.(names{i})=categorical(bank.(names{i}));
end

catPred=category(1:end-1);

rng('default');

figure(1);
gscatter(bank.balance,bank.duration,bank.y,'kk','xo');
xlabel('年平均余额','FontSize',12);
ylabel('上次接触时间','FontSize',12);
title('数据可视化图','FontSize',12);
set(gca,'linewidth',2);

X=table2array(varfun(@double,bank(:,1:end-1)));
Y=bank.y;

disp('YES & NO的统计结果:');
tabulate(Y)

%将分类数组进一步转化为二进制数组,以便某些算法对分类变量的处理
XNum=[X(:,~catPred) dummyvar(X(:,catPred))];
YNum=double(Y)-1;

cv=cvpartition(height(bank),'HoldOut',0.40);

Xtrain=X(training(cv),:);
Ytrain=Y(training(cv),:);
XtrainNum=XNum(training(cv),:);
YtrainNum=YNum(training(cv),:);

Xtest=X(test(cv),:);
Ytest=Y(test(cv),:);
XtestNum=XNum(test(cv),:);
YtestNum=YNum(test(cv),:);

disp('训练集:')
tabulate(Ytrain);
disp('测试集:')
tabulate(Ytest);

dist=repmat({'normal'},1,width(bank)-1);

%训练分类器
Nb=ClassificationNaiveBayes.fit(Xtrain,Ytrain,'Distribution',dist);

%进行预测
Y_Nb=Nb.predict(Xtest);
Yscore_Nb=Nb.posterior(Xtest);
Yscore_Nb=Yscore_Nb(:,2);

%计算混淆矩阵
disp('贝叶斯方法分类结果')
C_nb=confutionmat(Ytest,Y_Nb)

也出现了很多降低独立性假设的贝叶斯分类,

贝叶斯网络


贝叶斯网络是有向无环图,图中的结点表示随机变量,认为有因果关系的变量之间用有向边连接,边的权值即为条件概率

给定c的情况下,ab条件独立
给定c的条件下,ab条件独立
这样的条件依赖是链式的,xi+1的状态只与xi有关,和其他状态独立(任何状态只与上一状态有关),这样的顺序演变即马尔科夫链

支持向量机

通过学习算法,SVM可以自动找出那些对分类有较好区分能力的支持向量,由此构造出的分类器可以最大化类与类之间的间隔。
SVM属于有监督的学习方法,即已知训练点的类别,求训练点和类别之间的对应关系,以便将训练点之间分开,或者预测新的训练点所对应的类别。
SVM构建了一个分割两类的超平面,算法试图使两类之间的分割达到最大化。

以一个很大的边缘分割两个类可以使期望泛化误差最小化,“最小化泛化误差”的意思就是当对一个新的样本进行分类的时候,基于所得到的分类器,可以是的预测错误的概率被最小化。
假设容量为n的训练样本集(xi, yi)由两个类别组成。若xi属于第一类,则y=1,属于第二类则y=-1。
如果存在分类超平面\(w^Tx+b=0\)
能够将样本正确划分为两类(相同类别的样本都落在分类超平面的同一侧),则称该样本集是线性可分的
\(\begin{cases} w^Tx_i+b \ge 1 & y_i=1 \\ w^Tx_i+b \le -1 & y_i=-1 \end{cases}\)
也就是说这个分类问题的两个边界超平面就是:
\(w^Tx_i+b = 1\)
\(w^Tx_i+b = -1\)

\(w^Tx_i+b = 1\)到原点的距离为:\(\frac{|b-1|}{||w||}\)
\(w^Tx_i+b = -1\)到原点的距离为:\(\frac{|b+1|}{||w||}\)
则两个超平面的距离是\(\frac{2}{||w||}\)
最好的超平面应该使两个边界平面距离最大化,即
\(min \frac{||w||}{2}=min \frac{1}{2} \sqrt{w^Tw}\)
约束条件就是:\(y_i(w^Tx_i+b) \ge 1\)
这是一个二次优化问题——目标函数是二次的,约束条件是线性的。
有现成的QP优化包可以解决问题。
但是可以通过拉格朗日变换得到对偶变量的优化问题。
拉格朗日变换的作用,就是通过给每一个约束条件加上一个拉格朗日乘值,就可以将约束条件融合到目标函数里面去。
该问题的拉格朗日表达式:
\(L(w,b,a)= \frac{1}{2}||w||^2- \Sigma a_i[y_i(w^Tx_i+b)-1]\)
ai>0,为拉格朗日系数
输入空间中如果数据不是线性可分的,支持向量机通过非线性映射映射到其他某个点积空间F,在F上执行算法

clear,clc;
% load Patient.mat
load Patient.mat
names=Patient.Properties.VariableNames;
peopre=readmatrix("C:\Users\86136\Desktop\101-120SVM特征.xlsx");
category=varfun(@iscellstr,Patient,'OutputFormat','uniform');
for i=find(category)
    Patient.(names{i})=categorical(Patient.(names{i}));
end

%跟踪分类变量
catPred=category(1:end-1);

rng('default');

% 可视化需求

%设置响应变量和预测变量
X=table2array(varfun(@double,Patient(:,1:end-1)));
Y=Patient.Critical;

disp("the result of critical or not");
tabulate(Y);

XNum=[X(:,~catPred)];
YNum=double(Y);

cv=cvpartition(height(Patient),'HoldOut',0.30);

%训练集
Xtrain=X(training(cv),:);
Ytrain=Y(training(cv),:);
XtrainNum=XNum(training(cv),:);
YtrainNum=YNum(training(cv),:);

%测试集
Xtest=X(test(cv),:);
Ytest=Y(test(cv),:);
XtestNum=XNum(test(cv),:);
YtestNum=YNum(test(cv),:);

disp("train set")
tabulate(Ytrain);
disp("test set")
tabulate(Ytest);

ss=zeros(100,1);
% 训练分类
opts = struct('IterationLimit', 6000);
svmModel = fitcsvm(Xtrain, Ytrain, 'KernelFunction', 'linear','IterationLimit', opts.IterationLimit);

%进行预测
[Y_svm,Yscore_svm]=svmModel.predict(Xtest);
[pre_svm]=svmModel.predict(peopre);
disp(pre_svm);
disp("SVM result: ");
C_svm=confusionmat(Ytest,Y_svm)

聚类方法

K-means聚类

给定一个有N个元组或者记录的数据集,分裂法构造K个分组,每一个分组代表一个聚类。

要求每个分组至少有一个数据记录,每一个数据记录仅属于一个分组

算法给出初始的分组方法,然后反复迭代使得分组效果越来越好(同一分组中的数据记录越近越好,不同分组的数据记录越远越好
步骤:

  1. 从n个数据对象中任意选择k个对象作为初始聚类中心
  2. 根据每个聚类对象的均值(中心对象),计算每个对象与中心对象的距离,根据最小距离重新调整相应对象进行划分。
  3. 重新计算每个聚类的均值,直到聚类中心不再变化,这种划分使得下式最小:\(E=\Sigma_{j=1}^{k}\Sigma_{x_i∈w_j}||x_i-m_j||^2\)
  4. 循环2,3步,直到每个聚类不发生变化

案例

%% 数据准备和初始化
clc,clear

x=[0 0;1 0;0 1;1 1;2 1;1 2;2 2;3 2;6 6;7 6;8 6;6 7;7 7;8 7;9 7;7 8;8 8;9 8;8 9;9 9];
z=zeros(2,2);
z1=zeros(2,2);
z=x(1:2,1:2);

%%寻找聚类中心
while 1
    count=zeros(2,1);
    allsum=zeros(2,2);
    for i=1:20 %对每一个样本i,计算到两个聚类中心的距离
        temp1=sqrt((z(1,1)-x(i,1)).^2+(z(1,2)-x(i,2)).^2);
        temp2=sqrt((z(2,1)-x(i,1)).^2+(z(2,2)-x(i,2)).^2);
        if(temp1<temp2)
            count(1)=count(1)+1;
            allsum(1,1)=allsum(1,1)+x(i,1);
            allsum(1,2)=allsum(1,2)+x(i,2);
        else
            count(2)=count(2)+1;
            allsum(2,1)=allsum(2,1)+x(i,1);
            allsum(2,2)=allsum(2,2)+x(i,2);
        end
    end
    z1(1,1)=allsum(1,1)/count(1);
    z1(1,2)=allsum(1,2)/count(1);
    z1(2,1)=allsum(2,1)/count(2);
    z1(2,2)=allsum(2,2)/count(2);
    if(z==z1)
        break;
    else
        z=z1;
    end
end

%% 结果显示
disp(z1); %输出聚类中心
plot(x(:,1),x(:,2),'k*','LineWidth',2,'MarkerSize',10,'MarkerEdgeColor','k','MarkerFaceColor',[0.5,0.5,0.5])
hold on
plot(z1(:,1),z1(:,2),'ko','LineWidth',2,'MarkerSize',10,'MarkerEdgeColor','k','MarkerFaceColor',[0.5,0.5,0.5])
set(gca,'linewidth',2);
xlabel('特征x1','FontSize',12);
ylabel('特征x2','FontSize',12);
title('K-means','FontSize',12);

代码

z=zeros(2,2); %聚类中心,记录第一个聚类中心和第二个的两个特征量
z1=zeros(2,2); %临时变量
z=x(1:2,1:2); %初始化聚类中心为前两个点
    count=zeros(2,1);% 每个类别的个数
    allsum=zeros(2,2);% 每个点到聚类中心的距离之和
    z1(1,1)=allsum(1,1)/count(1);
    z1(1,2)=allsum(1,2)/count(1);
    z1(2,1)=allsum(2,1)/count(2);
    z1(2,2)=allsum(2,2)/count(2);

计算新的距离,判断是否更换聚类中心

案例:MATLAB中kmeans函数的使用

%% 导入数据和数据预处理
clc,clear,close all
load BondData.mat
settle=floor(date);

%数据预处理
bondData.MaturityN=datenum(bondData.Maturity,'dd-mm-yyyy');
bondData.SettleN=settle*ones(height(bondData),1);

%筛选数据
corp=bondData(bondData.MaturityN>settle & ...
              bondData.Type=='Corp' & ...
              bondData.Rating>='CC' & ...
              bondData.YTM<30 & ...
              bondData.YTM>=0,:);
rng('default');


%% 探索数据
figure
gscatter(crop.Coupon,crop.YTM,crop.Rating);
set(gca,'linewidth',2);
xlabel('票面利率');
ylabel('到期收益率');

%选择聚类变量
crop.RatingNum=double(crop.Rating);
bonds=crop{:,{'Coupon','YTM','CurrentYield','RatingNum'}};

%设置类别数量
numClust=3;

%设置用于可视化聚类效果的变量
VX=[crop.Coupon,double(crop.Rating),crop.YTM];


%% K-means聚类

dist_k='cosine';
kidx=kmeans(bonds,numClust,"Distance",dist_k);

%绘制聚类效果图
figure
F1=plot3( ...
    VX(kidx==1,1),VX(kidx==1,2),VX(kidx==1,3),'r*',...
    VX(kidx==2,1),VX(kidx==2,2),VX(kidx==2,3),'bo',...
    VX(kidx==3,1),VX(kidx==3,2),VX(kidx==3,3),'kd');
set(gca,'linewidth',2);
grid on;
set(F1,'linewidth',2,'MarkerSize',8);
xlabel('票面利率','FontSize',12);
ylabel('评级得分','FontSize',12);
ylabel('到期收益率','FontSize',12);
title('K-means聚类结果');

%评估各类别的相关程度
dist_metric_k=pdist(bonds,dist_k);
dd_k=squareform(dist_metric_k);
[~,idx]=sort(kidx);
dd_k=dd_k(idx,idx);
figure
imagesc(dd_k);
set(gca,'linewidth',2);
xlabel('数据点','FontSize',12);
ylabel('数据点','FontSize',12);
title('k-means聚类结果相关程度图','FontSize',12)
ylabel(colorbar,['距离矩阵:',dist_k])
axis square

代码


bondData.MaturityN=datenum(bondData.Maturity,'dd-mm-yyyy');
datenum函数接收一个dd-mm-yyyy形式的字符串,并转换成时间戳。

crop=bondData(bondData.MaturityN>settle & ...
              bondData.Type=='Corp' & ...
              bondData.Rating>='CC' & ...
              bondData.YTM<30 & ...
              bondData.YTM>=0,:);

筛选到期日期大于settle,类型为Corp,评级大于CC,到期收益率0到30之间的信息

figure
gscatter(crop.Coupon,crop.YTM,crop.Rating);
set(gca,'linewidth',2);
xlabel('票面利率');
ylabel('到期收益率');

画图指令,gscatter接收三个参数,横坐标矩阵,纵坐标矩阵,颜色,这里颜色直接传入储存分类变量的矩阵,会自动区分不同颜色的类别,可以很方便的做出分类点

可以看出,到期收益率越大,票面利率越大,债券被评为CC或CCC的可能性越高

crop.RatingNum=double(crop.Rating);
crop的Rating列,做数值化处理

bonds=crop{:,{'Coupon','YTM','CurrentYield','RatingNum'}};
创建新的向量bonds,过滤crop中的无关项(手动选择聚类变量)。

numClust=3;K-means的聚类类别需要手动设置

VX=[crop.Coupon,double(crop.Rating),crop.YTM];
用于可视化的辅助变量

dist_k='cosine';
kidx=kmeans(bonds,numClust,"Distance",dist_k);

kmeans函数进行分类,参数为相应的标记特征向量的矩阵,类别,距离,这里的距离是余弦距离,余弦距离计算两个向量的夹角并取反。

figure
F1=plot3( ...
    VX(kidx==1,1),VX(kidx==1,2),VX(kidx==1,3),'r*',...
    VX(kidx==2,1),VX(kidx==2,2),VX(kidx==2,3),'bo',...
    VX(kidx==3,1),VX(kidx==3,2),VX(kidx==3,3),'kd');
set(gca,'linewidth',2);
grid on;
set(F1,'linewidth',2,'MarkerSize',8);
xlabel('票面利率','FontSize',12);
ylabel('评级得分','FontSize',12);
ylabel('到期收益率','FontSize',12);
title('K-means聚类结果');

绘图指令

dist_metric_k=pdist(bonds,dist_k);pdist计算矩阵中向量之间的距离。
dist_metric_k(x,y)表示第x行和第y行向量的距离。
dd_k=squareform(dist_metric_k);将距离矩阵转换为方阵。

[~,idx]=sort(kidx); dd_k=dd_k(idx,idx);
这段代码的主要实现原理是对数组kidx进行排序,然后用排序后的索引数组idx中的值替换dd_k中的元素。这样,dd_k数组就会根据kidx数组中的值进行重新排列

~表示不关心返回的第一个参数,sort函数的第二个返回值是对应的数据在原数组内的索引值


最后按照idx对dd_k距离方阵重新排列

imagesc(dd_k);
set(gca,'linewidth',2);
xlabel('数据点','FontSize',12);
ylabel('数据点','FontSize',12);
title('k-means聚类结果相关程度图','FontSize',12)
ylabel(colorbar,['距离矩阵:',dist_k])

imagesc函数用于在二维平面中显示灰度图像

Kmeans的效果很大程度上取决于簇的数量,代码中numCluster也是自定义的值。
可以将numCluster设置为一个范围,每种簇数进行聚类后:

  1. 计算SSE
  2. 计算WCSS=ΣSSE
  3. 绘制WCSS的图像,根据肘部法则选择最好的簇数量
%% 导入数据和数据预处理
clc,clear,close all
load BondData.mat
settle=floor(date);

%数据预处理
bondData.MaturityN=datenum(bondData.Maturity,'dd-mm-yyyy');
bondData.SettleN=settle*ones(height(bondData),1);

%筛选数据
crop=bondData(bondData.MaturityN>settle & ...
              bondData.Type=='Corp' & ...
              bondData.Rating>='CC' & ...
              bondData.YTM<30 & ...
              bondData.YTM>=0,:);
rng('default');



%选择聚类变量
crop.RatingNum=double(crop.Rating);
bonds=crop{:,{'Coupon','YTM','CurrentYield','RatingNum'}};

%设置类别数量

numClust=[2,3,4,5,6,7,8,9,10];
wcss=zeros(size(numClust,2),1);


%% K-means聚类
disk_k='cosine';
for i=1:size(numClust,2)
    [~,~,sse]=kmeans(bonds,numClust(i),"Distance",disk_k);
    %计算WCSS
    for j=1:size(sse)
        wcss(i)=sum(sse);
    end
end

figure
plot(wcss);

肘部点的选择是有一定主观性的

层次聚类

层次聚类是通过将数据组织若干并形成一个相应的树来进行聚类的。

  1. 凝聚型的层次聚类将每个对象逐步的合并。
  2. 分裂型的层次聚类将放在一个簇里的对象逐个分裂。

这两种方法的中间过程得到的若干对象形成的若干簇,都可以作为聚类的结果

案例

案例同上

代码

%% 导入数据和数据预处理
clc,clear,close all
load BondData.mat
settle=floor(date);

%数据预处理
bondData.MaturityN=datenum(bondData.Maturity,'dd-mm-yyyy');
bondData.SettleN=settle*ones(height(bondData),1);

%筛选数据
crop=bondData(bondData.MaturityN>settle & ...
              bondData.Type=='Corp' & ...
              bondData.Rating>='CC' & ...
              bondData.YTM<30 & ...
              bondData.YTM>=0,:);
rng('default');


%% 探索数据
figure
gscatter(crop.Coupon,crop.YTM,crop.Rating);
set(gca,'linewidth',2);
xlabel('票面利率');
ylabel('到期收益率');

%选择聚类变量
crop.RatingNum=double(crop.Rating);
bonds=crop{:,{'Coupon','YTM','CurrentYield','RatingNum'}};

%设置类别数量
numClust=3;

%设置用于可视化聚类效果的变量
VX=[crop.Coupon,double(crop.Rating),crop.YTM];

dist_h='spearman';
link='weighted';
hidx=clusterdata(bonds,'maxclust',numClust,'distance',dist_h,'linkage',link);

%绘制聚类效果图
figure
F1=plot3( ...
    VX(hidx==1,1),VX(hidx==1,2),VX(hidx==1,3),'r*',...
    VX(hidx==2,1),VX(hidx==2,2),VX(hidx==2,3),'bo',...
    VX(hidx==3,1),VX(hidx==3,2),VX(hidx==3,3),'kd');
set(gca,'linewidth',2);
grid on;
set(F1,'linewidth',2,'MarkerSize',8);
xlabel('票面利率','FontSize',12);
ylabel('评级得分','FontSize',12);
ylabel('到期收益率','FontSize',12);
title('K-means聚类结果');

%评估各类别的相关程度
dist_metric_h=pdist(bonds,dist_h);
dd_h=squareform(dist_metric_h);
[~,idx]=sort(hidx);
dd_h=dd_h(idx,idx);
figure
imagesc(dd_h);
set(gca,'linewidth',2);
xlabel('数据点','FontSize',12);
ylabel('数据点','FontSize',12);
title('k-means聚类结果相关程度图','FontSize',12)
ylabel(colorbar,['距离矩阵:',dist_h])
axis square

%计算同型相关系数
Z=linkage(dist_metric_h,link);
cpcc=cophenet(Z,dist_metric_h);
disp('同表象相关系数:')
disp(cpcc)

%% 层次结构图
set(0,'RecursionLimit',5000)
figure
dendrogram(Z);
set(gca,'linewidth',2);
set(0,'RecursionLimit',500)
xlabel('数据点','FontSize',12);
ylabel('距离','FontSize',12);
title(['CPCC: ' sprintf('%0.4f',cpcc)])

同型相关系数CPCC是一种用于衡量数据相似性的方法,它通过对数据进行归一化处理,然后计算数据之间的皮尔逊相关系数。

文中案例来源:《MARTLAB数学建模方法与实践》(卓金武)

引用博客已在文中给出链接

标签:bondData,机器,crop,学习,FontSize,MATLAB,聚类,cv,bank
From: https://www.cnblogs.com/hansumsomemer/p/18301251

相关文章

  • 【java深入学习第5章】Spring Boot 中统一功能的实现与处理
    SpringBoot统一功能处理在开发Web应用程序时,为了提高代码的可维护性和可扩展性,我们通常会采用一些统一的功能处理方式。本文将介绍如何在SpringBoot中实现统一的数据返回格式、异常处理和功能处理,并通过一个图书管理系统的案例来演示这些功能的实现。一、统一数据返回格......
  • 【java深入学习第6章】Spring事件监听机制详解
    在Spring框架中,事件监听机制是一个强大且灵活的功能,允许我们在应用程序中发布和监听事件。这种机制可以帮助我们实现松耦合的设计,使得不同模块之间的通信更加灵活和可维护。本文将详细介绍Spring的事件监听机制,并通过代码示例展示如何使用这一功能。1.什么是Spring事件监听机制?......
  • 【机器学习】精准农业新纪元:机器学习引领的作物管理革命
    ......
  • 【java深入学习第4章】精通 Java 微服务:Spring Boot 与 Spring Cloud 的核心技术与设
    在现代软件开发中,微服务架构因其灵活性和可扩展性而备受青睐。本文将探讨Java微服务架构中的关键技术和设计原则,并通过SpringBoot和SpringCloud提供代码示例,展示如何构建一个简单的微服务应用。关键技术和设计原则服务拆分:将单体应用拆分为多个独立的微服务,每个服务负责特定......
  • 前端学习-flutter学习-010-按钮
    《Flutter实战·第二版》ElevatedButton(child:Text("ElevatedButton默认带有阴影和灰色背景。按下后,阴影会变大"),onPressed:(){},),TextButton(child:Text("TextButton默认背景透明并不带阴影。按下后,会有背景色"),onPressed:(){},),......
  • 【java深入学习第2章】Spring Boot 结合 Screw:高效生成数据库设计文档之道
    在开发过程中,数据库设计文档是非常重要的,它可以帮助开发者理解数据库结构,方便后续的维护和扩展。手动编写数据库设计文档不仅耗时,而且容易出错。幸运的是,可以使用SpringBoot和Screw来自动生成数据库设计文档。什么是Screw?Screw是一个开源的数据库文档生成工具,它可以根据数据库......
  • 前端学习-flutter学习-009-文本及样式
    《Flutter实战·第二版》TextTextAlign:leftrightcenter注意点:对齐的参考系是Textwidget本身,如果文本不够长,设置看起来是没有生效的;文本长才看得到,字符串内容超过一行,Text宽度等于屏幕宽度,第二行文本便会居中显示。maxLines、overflow:指定文本显示的最大行数,默认情况下,......
  • 【java深入学习第3章】通过 Spring AOP 完成参数的加解密
    在现代应用中,数据的安全性越来越受到重视。为了保护敏感数据,我们常常需要对数据进行加密和解密。在这篇博客中,我将展示如何使用SpringAOP(面向切面编程)来实现对方法参数的加解密。什么是SpringAOP?SpringAOP是Spring框架中的一个模块,它提供了面向切面编程的功能。AOP允许我们将......
  • 花几千上万学习Java,真没必要!(四)
    1、关系运算符:packagetest.com;publicclassRelationalArithmetic{ /*关系运算符用于比较两个值之间的关系,关系运算符的结果是一个布尔值,即true或false。 Java提供了6种关系运算符: >:大于 <:小于 >=:大于等于 <=:小于等于 ==:等于 !=:不等于*/publicstaticvoi......
  • vue学习day05-watch侦听器(监视器)、Vue生命周期和生命周期的四个阶段、、工程化开发和
    13、watch侦听器(监视器)(1)作用:监视数据变化,执行一些业务逻辑或异步操作(2)语法:1)简写语法——简单数据类型,直接监视①Watch:{数据属性名(newValue,oldValue){一些业务逻辑或异步操作},‘对象·属性名’(newValue,oldValue){一些业务逻辑或异步操作}}②示例:结果:2)完整写法......