特征工程
机器学习算法需要特定形式的数据结构。信号带有许多的特征可用于区分不同的事物。构建预测模型时,这些特征作为预测输入。需要将原始数据转化为一组特征。特征是整个信号的简单 统计度量、形状的度量,如局部最大数目或波峰的宽度、相关性的度量或任何数量的其他度量。有针对声音、振动或心跳等周期信号的方法,这些方法一般把一个信号分解成若干个简单分量并确定各个分量对整个信号的贡献。可以把许多周期性信号表示为不同频率的正弦和余弦的组合。
统计函数
集中趋势的度量
函数 | 说明 |
---|---|
mean | 算术均值 |
median | 中位数(中间)值 |
mode | 出现次数最多的值 |
trimmean | 截尾均值(均值,不包括离群值) |
geomean | 几何均值 |
harmean | 调和均值 |
散布的度量
函数 | 说明 |
---|---|
range | 值的极差(最大 - 最小) |
std | 标准差 |
var | 方差 |
mad | 均值绝对偏差 |
iqr | 四分位差(第 75 个百分位数减去第 25 个百分位数) |
形状的度量
函数 | 说明 |
---|---|
skewness | 偏度(第三个中心矩) |
kurtosis | 峰度(第四个中心矩) |
moment | 任意阶中心矩 |
描述性统计量
- 计算汇总统计量(量化字母形状)
字迹采样均进行了偏移处理,使它们在水平和垂直位置的均值都为零。与均值相比,中位数对离群值较不敏感。将均值与中位数进行比较,可以了解分布的不对称程度。值的散布可以用均值绝对偏差 (MAD)、标准差和方差来衡量。上述每一项都计算一种偏离均值的度量的平均值。默认情况下 mad 会忽略 NaN。
- 纵横比
- 中位数
- 均值绝对偏差
aratiovb = range(b1.Y)/range(b1.X)
medxb = median(b1.X,"omitnan")
medyb = median(b1.Y,"omitnan")
devxb = mad(b1.X)
devyb = mad(b1.Y)
不同字母的值如何比较?这些统计量会是有用的特征吗?
b与d的比较:中位数(水平值) b为负,d为正
- 查找峰值
局部最小值和最大值通常是信号的重要特征。islocalmin 和 islocalmax 函数接受信号作为输入,并返回与该信号长度相同的逻辑数组。
idxmin = islocalmin(x);
idxmax = islocalmax(x);
当 idx 在信号中的对应值为局部最小/大值时,它的值为 true。
通过计算信号中每个值的相对高差来定义局部最小值和最大值。相对高差用于度量一个值与其周围其他值的相对差别程度。您可以通过 islocalmin 或 islocalmax 的第二个输出来获得信号中每个点的相对高差值。
[idx,prom] = islocalmin(x);
prom为峰值;
默认情况下,islocalmin 和 islocalmax 将查找任何相对高差值大于 0 的点。这意味着按照定义,任意点只要大于位于其两侧的两个值,即为最大值。对于含噪信号,可能只想考虑相对高差高于给定阈值的最小值和最大值。
idx = islocalmin(x,"MinProminence",threshvalue)
选择阈值时,请注意相对高差值的范围可以从 0 到 range(x)。
将 idxmin 传递给 nnz 或 sum 函数来对最小值计数。不同信号中局部最小值和最大值的数目不同。
- 计算导数
平板电脑记录的原始数据只包含不同时间的位置信息(没有速度),因此必须从原始数据计算速度。对于离散数据点,这意味着需要通过使用有限差分逼近 v=Δx/Δt 来估计速度。
- diff 函数计算数组中连续元素之间的差值。即,如果 y = diff(x),则 y1=x2−x1,y2=x3−x2,以此类推。请注意,y 比 x 少一个元素。
将 dX 除以 dT 来计算 m2.X 的近似导数。请记住使用数组除法运算符(./)
diff 函数的输出比输入少一个元素。绘制dXdT 随 m2.Time 变化的图,不包括最终值可以使用 end 关键字来引用数组中的最后一个元素。
dY = diff(m2.Y)
dX = diff(m2.X);
dT = diff(m2.Time);
dYdT = dY./dT
dXdT = dX./dT
maxdx = max(dXdT)
maxdy = max(dYdT)
plot(m2.Time(1:end-1),dXdT)
♦️受数据采集过程的分辨率限制,数据会包含一些重复值。如果位置和时间都重复,则差值都是 0,这会得到导数 0/0 = NaN。然而,如果位置值有极微小的差异,则导数为 Inf(非零值除以 0)。
请注意,max 会忽略 NaN 但不会忽略 Inf,因为 Inf 大于任何有限值。然而,这里的应用可以忽略 NaN 和 Inf,因为它们表示重复数据。
可以使用 standardizeMissing 函数将一系列值转换为 NaN(或非数值数据类型的缺失值)。
xclean = standardizeMissing(x,0);
dYdT = standardizeMissing(dYdT,Inf)
xclean = standardizeMissing(x,[-Inf 0 Inf]);
在此处,xclean 与 x 相同(包括其中的任何 NaN),只是在 x 具有值 0 的对应位置都会转换为 NaN。dYdT的所有Inf值全部转化为Nan。负值被零除将得到 -Inf。可以将值的向量传递给 standardizeMissing ,以便一次处理多个缺失值。
- 计算相关性
对于字母 V 的前半部分,水平和垂直位置有很强的负线性相关性:随着水平位置增大,垂直位置成比例减小。同样,对于后半部分,两个位置具有很强的正相关性:随着水平位置增大,垂直位置也成比例增大。
corr 函数计算变量之间的线性相关性。
C = corr(x,y);
C = corr(v2.X,v2.Y,"Rows","complete")
由于两个变量都包含缺失数据,C 为 NaN。将 "Rows" 选项设置为 "complete",来比避免缺失值。
相关系数始终在 -1 和 +1 之间。
- 当系数为 -1时, 表示完全负线性相关
- 当系数为 +1 时,表示完全正线性相关
- 当系数为 0 时,表示无线性相关。
计算每对变量之间的相关性,可以将矩阵传递给 corr 函数,其中每个变量均为矩阵的一列。
M = [a b c d];
Cmat = corr(M,"Rows","complete");
输出 Cmat 是一个 4×4 矩阵,其中包含 M 的两两列之间的相关系数。即 Cmat(j,k) 是 M(:,j) 和 M(:,k) 之间的相关性。该矩阵是对称矩阵,因为 x 和 y 之间的相关性与 y 和 x 之间的相关性相同。对角线元素始终等于 1,因为变量始终与自身完美相关。
M 的前两列是信号的前半部分的水平和垂直位置;最后两列是信号的后半部分的水平和垂直位置。对于字母 V ,即前两列是负相关,后两列正相关。
- 自动化特征提取
一旦确定了要提取的特征,就需要对数据集中的每个采样应用适当的计算。自动化此过程的第一步是创建一个自定义函数,该函数接受数据作为输入,并返回一个特征数组作为输出。
load sampleletters.mat
letter = b1;
featB1 = extract(letter)
function feat = extract(letter)
% Aspect ratio
aratio = range(letter.Y)/range(letter.X);
% Local max/mins
idxmin = islocalmin(letter.X,"MinProminence",0.1);
numXmin = nnz(idxmin);
idxmax = islocalmax(letter.Y,"MinProminence",0.1);
numYmax = nnz(idxmax);
% Velocity
dT = diff(letter.Time);
dXdT = diff(letter.X)./dT;
dYdT = diff(letter.Y)./dT;
avgdX = mean(dXdT,"omitnan");
avgdY = mean(dYdT,"omitnan");
% Correlation
corrXY = corr(letter.X,letter.Y,"rows","complete");
% Put it all together into a table
featurenames = ["AspectRatio","NumMinX","NumMinY","AvgU","AvgV","CorrXY"];
feat = table(aratio,numXmin,numYmax,avgdX,avgdY,corrXY,'VariableNames',featurenames);
end
需要数据存储在每次读取数据时应用提取函数。
多个数据文件中提取特征
文件名包含数据表示的字母,其形式为 usernnn_X_n.txt。请注意,字母名称出现在下划线字符之间 (X)。可以使用 extractBetween 函数提取出现在给定字符串之间的文本。
extractedtxt = extractBetween(txt,"abc","xyz")
如果 txt 是字符串数组 ["hello abc 123 xyz","abcxyz","xyzabchelloxyzabc"],则 extractedtxt 将是 [" 123 ","","hello"]。
对于分类问题,通常希望将已知标签表示为分类变量。您可以使用 categorical 函数将数组转换为分类类型。
xcat = categorical(x)
默认情况下,x 中的唯一值将用于定义类别集。
letterds = datastore("*.txt");
preprocds = transform(letterds,@scale)
featds = transform(preprocds,@extract)
data = readall(featds)
knownchar = extractBetween(letterds.Files,"_","_")
knownchar = categorical(knownchar)
data.Character = knownchar
gscatter(data.AspectRatio,data.CorrXY,data.Character)
function data = scale(data)
% Normalize time [0 1]
data.Time = (data.Time - data.Time(1))/(data.Time(end) - data.Time(1));
% Fix aspect ratio
data.X = 1.5*data.X;
% Center X & Y at (0,0)
data.X = data.X - mean(data.X,"omitnan");
data.Y = data.Y - mean(data.Y,"omitnan");
% Scale to have bounding box area = 1
scl = 1/sqrt(range(data.X)*range(data.Y));
data.X = scl*data.X;
data.Y = scl*data.Y;
end
function feat = extract(letter)
% Aspect ratio
aratio = range(letter.Y)/range(letter.X);
% Local max/mins
idxmin = islocalmin(letter.X,"MinProminence",0.1);
numXmin = nnz(idxmin);
idxmax = islocalmax(letter.Y,"MinProminence",0.1);
numYmax = nnz(idxmax);
% Velocity
dT = diff(letter.Time);
dXdT = diff(letter.X)./dT;
dYdT = diff(letter.Y)./dT;
avgdX = mean(dXdT,"omitnan");
avgdY = mean(dYdT,"omitnan");
% Correlation
corrXY = corr(letter.X,letter.Y,"rows","complete");
% Put it all together into a table
featurenames = ["AspectRatio","NumMinX","NumMinY","AvgU","AvgV","CorrXY"];
feat = table(aratio,numXmin,numYmax,avgdX,avgdY,corrXY,'VariableNames',featurenames);
end