机器学习
机器学习是一中工具、方法,通过对机器训练,进而学习到某种规律或者模式,并建立预测未来结果的模型。
机器学习可以分为监督学习和无监督学习
- 有监督学习方法,是提供答案的,主要包括分类和回归
- 无监督学习方法,是不提供答案的,主要包括聚类,用来发现隐藏的模式。显然无监督学习更加消耗时间。
分类方法可以分为以下几种
- k-近邻(K-NN)
- 贝叶斯
- 神经网络
- 逻辑(logistic)
- 判别分析
- 支持向量机
- 决策树
聚类方法可以分为以下几种
- k-means
- 层次聚类
- 神经网络
- 高斯混合
- 模糊C均值
K-近邻分类(K-NN)
K-NN是计算每个训练样例到分类样品的距离,取和待分类的样品距离最近的k个样例,k个样例中哪个类别最多,则待分类的就属于哪个。
“走得像鸭子,叫得像鸭子,看起来还像鸭子,那它很有可能就是鸭子”
优点是,因为是根据样本而不是类域来确定所属类别,对于类域交叉或重叠较多的待分样本来说,K-NN更好。
缺点是有过一点编程素养的就知道,这个方法因为要计算全部的距离,对于大数据集,运算量大,需要压缩数据集,对于小数据集,准确度低。
案例:根据客户的年龄、工作等属性来确定客户是否愿意购买该产品。表格是除了属性名词都是数值、分类变量的。
我们通过代码来初步了解分类的基本步骤
预处理
如下是导入数据的预处理
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.banlance,bank.duration,bank.y,'kk','xo')
xlabel('年平均余额/万元');
ylabel('上次接触时间/秒');
title('效果图');
set(gca,'linewidth',2);
X=table2array(varfun(@double,bank(:,1:end-1)));//预测变量,2=to,转换
Y=bank.y;//响应变量
tabulate(Y)
//把分类数组转化为二进制数组 以便某些算法对分类变量的处理,具体的转化方式笔者还没看懂,甚至笔者都没发现后面这个数组用在哪里,可能下面写错了吧,num理解为数字化更好,而不是数量
XNum=[X(:,~catPred) dummyvar(X(:,catPred))];
YNum=double(Y)-1
varfun
这是把矩阵A中的变量全部通过函数运算一遍,返回值是table,用法如下
B = varfun(func,A,Name,Value)
通过设置输出格式来生成数值向量
func=@mean;
B = varfun(func,A,'OutputFormat','uniform').
生成uniform格式,就是生成一致的格式,要求func的返回值类型一直一致
详见https://www.mathworks.com/help/matlab/ref/varfun.html?searchHighlight=varfun&s_tid=srchtitle#namevaluepairarguments
iscellstr
is cell str?确定输入是否为字符向量的元胞数组,是的话返回1,否则0。值得注意的是字符向量是如下的
C = {'Li','Sanchez','Jones','Yang','Larson'}
L = strlength(C)
L = 1×5
2 7 5 4 6
如果执行了
str = string(C)
那么str数组包含的是字符串而不是字符向量
find
返回各个非零元素位置的向量
category和逻辑向量
category是个数据类型,相当于集合,似乎是自动排序的,可以用categories
dummyvar
验证在搜索的时候很方便,上面是把表格强制转换成分类数组
下面举例子吧,不想打字了
rng
控制随机数发生器,控制随机数的种子和生成方式,default是默认,能保证结果可以重现
Temps = [58; 72; 56; 90; 76];
Dates = {'2017-04-17';'2017-04-18';'2017-04-30';'2017-05-01';'2017-04-27'};
Stations = {'S1';'S2';'S1';'S3';'S2'};
Stations = categorical(Stations)
此时输入
categories(Stations)
得到分类集合,然后我们继续,制作一张表格
T = table(Temps,Dates,Stations)
TF = (T.Stations == 'S2');
T(TF,:)
以下是输出
ans=2×3 table
Temps Dates Stations
_____ ______________ ________
72 {'2017-04-18'} S2
76 {'2017-04-27'} S2
我们顺便再看一下TF的值
TF =
5×1 logical 数组
0
1
0
0
1
也就是逻辑变量组成的向量在表中会自动成为行数,也就是哪一行应该输出。
tabulate
制表统计,给个例子一目了然
load patients
Gender(1:5)
tabulate(Gender)
ans = 5x1 cell
{'Male' }
{'Male' }
{'Female'}
{'Female'}
{'Female'}
Value Count Percent
Male 47 47.00%
Female 53 53.00%
dummyvar
虚拟变量函数,返回二元的亚变量(虚拟变量?)0,1矩阵,作用是把分类数组(内部会自动排序)、元胞数组等数组转化为二进制数组,应该只支持列向量
看一下下面的例子你就懂了
Colors = {'Red';'Blue';'Green';'Red';'Green';'Blue'};
Colors = categorical(Colors);
D = dummyvar(Colors)
输出
D = 6×3
0 0 1
1 0 0
0 1 0
0 0 1
0 1 0
1 0 0
machine = [1 1 1 1 2 2 2 2]';
operator = [1 2 3 1 2 3 1 2]';
group = [machine operator];
D = dummyvar(group)
D = 8×5
1 0 1 0 0
1 0 0 1 0
1 0 0 0 1
1 0 1 0 0
0 1 0 1 0
0 1 0 0 1
0 1 1 0 0
0 1 0 1 0
设置交叉验证方式
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)
cvpartition
进行交叉验证的分区数据,用法
c = cvpartition(group,'KFold',k)
c = cvpartition(group,'Holdout',p)
c = cvpartition(n,'KFold',k)
c = cvpartition(n,'Holdout',p)
K-Fold交叉验证是数据分成k组,每次迭代用k-1组训练模型,1组验证。我们为了防止在训练过程中,出现过拟合的问题,通常是将数据分为训练集和测试集。如果测试集是与训练独立的数据,那就会浪费,所以这个方法充分利用了数据。但建议小数据集用这个,大数据集不要用,因为训练的时间是通常的k倍。
Holdout是随机选择比例为p的样本作为测试样本,1-p为训练样本。
cvpartition函数是生成特定结构变量,包含样本数、测试轮数、测试数和训练数,需要搭配training函数和test函数生成逻辑向量。
https://www.mathworks.com/help/stats/cvpartition.html
height
返回表格行数
training/test
就这么用
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),:);
对于k-fold,要迭代k次,我们用这两个函数的时候,加上迭代轮数
比如
xtest1=X(training(cv,1),:);
训练分类器
knn=ClassificationKNN.fit(Xtrain,Ytrain,'Distance',...
'seuclidean','NumNeighbor',5);
[Y_knn,Yscore_knn]=knn.predict(Xtest);
Yscore_knn=Yscore_knn(:,2);
disp('KNN results:')
C_knn=confusionmat(Ytest,Y_knn)
ClassificationKNN
Distance设定距离,程序给的是标准欧几里得距离
NumNeighbor设定临近个数k
具体调整参数看官网
https://www.mathworks.com/help/stats/classificationknn.html?searchHighlight=ClassificationKNN&s_tid=srchtitle
朴素贝叶斯分类(Naive Bayes)
该分类是由贝叶斯定理推导的
P ( Y ∣ X ) = P ( X ∣ Y ) P ( Y ) P ( X ) P(Y|X)= \frac{P(X|Y)P(Y)}{P(X)} P(Y∣X)=P(X)P(X∣Y)P(Y)
这个分类的朴素思想是对于未知类别的X,在各个类别中概率最高的类别就是X的类别。
令 Y Y Y为类别集合,当得到最大的 P ( y i ∣ x ) P(y_i|x) P(yi∣x),x就属于i类别。
设 x = { a 1 , a 2 , . . . a n } x=\{a_1,a_2,...a_n\} x={a1,a2,...an}其中 a i a_i ai为各个特征,那么在各个特征独立的假设下,可以得到如下公式
P ( x ∣ y i ) = P ( y i ) ∏ j = 1 n P ( a j ∣ y i ) P(x|y_i)=P(y_i)\prod_{j=1}^nP(a_j|y_i) P(x∣yi)=P(yi)∏j=1nP(aj∣yi)
在各个特征关联度不高的情况下,朴素贝叶斯简单、快速而准确,但特征在相关的时候,准确度会受到影响,所以还有TAN、BNC等新算法,降低独立性假设。
我们通过朴素贝叶斯算法来大概了解模型训练和使用的过程
dist = repmat({'normal'},1,width(bank)-1);
dist(catPred)={'mvmn'};
Nb=NaiveBayes.fit(Xtrain,Ytrain,'Distibution',dist);
Y_Nb=Nb.predict(Xtest);
Yscore_Nb=Nb.posterior(Xtest);
Yscore_Nb=Yscore_Nb(:,2);
disp('result:')
C_nb=confusionmat(Ytest,Y_Nb)
repmat
repmat是初始化重复矩阵的函数,即repeat matrix
A = repmat(10,3,2)
A = 3×2
10 10
10 10
10 10
posterior
高斯混合分量的后验概率
disp
disp就是display,输出函数
confusionmat
最后一行输出混淆矩阵,混淆矩阵会输出四个值,从左到右,从上到下是false positives,falsenegatives,true positives和true negatives
含义如下:
TP(True Positive):将正类预测为正类数,真实为0,预测也为0
FN(False Negative):将正类预测为负类数,真实为0,预测为1
FP(False Positive):将负类预测为正类数, 真实为1,预测为0
TN(True Negative):将负类预测为负类数,真实为1,预测也为1
支持向量机(SVM)
支持向量机构建一个超平面,让数据分布在平面上,然后用线性的分割,或者经过非线性的投影(激励)后用线性分割,使泛化误差最小化。
存在超平面,使
w
T
x
+
b
=
0
w^Tx+b=0
wTx+b=0
以下情况视为平面线性可分
{
w
T
x
i
+
b
>
=
1
,
y
i
=
1
w
T
x
i
+
b
<
=
−
1
,
y
i
=
−
1
\left\{ \begin{aligned} w^Tx_i+b>=1,y_i=1\\ w^Tx_i+b<=-1,y_i=-1\\ \end{aligned} \right.
{wTxi+b>=1,yi=1wTxi+b<=−1,yi=−1
上式可以简化为
(
w
T
x
i
+
b
)
y
i
>
=
1
(w^Tx_i+b)y_i>=1
(wTxi+b)yi>=1
而要求的是距离最小值,和||
w
w
w||的二次正相关,于是这就是满足线性条件下的凸优化,可以使用QP优化,或者通过拉格朗日变换到对偶变量后解决问题。(完了我又在挖坑)
据说支持向量机是最难理解的,先贴代码吧
opts = statset('MaxIter',45000);
svmStruct=svmtrain(Xtrain,Ytrain,'kernel_function','linear','kktviolationlevel',0.2,'options',opts);
Y_svm=svmclassify(svmStruct,Xtest);
Yscore_svm=svmscore(svmStruct,Xtest);
Yscore_svm=(Yscore_svm-min(Yscore_svm))/range(Yscore_svm)
disp('SVM result')
C_svm=confusionmat(Ytest,Y_svm)
支持向量机由于可以表示为凸优化,可以找到全局最小值,而其他一些算法用的是贪心的思想。他其他方面的性质也不差,所以是很优秀的分类方法。
竟然没写完1/3!!!!今天不写了
2021-02-03来填坑了,速成真的很粗糙,以后还应该重新学,所以先贴代码吧,今天还是调包侠
K-means聚类
K-均值聚类,大致流程如下
- 随机选取k个点作为k个聚类中心
- 计算k个聚类中心的均值(means)
- 计算每个点到中心的距离,根据最小距离划分
- 重复2、3直到收敛
实例:有20个样本,每个样本有两个特征,试进行分类,下面这个程序不调用包。
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);//设定2个初始聚类
while 1
count=zeros(2,1);
allsum=zeros(2,2);
for i=1:20//计算距离
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)=count1(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
plot(x(:,1),x(:,2),'k*')
hold on
plot(x(:,1),x(:,2),'ko*')
下面再通过银行例子来写下聚类调包写法
背景:已知债券一些基本属性和评级,希望通过聚类来确定分成几类合适。
预处理
clc,clear all,close all
load BondData
settle = floor(date);
%数据预处理
bondData.MaturityN=datenum(bondData.Maturity,'dd-mmm-yyy');
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');
floor
向负无穷大舍入取整
date
c=date
c=floor(date)
c=char(c)
c =
'03-Feb-2021'
c =
48 51 45 70 101 98 45 50 48 50 49
c =
'03-Feb-2021'
datenum
DateString = '19-May-2001';
formatIn = 'dd-mmm-yyyy';
datenum(DateString,formatIn)
ans = 730990
探索数据
Figure
gscatter(corp.Coupon,corp.YTM,corp.Rating)//票面利率、到期收益率、评级结果
set(gca,'linewidth',2);
xlable('票面利率')
ylable('到期收益率')
//设置聚类变量
corp.RatingNum=double(corp.Rating);//数字化
bonds=corp{:,{'Coupon','YTM','CurrentYield','RatingNum'}};
//设置类别变量
numClust=3;
/设置用于可视化聚类效果的变量
VX=[corp.Coupon,corp.RatingNum,corp.YTM]
开始聚类
dist_k='cosine'///设定距离类型
kidx=kmeans(bonds,numClust,'distance',dist_k);//idx=index索引
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);
zlabel('评级得分','fontsize',12);
ylabel('到期收益率','fontsize',12);
title('K-means results');
%评估类别的相关程度
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 correlogram')
ylable(colorbar,['距离矩阵:',dist_k])//单纯展示给读者距离的形式是dist_k
axis square
kmeans
idx = kmeans(X,k,Name,Value)
对于X 会自动去掉包含NaN的行
NaN,Not a Number,非数
Name,Value一如既往是参数名和参数
调参详见
https://www.mathworks.com/help/stats/kmeans.html?s_tid=srchtitle#namevaluepairarguments
grid on
添加网格线
imagesc
颜色表距离的图
pdist&squareform
Pairwise distance between pairs of observations
成对距离,是行与行之间的两两计算,常常搭配squareform使用,生成距离矩阵
pdist(X,distance)
自己决定距离种类
rng('default') % For reproducibility
X = rand(3,2);
D = pdist(X)
Z = squareform(D)
D = 1×3
0.2954 1.0670 0.9448
Z = 3×3
0 0.2954 1.0670
0.2954 0 0.9448
1.0670 0.9448 0
这个算法缺点比较多,首先k难以估计,其次对于大规模数据难以运算,然后它的结果受初始设定影响较大
层次聚类
忽略
模糊C-均值聚类(FCM)
Fuzzy C-means Algorithm
这个聚类算法引入隶属度,每个样品不是严格划分成几个类,而是以隶属度划分。
对n个样本(观测量)和p个特征,给定一个观测数据矩阵
X = [ x 11 x 12 ⋯ x 1 p x 21 x 22 ⋯ x 2 p ⋮ ⋮ ⋱ ⋮ x n 1 x n 2 ⋯ x n p ] X=\begin{bmatrix} {x_{11}}&{x_{12}}&{\cdots}&{x_{1p}}\\ {x_{21}}&{x_{22}}&{\cdots}&{x_{2p}}\\ {\vdots}&{\vdots}&{\ddots}&{\vdots}\\ {x_{n1}}&{x_{n2}}&{\cdots}&{x_{np}}\\ \end{bmatrix} X=⎣⎢⎢⎢⎡x11x21⋮xn1x12x22⋮xn2⋯⋯⋱⋯x1px2p⋮xnp⎦⎥⎥⎥⎤
记
V
=
(
v
1
,
v
2
,
.
.
.
,
v
c
)
V=(v_1,v_2,...,v_c)
V=(v1,v2,...,vc)为c个聚类中心
v
i
v_i
vi又包含p个特征
大致方法是定义目标函数
J
(
U
,
V
)
J(U,V)
J(U,V)
(markdown写数学公式太麻烦了不写了)
函数值为样品到聚类中心的加权距离平方和,权值是隶属度的m次方,通过修改U,V让目标函数达到终止容限或者到达设定的隶属度容限或者超过迭代步长。
下面给出代码
options=nan(4,1);
options(4)=0;
[centres,U]=fcm(bonds,numClust,options);
[~,fidx]=max(U);
fidx=fidx';
Figure
F4=plot3(VX(fidx==1,1),VX(fidx==1,2),VX(fidx==1,3),'r*',...
VX(fidx==2,1),VX(fidx==2,2),VX(fidx==2,3),'bo',...
VX(fidx==3,1),VX(fidx==3,2),VX(fidx==3,3),'kd');
set(gca,'linewidth',2);
grid on;
set(F4,'linewidth',2,'MarkerSize',8);
xlabel('票面利率','fontsize',12);
zlabel('评级得分','fontsize',12);
ylabel('到期收益率','fontsize',12);
title('FCN results');
nan
生成全为NaN的数组(相当于空数组)
fcm
[centers,U] = fcm(data,Nc,options)
输入数据 分类数 选项
选项可以不输入 是一个4*1的向量
选项1是 计算隶属度权重的幂指数m 默认为2
选项2是最大迭代次数 默认为100
选项3是判断收敛用的两轮最小差值 默认1e-5
选项4是是否显示迭代后的函数值 默认是true
优点是省去了反复的不必要迭代,效率高。缺点是梯度法搜索来最小化目标函数,容易陷入局部最小值,m是一个经验值,不一定准确。
深度学习
既然是老客人了,那就多写一点吧
题外话:人工智能和深度学习和机器学习的关系?
在上个世纪五十年代,计算机领域就产生一系列推理、感知、电脑游戏、机器翻译这样的应用,计算机科学家们把这些应用统称为人工智能。
而在七十年代,一个新的子领域产生,科学家借助历史数据对机器训练,使机器学习到某种模式或规律,并建立预测未来结果的模型,机器学习由此热门,它广泛用在天气预测、推送、垃圾邮件检测、医疗诊断等领域。
而最近由于算法的突破和运算设备性能的提升,机器学习产生新的分支深度学习。相比于之前的机器学习算法,深度学习强调模型的深度,建立多层隐层节点,然后通过逐层的变换,提取多个特征,从而提升分类和预测的准确性。
其中笔者认为最有传奇色彩的是HUBEL和WIESEL对猫视觉皮层的研究,强调特征提取,信息从低维到高维的流动,以及随后的福岛邦彦的模仿。不扯开去了。
深度学习用在自动驾驶、对象识别、机器人、语音识别等领域。
希望语义鸿沟有一天能突破吧。
深度学习的分类
自下向上的非监督学习
没有去深入理解,大概是n-1层的输出去训练n层
自上向下的监督学习
给标定的输入,通过整体微调参数得到模型
深度学习模型的训练
就稍微学一下,感觉不怎么会考到
而且课本里应该是一个全连接神经网络,先鸽了。