2015-05-30 4 views
3

Учитывая матрицу X, я хочу установить k наименьших элементов каждого столбца равным нулю. Для вектора х, я делаю следующее:MATLAB - Разрешить столбцы матрицы, заданной матрицей индексов

[~, ind] = sort(x) 
x(ind(1:k)) = 0 

Теперь для матрицы X, это не работает:

[~, IND] = sort(X) 
X(IND(1:k)) = 0 

Просто устанавливает K наименьший элемент первого столбца 0. Как я правильно его индексирую?

ответ

3

Решение Код: Один подход с sort (для получения индексов по столбцам отсортирован) & затем bsxfun (чтобы получить линейные упорядоченные индексы) -

%// Get 2D array of column-sorted indices for input X 
[~,sorted_idx] = sort(X,1) 

%// Get linear indices for the first k rows of sorted indices 
lin_idx = bsxfun(@plus,sorted_idx(1:k,:),[0:size(X,2)-1]*size(X,1)) 

%// Use those indices to set them in X as zeros 
X(lin_idx) = 0; 

Пример запуска

1) Входы:

X = 
    61 67 86 54 49 40 13 
    48 91 28 70 34 98 87 
    79  7 27 86 71 58 52 
    16 10 45 60 79  4  3 
    56 36 49 50 31 48 87 
k = 
    3 

2) Отсортированные показатели:

>> [~,sorted_idx] = sort(X,1) 
sorted_idx = 
    2  3  2  1  1  1  1 
    4  4  3  4  2  4  3 
    5  5  4  5  5  5  4 
    1  1  5  2  3  3  2 
    3  2  1  3  4  2  5 

3) Выбрать только первые к индексам из каждой колонки:

>> sorted_idx(1:k,:) 
ans = 
    4  3  3  5  5  4  4 
    2  4  2  1  2  1  1 
    5  5  4  4  1  5  3 

4) Нам нужно преобразовать эти столбцы индексов для линейных индексов, соответствующих 2D массив, X. Таким образом, после индексации столбца, используемого в MATLAB, первый столбец остается таким, как он есть, второй столбец должен иметь смещение number of rows in X, добавленный третий столбец, и добавляется до тех пор, пока не будут покрыты все столбцы.

Выражаясь математически, мы имели бы [0 5 10 15 20 25 30], т.е. [0:6]*5, т.е. положить в общем случае [0:size(X,2)-1]*size(X,1), добавляется к sorted_idx(1:k,:). Поскольку нам нужно сделать это для каждой строки sorted_idx(1:k,:), мы можем использовать автоматическое расширение и суммирование (с @plus) с bsxfun. Обратите внимание, что это будет сделано в векторном виде. Таким образом, здесь будет происходить расширение [0:size(X,2)-1]*size(X,1), а затем будут выполняться элементарные суммы с sorted_idx(1:k,:) с использованием @plus. Таким образом, мы имели бы столь необходимые линейные показатели, как так -

>> lin_idx = bsxfun(@plus,sorted_idx(1:k,:),[0:size(X,2)-1]*size(X,1)) 
lin_idx = 
    4  8 13 20 25 29 34 
    2  9 12 16 22 26 31 
    5 10 14 19 21 30 33 

5) Наконец, мы используем эти индексы, чтобы выборочно устанавливать нули в X с X(lin_idx) = 0.

+0

Если у вас есть время, не могли бы вы объяснить, что именно делает bsxfun? Это значительно улучшит этот ответ с помощью такого элегантного решения. – spurra

+1

@BananaCode В него добавлено некоторое объяснение. – Divakar

1

Использование quantile (Statistics Toolbox):

X = X .* bsxfun(@ge, X, quantile(X, k/size(X,1))); 

Как это работает:

  1. quantile(X, k/size(X,1)) дает для каждого столбца, число (квантиль) такое, что фракция k/size(X,1)) из записей в этой колонке меньше этого числа. Это означает, что в каждом столбце точно k записей меньше, чем квантиль столбца.
  2. Сравнение каждого столбца с соответствующим квантилем (bsxfun(@ge, ...)) дает матрицу, содержащую 0 для записей, меньших, чем квантиль, и 1 в противном случае.
  3. Элементарное умножение A по результату 2 делает желаемые значения A равными 0.

Пример:

>> X = rand(5,3) 
X = 
    0.088188645571510 0.907109055220371 0.805984932289666 
    0.683710335821638 0.860456667336885 0.868488116302772 
    0.120400876857723 0.338451384118250 0.669646599875533 
    0.010699003144174 0.027158829325862 0.807778862315076 
    0.557268230074914 0.800859355130033 0.897498282302820 
>> k=2; 
>> X = X.*bsxfun(@ge, X, quantile(X,k/size(X,1))) 
X = 
        0 0.907109055220371     0 
    0.683710335821638 0.860456667336885 0.868488116302772 
    0.120400876857723     0     0 
        0     0 0.807778862315076 
    0.557268230074914 0.800859355130033 0.897498282302820 
+1

Этот ответ выглядит очень интересным. Объяснение того, как это работает, в значительной степени поможет его полезности. – spurra

+1

@BananaCode Готово! –

Смежные вопросы