Позволяя 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,:);