Engineering Features
计算统计特性(量化字母的形状)
有什么统计数据可以提供关于字母形状的信息呢?不同的字母会有不同的点分布。
% 导入数据
load sampleletters.mat
plot(b1.Time,b1.X)
hold on
plot(b2.Time,b2.X)
hold off
plot(b1.Time,b1.Y)
hold on
plot(b2.Time,b2.Y)
hold off
% 计算字母b的比例
aratiob = range(b1.Y)/range(b1.X)
% 计算中值,使用omitnan参数消除NaN值的影响
medxb = median(b1.X,"omitnan")
medyb = median(b1.Y,"omitnan")
字母经过预处理,其均值为0(在X和Y中)。中值对异常值的敏感性低于均值。比较平均值和中位数可以让我们了解一个分布有多不对称。
% 平均绝对偏差(mean absolute deviation, MAD)
devxb = mad(b1.X) % mad函数自动忽略NaNs
devyb = mad(b1.Y)
值的扩散程度可以用平均绝对值偏差、标准差和方差来测量,每一项都是计算偏离均值的平均值。
然后对其它的字母样本做了重复的统计特性的计算。下图中绘制了8个字母样本的长宽比(aspect ratio)和字母横向的平均绝对值偏差(mean absolute deviation)
对比字母b和d,确实这些统计特性能够反映出字母形状上的不同。
寻找峰值
局部极小值和极大值通常是一个信号的重要特征。islocalmin和islocalmax函数能够实现寻找峰值的功能。
load sampleletters.mat
% islocalmin和islocalmax会返回一个与输入数据等长的向量,峰值处置1。
idxmin = islocalmin(m1.X)
idxmax = islocalmax(m1.X)
plot(m1.Time,m1.X)
hold on
plot(m1.Time(idxmin),m1.X(idxmin),"o")
plot(m1.Time(idxmax),m1.X(idxmax),"s")
hold off
局部极小值和极大值通过计算信号中每个值的突出度来定义。突出值是衡量一个值与周围其他值之间的比较。您可以通过从islocalmin或islocalmax获得第二个输出来获得信号中每个点的突出值。
[idx,prom] = islocalmin(m1.X);
plot(m1.Time,prom)
% 通过参数指定大于多少才是峰值
idxmin = islocalmin(m1.X,"MinProminence",0.1)
idxmax = islocalmax(m1.X,"MinProminence",0.1)
计算导数
检测书写在平板上的字母的一个重要方面是在字母书写过程中有用的信息。即横纵位置随时间变换的斜率。
对于离散的数据点,估计速度通过使用有限差分近似v =Δx /Δt。
load sampleletters.mat
plot(m2.Time,m2.X)
grid
dX = diff(m2.X);
dT = diff(m2.Time);
dXdT = dX./dT;
diff函数计算相邻两个元素之间的差值。所以输出会比输入少一个元素。在绘图时需要注意。
% 观察dXdT和dYdT的最大值
maxdx = max(dXdT)
dYdT = diff(m2.Y)./dT;
maxdy = max(dYdT)
% 结果maxdx=4.2971; maxdy=Inf
由于数据收集过程的分辨率的限制,数据包含一些重复的值。如果位置和时间都是重复的,那么差值都为0,则0/0=NaN。但是,如果位置值有非常轻微的不同,那么导数将是Inf(非零除以0)。
注意,max忽略NaN,但不忽略Inf,因为Inf大于任何有限值。但是,对于这个应用程序,NaN和Inf都可以忽略,因为它们表示重复的数据。可以使用standardizeMissing函数将一系列的值转化为NaN
dYdT = standardizeMissing(dYdT,Inf);
maxdy = max(dYdT)
计算相关(Correlations)
左边的一对信号与右边的一对信号具有明显不同的形状。但是两组信号之间的关系是相似的,在蓝色区域,上信号是增加的,下信号是减少的,在黄色区域是相反的。Correlation试图衡量这种相似性,而不管信号的形状如何。
字母V的前半部分,水平位置与垂直位置呈较强的线性负相关,水平位置增大,垂直位置成比例减小。同样的,在后半段,位置也有很强的正相关,当水平位置增加时,垂直位置也成比例增加。
% corr函数计算变量之间的线性相关。
load sampleletters.mat
plot(v2.X,v2.Y,"o-")
C = corr(v2.X,v2.Y) % corr函数计算变量之间的线性相关。
因为这两个变量都包含缺失的数据,所以C是NaN。您可以使用“Rows”选项来指定如何避免丢失值。
C = corr(v2.X,v2.Y,"Rows","complete")
相关系数总是在-1和+1之间。系数-1表示完全负线性相关,系数+1表示完全正线性相关,系数为0表示不存在线性相关。在这种情况下,只有一个适度的相关性,因为计算已经在整个信号上执行。分开考虑信号的两半可能更有用。
% 要计算每一对变量之间的相关性,可以向corr函数传递一个矩阵,其中每个变量是矩阵的一列。
M = [v2.X(1:11) v2.Y(1:11) v2.X(12:22) v2.Y(12:22)]
Cmat = corr(M,"Rows","complete")
自动化特征提取
一旦你决定你想要的特征提取,需要应用适当的计算每个样本的数据集。自动化这个过程的第一步是让一个自定义函数功能的数据作为输入,并返回一个数组作为输出。
目前,该脚本为给定的字母(存储在变量letter中)计算6个特性。这六个特性存储在六个单独的变量中。
可以使用table函数将单独的变量组合到一个表中。
load sampleletters.mat
letter = b1;
aratio = range(letter.Y)/range(letter.X)
idxmin = islocalmin(letter.X,"MinProminence",0.1);
numXmin = nnz(idxmin)
idxmax = islocalmax(letter.Y,"MinProminence",0.1);
numYmax = nnz(idxmax)
dT = diff(letter.Time);
dXdT = diff(letter.X)./dT;
dYdT = diff(letter.Y)./dT;
avgdX = mean(dXdT,"omitnan")
avgdY = mean(dYdT,"omitnan")
corrXY = corr(letter.X,letter.Y,"rows","complete")
featurenames = ["AspectRatio","NumMinX","NumMinY","AvgU","AvgV","CorrXY"];
默认情况下,用table函数构造的表有默认的变量名。要使表具有更有用的名称,请使用“VariableNames”选项。
T = table(x,y,z,‘VariableNames’,[“X”,“Y”,“Z”]);
通常可以使用单引号或双引号来指定选项名。但是,因为字符串可以表示表中的数据,所以在指定’VariableNames’选项时需要使用单引号。
feat = table(aratio,numXmin,numYmax,avgdX,avgdY,corrXY,'VariableNames',featurenames)
要自动化特征提取,需要数据存储在每次读取数据时应用提取功能。与预处理一样,您可以使用转换后的数据存储来完成此操作。
对于原始数据,通常需要同时应用预处理和特征提取功能。您可以重复应用transform()函数来向原始数据存储添加任意数量的转换。
% 把.txt的文件存一个datastore
letterds = datastore("*.txt");
% 通过函数scale(),把datastore1预处理成另一个datastore2
preprocds = transform(letterds,@scale);
% 通过函数extract(),把datastore2中的特征值提取成另一个datastore3
featds = transform(preprocds,@extract);
data1 = readall(letterds)
data2 = readall(preprocds)
data3 = readall(featds)
scatter(data3.AspectRatio,data3.CorrXY)
可以使用extractBetween()函数来提取给定字符串之间的文本。
% 提取原始datastore中的.Files字段数据。
knownchar = extractBetween(letterds.Files,"_","_")
对于分类问题,通常希望将已知标签表示为分类变量。可以使用categorical()函数将数组转换为分类类型。
knownchar = categorical(knownchar)
将已知的类与训练数据关联起来是很方便的。
使用gscatter()函数制作x轴上的AspectRatio和y轴上的CorrXY的分组散点图,按字符分组。
data.Character = knownchar
gscatter(data.AspectRatio,data.CorrXY,data.Character)
分类模型
训练和使用机器学习模型进行预测。
训练模型
letterdata.mat包含了了2906个字母样本的特征数据。有25个特征,包括统计测量,相关,和最大值/最小值的位置,速度,和压力的笔。
load letterdata.mat
traindata
histogram(traindata.Character) % 画一下26个字母的直方图
线箱图是可视化多个分布的一种简单方法。
boxplot(x, c)
这创建了一个图,图中的方框表示c中每个类的x值的分布。如果一个类的x值与另一个类的x值显著不同,那么x就是一个可以区分这些类的特性。您拥有的能够区分不同类的特性越多,您就越有可能从完整的数据集构建准确的分类模型。
boxplot(traindata.MADX,traindata.Character)
用分类模型进行预测
load letterdata.mat
traindata
knnmodel = fitcknn(traindata,"Character","NumNeighbors",5,"Standardize",true,"DistanceWeight","squaredinverse");
testdata
predLetter = predict(knnmodel,testdata)
misclassrate = sum(predLetter ~= testdata.Character)/numel(predLetter)
响应类在训练或测试数据中并不总是平均分布的。损失是对错误分类的更公平的衡量,它包含了每一类的概率(基于数据的分布)。
testloss = loss(knnmodel,testdata)
您可以计算已知正确类的任何数据集的损失。尝试确定原始训练数据(traindata)的丢失情况。这就是所谓的重新替换损失(训练数据被“重新替换”到模型中的损失)。您可以使用再减损失(knnmodel)直接计算再替换损失。
Investigating Misclassifications(Identifying Common Misclassifications)
根据预测结果和真实结果的关系,可以将机器学习模型的预测分为4类
称这个东西为Confusion矩阵。