要求:随机生成两组数据,每组50个数,其中一组服从正态分布,另一组服从N(1,1) 。编写一个code:
Input:上面产生的100个数,类别数:2
Output:1、0标签序列(每个标签对应每个数)
评估以上code输出结果的准确度。(准确度标准:查准率、查全率)
查准率:
查全率:
PR图理解错了,不是多个独立的样例,而是修改阈值,我一直用的是>=0.5判为1,即阈值设置的是0.5,应该修改这个阈值
另外老师会嫌弃只用查准率、查全率,建议画AUC曲线等(感觉被嫌弃了_(:з」∠)_)
数据生成:
X_1=normrnd(0,1,1,50);
y_1=ones(1,50);
X_2=normrnd(1,1,1,50);
y_2=zeros(1,50);
X_p=[X_1,X_2];
y_p=[y_1,y_2];
c=randperm(numel(X_p)); %打乱顺序
X=X_p(c(1:numel(X_p))); %数据集
y=y_p(c(1:numel(X_p)));
X=X';
y=y';
一、十折交叉验证
function [p r]=cross(X,y,fold);
indices=crossvalind('Kfold',100,fold); %Indices = crossvalind('Kfold', N, K) K折交叉
p=0;
r=0;
% cp=classperf(X);
for i=1:fold
test=(indices==i);
train=~test;
train_x=X(train,:);
train_y=y(train,:);
test_x=X(test,:);
test_y=y(test,:);
b=glmfit(train_x,train_y,'binomial','link','logit');%用逻辑回归来计算系数矩阵
logitFit=glmval(b,test_x,'logit'); %用逻辑回归的结果预测测试集的结果
logitFit=(logitFit>=0.5); %如果概率值不小于0.5,就认为是1,否则是0
pp=0;
rr=0;
tpfp=length(find(logitFit==1)); %预测出来的正例
tpfn=length(find(test_y==1)); %正例真正个数
m=length(test_y);
tp=0;
for j=1:m
if((test_y(j)==logitFit(j))&&(test_y(j)==1))
tp=tp+1; %预测出来的正确的正例个数
end;
end;
if(tpfp)
pp=tp/tpfp; %一次验证得到的查准率
end;
if(tpfn)
rr=tp/tpfn; %一次验证得到的查全率
end;
p=p+pp;
r=r+rr;
end
p=p/fold; %求平均值
r=r/fold;
数据展示:
P=zeros(100,1);
R=zeros(100,1);
for k=1:100
[P(k) R(k)]=cross(X,y,10);
end;
figure;
plot(P,R,'rx','MarkerSize',10);
title('100 times 10 fold cross valindation');
xlabel('查准率');
ylabel('查全率');
当然每次生成的数据集不一样,结果也很随机~
特例:当fold=N(样本数),就是留一法
[P R]=cross(X,y,100); %为啥留一法出来的值那么低,
训练出来的结果查准率和查全率都在0.3左右
二、留出法
留出法实现参考博客
function [P R]=split(X,y,k,ratio)
m=size(X,1);
y_labels=unique(y); %去重,只留下标记
train_x=[];
train_y=[];
d=[1:m]';
for i=1:k
class_i=find(y==y_labels(i));
if isempty(class_i)
continue;
end
size_i=length(class_i); %打乱标记i
rp=randperm(size_i);
rp_ratio=rp(1:floor(size_i*ratio)); %在标记i中取ratio作为训练集 以保证每个类别都取出一定的数量来训练
indices=class_i(rp_ratio); %i类作为训练集的下标
train_x=[train_x;X(indices,:)];
train_y=[train_y;y(indices,:)];
d=setdiff(d,indices); %训练集以外为测试集
end
test_x=X(d,:);
test_y=y(d,:);
P-R图
(注意P-R图绘制方法是错的,还没修改)
正确方法是将logitFit按照从大到小顺序排序,每次以一个logitFit作为正例和反例的界限,计算P值和R值
for r=1:1:100
tpfn=length(find(test_y==1)); %正例真正个数
b=glmfit(train_x,train_y,'binomial','link','logit');%用逻辑回归来计算系数矩阵
logitFit=glmval(b,test_x,'logit'); %用逻辑回归的结果预测测试集的结果
logitFit=(logitFit>=1.0*r/100);
% P=0;
% R=0;
tpfp=length(find(logitFit==1)); %预测出来的正例
m=length(test_y);
tp=0;
% plot(logitFit,test_y,'rx');
for j=1:m
if((test_y(j)==logitFit(j))&&(test_y(j)==1))
tp=tp+1;
end
end
if(tpfp)
P(r)=tp/tpfp;
end
if(tpfn)
R(r)=tp/tpfn;
end
end;
plot(P,R);
阈值由0.01到1,步长0.01
三、自助法
function [P R]=bootstrap(X,y)
m=size(X,1); %得到样本个数
train_x=[];
train_y=[];
d=[1:m]';
for i=1:m
indices=unidrnd(m);
train_x=[train_x;X(indices,:)];
train_y=[train_y;y(indices,:)];
d=setdiff(d,indices);
end
test_x=X(d,:);
test_y=y(d,:);
四、总结
讲道理小数据自助法应该比较好用,是不是我代码写崩了