Позволяя accmarray выводить таблицу

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

A = [11:20]; 
B = flipud([11:20]); 
C = 1:10;
datamatrix = accumarray([A B],C);

Сюда datamatrix будет 20x20 матрица со значениями. Если значения A а также B однако они очень большие, в результате получается в основном пустая матрица с небольшим пакетом данных в дальнем углу. Чтобы обойти это, можно установить accumarray в issparse:

sparsedatamatrix = accumarray([A B],C,[],@sum,[],true);

Это сэкономит много памяти в случае min(A) и / или min(B) очень большой

Моя проблема, однако, в том, что у меня есть Mx7 матрица, с M~1e8на котором я хочу собрать средние значения столбцов с третьего по седьмой на основе индексации в первых двух столбцах и стандартного отклонения третьего столбца на основе третьего:

result = accumarray([data(:,1) data(:,2)],data(:,3),[],@std);

Я хочу сохранить это обратно в таблицу, структурированную как [X Y Z std R G B I], где X а также Y являются индексами, Z средняя высота этого пикселя,R, G, B а также I средние значения (цвет и интенсивность) на пиксель и std стандартное отклонение высоты (то есть шероховатости). С использованием issparse в этом случае не помогает, так как я преобразовываю свои матрицы в результате accumarray с помощью repmat,

Смысл этого кода - оценить высоту, шероховатость, цвет и интенсивность участка земли из облака точек. Я округлил координаты по осям X и Y, чтобы создать сетку, и теперь мне нужны эти средние значения для каждой ячейки сетки, но они выводятся как "таблица" (не тип данных MATLAB, а двумерный массив, который не является выходом матрицы по умолчанию).

Итак, в заключение вопроса:

Есть ли способ для accumarray или аналогичная функция для вывода этой таблицы без промежуточной (потенциально очень большой) матрицы?

Код ниже:

Xmax = max(Originaldata(:,1));
Ymax = max(Originaldata(:,2));
X_avg_grid=(Edgelength:Edgelength:Xmax*Edgelength)+Xorig;
TestSet = zeros(Xmax*Ymax,9);

xx = [1:length(X_avg_grid)]'; %#ok<*NBRAK>
TestSet(:,1) = repmat(xx,Ymax,1);
ll = 0:Xmax:Xmax*Ymax;
for jj = 1:Ymax
    TestSet(ll(jj)+1:ll(jj+1),2) = jj;
end

for ll = 1:7
    if ll == 2
        tempdat = accumarray([Originaldata(:,1) Originaldata(:,2)],Originaldata(:,3),[],@std);
        tempdat = reshape(tempdat,[],1);
        TestSet(:,ll+2) = tempdat;
    elseif ll == 7
        tempdat = accumarray([Originaldata(:,1) Originaldata(:,2)],1);
        tempdat = reshape(tempdat,[],1);
        TestSet(:,ll+2) = tempdat;
    elseif ll == 1
        tempdat = accumarray([Originaldata(:,1) Originaldata(:,2)],Originaldata(:,3),[],@mean);
        tempdat = reshape(tempdat,[],1);
        TestSet(:,ll+2) = tempdat;
    else
        tempdat = accumarray([Originaldata(:,1) Originaldata(:,2)],Originaldata(:,ll+1),[],@mean);
        tempdat = reshape(tempdat,[],1);
        TestSet(:,ll+2) = tempdat;
    end
end

TestSet = TestSet(~(TestSet(:,9)==0),:);

Девятый столбец - это просто количество очков на клетку.

Originaldata = 
19  36  2.20500360107422    31488   31488   31488   31611
20  37  2.26400360107422    33792   33792   34304   33924
20  37  2.20000360107422    33536   33536   34048   33667
19  36  2.20500360107422    34560   34560   34560   34695
20  36  2.23300360107422    32512   32512   33024   32639
21  38  2.22000360107422    31744   31488   33024   31611
21  37  2.20400360107422    32512   32768   33792   32896
21  37  2.24800360107422    29696   29440   30720   29555
21  38  2.34800360107422    32768   32768   32768   32639
21  37  2.23000360107422    33024   33024   33536   33153

Таким образом, все точки на одном и том же X,Y (например, [19 36] или же [21 37]) усредняются (высота, RGB, интенсивность в этом порядке), и для значений в третьем столбце также необходимо стандартное отклонение:

Result = 
19  36  2.2050036   0.00        33024   33024   33024       33153
21  37  2.227336934 0.02212088  31744   31744   32682.66    31868

и так далее для остальных данных.

Я обновил свой код до последней версии, которая у меня есть. Это значительно уменьшило накладные расходы памяти, так как теперь функция создает сетки один за другим, а не все сразу. Тем не менее, код выполняется параллельно, поэтому все еще создаются восемь сеток, поэтому решение все равно будет приветствоваться.

3 ответа

Эскиз решения с использованием линейных индексов и разреженной 2D-матрицы

lind = Originaldata(:,1) + max( Originaldata(:,1) ) * ( Originaldata(:,2) - 1 );
daccum(7,:) = accumarray( lind, 1, [], @sum, [], true ); %// start with last one to pre-allocate all daccum
daccum(1,:) = accumarray( lind, Originaldata(:,3), [], @mean, [], true );
daccum(2,:) = accumarray( lind, Originaldata(:,3), [], @std, [], true );
daccum(3,:) = accumarray( lind, Originaldata(:,4), [], @mean, [], true );
daccum(4,:) = accumarray( lind, Originaldata(:,5), [], @mean, [], true );
daccum(5,:) = accumarray( lind, Originaldata(:,6), [], @mean, [], true );
daccum(6,:) = accumarray( lind, Originaldata(:,7), [], @mean, [], true );

Теперь вы можете получить только то, что вам нужно

inter = [Originaldata(:,1), Originaldata(:,2), full( daccum(:,lind) )' ];

Вы можете сначала использовать unique с 'rows' возможность найти индексы уникальных пар координат X и Y, а затем использовать эти индексы в качестве подстрочного ввода в ваших вызовах accumarray (вам придется вызывать его отдельно для каждого столбца, так как accumarray не обрабатывает матричные входы):

[xyPairs, ~, index] = unique(Originaldata(:, 1:2), 'rows');
nPairs = max(index);
Result = [xyPairs ...
          accumarray(index, Originaldata(:, 3), [nPairs 1], @mean) ...
          accumarray(index, Originaldata(:, 3), [nPairs 1], @std) ...
          accumarray(index, Originaldata(:, 4), [nPairs 1], @mean) ...
          accumarray(index, Originaldata(:, 5), [nPairs 1], @mean) ...
          accumarray(index, Originaldata(:, 6), [nPairs 1], @mean) ...
          accumarray(index, Originaldata(:, 7), [nPairs 1], @mean) ...
          accumarray(index, ones(size(index)), [nPairs 1], @sum)];

Вы можете предварительно обработать данные.

Одна вещь, которую вы можете достичь этим способом, это удалить нежелательные строки (например, те, которые имеют два или менее вхождения), чтобы вам не приходилось иметь дело с 0 стандартное отклонение:

%// Count occurences:
combined_coord = Originaldata(:,1)*1E6+Originaldata(:,2); %// "concatenating" the coords
[C,~,ic] = unique(combined_coord);
occurences = [C accumarray(ic,1)];
%// Find all points that have <=2 occurences:
coords_to_remove = occurences((occurences(:,2)<=2),1);
%// Find valid lines:
valid_lns = ~sum(bsxfun(@eq,combined_coord,coords_to_remove'),2); %'
%// Filter original data:
new_data = Originaldata(valid_lns,:);
Другие вопросы по тегам