web-dev-qa-db-ja.com

Matlabでホットエンコードするにはどうすればよいですか?

多くの場合、たとえば、ラベル(別名クラス)を表す整数値のベクトルが与えられます。

[2; 1; 3; 3; 2]

たとえば、ラベルベクトルの各行の値で示される列の各値が1で表されるように、このベクトルをホットワンエンコードする必要があります。

[0 1 0;
 1 0 0;
 0 0 1;
 0 0 1;
 0 1 0]
8
osipov

速度とメモリを節約するために、bsxfuneqと組み合わせて使用​​して同じことを実現できます。 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行列を(完全な行列に変換せずに)使用できる場合は、これが最速で最もメモリ効率の高いオプションです。 。

enter image description here

20
Suever

たとえば、ラベルベクトル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,:)
5
osipov

行列の次元が大きくなると、これは特に高速だと思います。

Y = sparse(1:numel(X), X,1);

または

Y = full(sparse(1:numel(X), X,1));
2
rahnema1

好奇心を満たすために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
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次元に沿ってワンホットエンコードされた行列を与えます。

0
mcExchange