如何在 Matlab 中进行热编码? [复制]
Posted
技术标签:
【中文标题】如何在 Matlab 中进行热编码? [复制]【英文标题】:How can I hot one encode in Matlab? [duplicate] 【发布时间】:2016-12-21 05:42:23 【问题描述】:例如,通常会给你一个整数值向量,代表你的标签(又名类)
[2; 1; 3; 3; 2]
并且您想对这个向量进行热编码,例如,每个值在由标签向量的每一行中的值指示的列中由 1 表示,例如
[0 1 0;
1 0 0;
0 0 1;
0 0 1;
0 1 0]
【问题讨论】:
你有什么尝试吗? 是的,我一直在尝试使用 sub2ind 的不同方法,但最终使用了对单位矩阵的索引,如下所示。 【参考方案1】:为了速度和节省内存,您可以使用bsxfun
与eq
组合来完成同样的事情。虽然您的eye
解决方案可能有效,但您的内存使用量会随着X
中唯一值的数量呈二次方增长。
Y = bsxfun(@eq, X(:), 1:max(X));
如果您愿意,也可以作为匿名函数:
hotone = @(X)bsxfun(@eq, X(:), 1:max(X));
或者,如果您使用的是 Octave(或 MATLAB R2016b 及更高版本),则可以利用自动广播,只需按照@Tasos 的建议执行以下操作。
Y = X == 1:max(X);
基准测试
这是一个快速基准测试,显示了在 X
上具有不同数量的元素以及在 X
中具有不同数量的唯一值的各种答案的性能。
function benchit()
nUnique = round(linspace(10, 1000, 10));
nElements = round(linspace(10, 1000, 12));
times1 = zeros(numel(nUnique), numel(nElements));
times2 = zeros(numel(nUnique), numel(nElements));
times3 = zeros(numel(nUnique), numel(nElements));
times4 = zeros(numel(nUnique), numel(nElements));
times5 = zeros(numel(nUnique), numel(nElements));
for m = 1:numel(nUnique)
for n = 1:numel(nElements)
X = randi(nUnique(m), nElements(n), 1);
times1(m,n) = timeit(@()bsxfunApproach(X));
X = randi(nUnique(m), nElements(n), 1);
times2(m,n) = timeit(@()eyeApproach(X));
X = randi(nUnique(m), nElements(n), 1);
times3(m,n) = timeit(@()sub2indApproach(X));
X = randi(nUnique(m), nElements(n), 1);
times4(m,n) = timeit(@()sparseApproach(X));
X = randi(nUnique(m), nElements(n), 1);
times5(m,n) = timeit(@()sparseFullApproach(X));
end
end
colors = get(0, 'defaultaxescolororder');
figure;
surf(nElements, nUnique, times1 * 1000, 'FaceColor', colors(1,:), 'FaceAlpha', 0.5);
hold on
surf(nElements, nUnique, times2 * 1000, 'FaceColor', colors(2,:), 'FaceAlpha', 0.5);
surf(nElements, nUnique, times3 * 1000, 'FaceColor', colors(3,:), 'FaceAlpha', 0.5);
surf(nElements, nUnique, times4 * 1000, 'FaceColor', colors(4,:), 'FaceAlpha', 0.5);
surf(nElements, nUnique, times5 * 1000, 'FaceColor', colors(5,:), 'FaceAlpha', 0.5);
view([46.1000 34.8000])
grid on
xlabel('Elements')
ylabel('Unique Values')
zlabel('Execution Time (ms)')
legend('bsxfun', 'eye', 'sub2ind', 'sparse', 'full(sparse)', 'Location', 'Northwest')
end
function Y = bsxfunApproach(X)
Y = bsxfun(@eq, X(:), 1:max(X));
end
function Y = eyeApproach(X)
tmp = eye(max(X));
Y = tmp(X, :);
end
function Y = sub2indApproach(X)
LinearIndices = sub2ind([length(X),max(X)], [1:length(X)]', X);
Y = zeros(length(X), max(X));
Y(LinearIndices) = 1;
end
function Y = sparseApproach(X)
Y = sparse(1:numel(X), X,1);
end
function Y = sparseFullApproach(X)
Y = full(sparse(1:numel(X), X,1));
end
结果
如果您需要非稀疏输出 bsxfun
表现最佳,但如果您可以使用 sparse
矩阵(无需转换为完整矩阵),那么这是最快且内存效率最高的选项。
【讨论】:
这是为什么呢?他只是在做一个简单的索引操作 哦,好吧,你说的是眼睛矩阵的大小。 @suever 我认为您的意思是内存使用量呈二次增长,因为 eye(max(X)) 占用 max(X)^2 内存。指数内存使用量为 c^max(X) @osipov 是的,你是对的。更新。我还添加了一个基准来显示这些技术的相对性能。 @TasosPapastylianou 是的,我指的是eye
不必要地庞大。【参考方案2】:
您可以使用单位矩阵并使用输入/标签向量对其进行索引,例如,如果标签向量 X 是某个随机整数向量
X = randi(3,5,1)
ans =
2
1
2
3
3
那么,下面将热一编码X
eye(max(X))(X,:)
可以方便地定义为一个函数使用
hotone = @(v) eye(max(v))(v,:)
编辑:
虽然上面的解决方案在 Octave 中有效,但你可以为 Matlab 修改它,如下所示
I = eye(max(X));
I(X,:)
【讨论】:
只指出链式操作在 matlab 中不起作用,因此您必须拆分单行。不错的解决方案。 @TasosPapastylianou 谢谢...我最初是用 Octave 编写的。刚刚用未链接的操作编辑了答案。 @Suever 内存使用绝对是需要牢记的重要因素。在机器学习问题的情况下,标签集的基数通常是可管理的,因此这种“热编码”方法是一种简单的入门方法。更理想的解决方案是在 Matlab/Octave 之外进行一些操作。 @osipov 在 MATLAB 中,最好从一开始就设计出可以很好扩展的东西,因为这样的事情很快就会失控(参见基准),不使用最佳的真的没有意义如果您有一个可以使用的解决方案。此外,正如基准所显示的,它是内存使用和执行时间。【参考方案3】:我认为这在矩阵维度增长时特别快:
Y = sparse(1:numel(X), X,1);
或
Y = full(sparse(1:numel(X), X,1));
【讨论】:
【参考方案4】:只需发布sub2ind
解决方案即可满足您的好奇心 :)
但我更喜欢你的解决方案:p
>> X = [2,1,2,3,3]'
>> LinearIndices = sub2ind([length(X),3], [1:length(X)]', X);
>> tmp = zeros(length(X), 3);
>> tmp(LinearIndices) = 1
tmp =
0 1 0
1 0 0
0 1 0
0 0 1
0 0 1
【讨论】:
【参考方案5】:以防万一有人正在寻找 2D 案例(就像我一样):
X = [2 1; ...
3 3; ...
2 4]
Y = zeros(3,2,4)
for i = 1:4
Y(:,:,i) = ind2sub(X,X==i)
end
给出一个沿第 3 维的 one-hot 编码矩阵。
【讨论】:
以上是关于如何在 Matlab 中进行热编码? [复制]的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 sklearn 对 CSV 文件中的多列进行一次热编码?