MATLAB находит и применяет функцию к значениям повторяющихся индексов

У меня есть матрица 352x11, проиндексированная столбцом 1 с 10 точками данных. Некоторые значения индекса повторяются. Я хотел бы найти повторяющиеся индексы и рассчитать средние точки данных для повторных испытаний (избегая циклов, если это возможно).

Например,

x =

   26   77.5700   17.9735   32.7200
   27   40.5887   16.6100   31.5800
   28   60.4734   18.5397   33.6200
   28   35.6484   27.2000   54.8000
   29   95.3448   19.0000   37.7300
   30   82.7273   30.4394   39.1400

в итоге:

ans =

   26   77.5700   17.9735   32.7200
   27   40.5887   16.6100   31.5800
   28   48.0609   22.8699   44.2150
   29   95.3448   19.0000   37.7300
   30   82.7273   30.4394   39.1400

Я думал, если бы я использовал

J = find(diff(x(:,1))==0);

чтобы найти положение повторяющихся значений, я мог бы затем применить функцию к соответствующим позициям x, но с чего мне начать?


person 8eastFromThe3ast    schedule 18.04.2013    source источник


Ответы (4)


Вы можете применить accumarray к нескольким столбцам как показано здесь

labels = x(:,1) - min(x(:, 1)) + 1; 
labels = [repmat(labels(:),size(x,2),1), kron(1:size(x,2),ones(1,numel(labels))).'];             
totals = accumarray(labels,x(:),[], @mean);

Это адаптировано из кода Gnovice.

Чтобы заставить его работать для вашего кода, вам нужно удалить все нули впереди

totals(find(mean((totals == zeros(size(totals)))')), :) = [];

что приводит к желаемому

   26.0000   77.5700   17.9735   32.7200
   27.0000   40.5887   16.6100   31.5800
   28.0000   48.0609   22.8699   44.2100
   29.0000   95.3448   19.0000   37.7300
   30.0000   82.7273   30.4394   39.1400
person Dan    schedule 18.04.2013
comment
Похоже, вы сделали это снова, это просто билет! Большое спасибо, я весь день бился головой о стену, пытаясь что-то придумать. - person 8eastFromThe3ast; 18.04.2013
comment
Однако это решение не является надежным (в основном потому, что я не понимаю, как оно работает) - исправление в конце, чтобы избавиться от нулей, не является хорошим знаком. Например, я не уверен, что произойдет, если в первом столбце будут минусы... над этим еще нужно поработать, но я думаю, что пока это работает. - person Dan; 18.04.2013
comment
labels = x(:,1); эту строку нужно улучшить, если только x(:,1) не содержит только положительные целые числа, которые всегда увеличиваются. Постоянное увеличение легко решается с помощью sortrows, а положительное легко решается с помощью labels = x(:,1) - min(x(:, 1)) + 1, что, я думаю, также устраняет проблему заполнения нулями. - person Dan; 18.04.2013
comment
Да, первый столбец — это индекс номера участника, поэтому отрицательных значений нет! На данный момент он отлично справляется со своей задачей, так что я пойду с ним. - person 8eastFromThe3ast; 18.04.2013
comment
Я думаю, что исправил это сейчас, я изменил первую и последнюю строки кода - person Dan; 18.04.2013
comment
@Dan Я думаю, наши решения похожи, единственное, что отличается, это то, как мы создаем матрицу индексов индексов. - person Eitan T; 18.04.2013
comment
@EitanT Я должен быть честным, возможно, я заставил это работать, но я действительно этого не понимаю. Ваше решение не требует удаления нулей в конце, хотя и поставляется с объяснением, поэтому мне кажется лучшим выбором - person Dan; 18.04.2013

Более общий подход будет использовать unique для поиска уникальных значений индекса:

[U, ix, iu] = unique(x(:, 1));

а затем accumarray:

[c, r] = meshgrid(1:size(x, 2), iu);
y = accumarray([r(:), c(:)], x(:), [], @mean);

Объяснение

Входные значения для обработки на самом деле являются вторым параметром accumarray.

первый параметр accumarray — это матрица, каждая строка которой представляет собой набор индексов в (накопленной) выходной матрице, и он соответствует значению из соответствующей строки в векторе, заданном как второй параметр.

Думайте о выходе как о массиве ячеек. Вторые параметры являются входными значениями, и каждая строка в первом параметре сообщает, в какой ячейке выходной матрицы accumarray должно храниться соответствующее входное значение. Когда вывод «массива ячеек» завершен, к каждой ячейке применяется функция (в нашем случае mean).

Пример

Вот короткий пример с меньшей матрицей:

x = [27, 10, 8;
     28, 20, 10;
     28, 30, 50];

Мы находим уникальные значения:

[U, ix, iu] = unique(x(:, 1));

Вектор U хранит уникальные значения, а iu указывает, какой индекс значения связан с каждой строкой (обратите внимание, что в этом решении мы не используем ix ). В нашем случае получаем, что:

U = 
    27
    28

iu =
    1
    2
    2

Теперь применяем accumarray:

[c, r] = meshgrid(1:size(x, 2), iu);
y = accumarray([r(:), c(:)], x(:), [], @mean);

Причудливый трюк с meshgrid и [r(:), c(:)] создает набор индексов:

[r(:), c(:)] =
     1     1
     2     1
     2     1
     1     2
     2     2
     2     2
     1     3
     2     3
     2     3

и это индексы для входных значений x(:), которые являются эквивалентом вектора-столбца x:

x(:) =
    27
    28
    28
    10
    20
    30
     8
    10
    50

Процесс накопления:

  • Первое значение 27 помещается в ячейку ‹1,1> в выходной матрице.
  • Второе значение 28 помещается в ячейку ‹2,1> в выходной матрице.
  • Третье значение 28 помещается в ячейку ‹2,1> в выходной матрице.

Видишь, что только что произошло? Оба значения 28 накапливаются в одной и той же ячейке (и в конечном итоге они будут усреднены). Процесс продолжается:

  • Четвертое значение 10 помещается в ячейку ‹1,2> в выходной матрице.

и так далее...

Как только все значения сохранены в ячейках, функция mean применяется к каждой ячейке, и мы получаем окончательную выходную матрицу:

y =
    27    10     8
    28    25    30
person Eitan T    schedule 18.04.2013
comment
@8eastFromThe3ast Я добавил для вас объяснение. - person Eitan T; 18.04.2013
comment
@8eastFromThe3ast Это более надежное решение. - person Dan; 18.04.2013
comment
@Eitan T Gosh, это подробно! Большое спасибо. На данный момент кладж Дэна работает очень хорошо, но когда у меня будет немного больше времени, я проработаю ваше предложение и посмотрю, какое из них работает лучше! Спасибо еще раз - person 8eastFromThe3ast; 18.04.2013
comment
@8eastFromThe3ast Нет проблем. Цель состоит в том, чтобы учиться, и мы все здесь, чтобы помогать друг другу. - person Eitan T; 18.04.2013
comment
Решения Дэна и Эйтана в основном одинаковы, единственная разница заключается в том, как создается матрица субтитров (меток). На мой взгляд, решение Eitan чище, и я лично предпочитаю meshgrid или даже пару вызовов repmat. Раньше Крон работал медленнее. - person Oleg; 18.04.2013
comment
Я чувствую себя обязанным пойти с Эйтаном только из-за объяснения! На самом деле оказалось, что (по крайней мере, для моих данных) решение Дэна быстрее (0,0781 с против 0,1094), но я предполагаю, что это может измениться с большим количеством данных? - person 8eastFromThe3ast; 18.04.2013
comment
@8eastFromThe3ast Позвольте Дэну оставить галочку, его решение действительно работает, поэтому он его заслужил. Суть в том, что вам предлагается выбрать решение, которое лучше всего подходит для вас. - person Eitan T; 18.04.2013
comment
@EitanT @Dan Поскольку оба ваших решения работают так хорошо, я думаю применить ту же концепцию к другому расчету, который мне нужно сделать. Можно ли одновременно индексировать данные по двум столбцам, чтобы accumarray применяла функцию mean к каждому дублирующемуся индексу, но только тогда, когда значения в другом столбце совпадают? Было бы лучше, если бы я задал новый вопрос по этому поводу? - person 8eastFromThe3ast; 19.04.2013
comment
@ 8eastFromThe3ast новый вопрос предпочтительнее, но я настоятельно рекомендую вам сначала попробовать его самостоятельно. Все дело в построении параметров SUBS и VALS для accumarray соответственно. - person Eitan T; 19.04.2013

Вы можете найти accumarray с @mean полезным:

Предполагая, что первый столбец содержит значения 1 .. k для некоторого k <= size(x,1), вы можете вычислить каждый столбец вывода, используя

col = accumarray( x(:,1), x(:,2), [], @mean ); % second column
person Shai    schedule 18.04.2013
comment
Я пытался использовать accumarray, но поскольку я хотел бы применить функцию к нескольким столбцам одновременно, мои значения VAL несовместимы с функцией. - person 8eastFromThe3ast; 18.04.2013
comment
@8eastFromThe3ast, но теперь вы можете просто перебирать столбцы - person Dan; 18.04.2013

Учитывая ваш ввод

x = [ ...
    26   77.5700   17.9735   32.7200; ...
    27   40.5887   16.6100   31.5800; ...
    28   60.4734   18.5397   33.6200; ...
    28   35.6484   27.2000   54.8000; ...
    29   95.3448   19.0000   37.7300; ...
    30   82.7273   30.4394   39.1400];

Вы можете создать массив индексов, в котором дублированные vgalue используют один и тот же индекс, используя третий вывод unique.

%Get index of unique values (1 - N)
[~, ~, ix] = unique(x(:,1))

Затем вы можете использовать этот массив, чтобы перестроить свою матрицу, комбинируя повторяющиеся значения с функцией по вашему выбору.

%Use accumarry to rebuild the matrix one column at a time
result = [...
    accumarray( ix, x(:,1), [], @max )  ...  %Many functions works here, as all inputs are the same.  E.G.  @mean, @max, @min
    accumarray( ix, x(:,2), [], @mean ) ...  %Use mean to combine data, per problem statement.
    accumarray( ix, x(:,3), [], @mean ) ...
    accumarray( ix, x(:,4), [], @mean ) ...
    ]
person Pursuit    schedule 18.04.2013
comment
+1 за использование accumarray, -1 для построения столбцов по одному :) вы можете заставить accumarray строить все столбцы сразу, если правильно строите ix... - person Eitan T; 18.04.2013
comment
:) Пункт отмечен. Я никогда не использую accumaray изо дня в день; Я все еще учусь тому, что он может сделать. - person Pursuit; 18.04.2013