多くの場合、たとえば、ラベル(別名クラス)を表す整数値のベクトルが与えられます。
[2; 1; 3; 3; 2]
たとえば、ラベルベクトルの各行の値で示される列の各値が1で表されるように、このベクトルをホットワンエンコードする必要があります。
[0 1 0;
1 0 0;
0 0 1;
0 0 1;
0 1 0]
速度とメモリを節約するために、bsxfun
をeq
と組み合わせて使用して同じことを実現できます。 eye
ソリューションは機能する可能性がありますが、メモリ使用量はX
の一意の値の数に応じて2次関数的に増加します。
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
行列を(完全な行列に変換せずに)使用できる場合は、これが最速で最もメモリ効率の高いオプションです。 。
たとえば、ラベルベクトル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,:)
行列の次元が大きくなると、これは特に高速だと思います。
Y = sparse(1:numel(X), X,1);
または
Y = full(sparse(1:numel(X), X,1));
好奇心を満たすために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
誰かが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次元に沿ってワンホットエンコードされた行列を与えます。