2015-02-02 6 views
3

У меня есть массив ячеек размером m x 1, и каждая ячейка снова массива s x t (размер варьируется). Я хотел бы конкатенировать по вертикали. Код выглядит следующим образом:Более быстрая конкатенация массивов ячеек разных размеров

function(cell_out) = vert_cat(cell_in) 
    [row,col] = cellfun(@size,cell_in,'Uni',0); 
    fcn_vert = @(x)([x,repmat({''},size(x,1),max(cell2mat(col))-size(x,2))]); 
    cell_out = cellfun(fcn_vert,cell_in,'Uni',0); % Taking up lot of time 
    cell_out = vertcat(cell_out{:}); 
end 

Шаг 3 занимает много времени. Это правильный способ сделать или есть еще один более быстрый способ достичь этого?

+0

Вы пробовали 'profile'ing кода? – Shai

+0

Просто небольшое улучшение: вам не нужно '' uni ', 0' для первого 'cellfun'. Вывод размера является однородным. – Daniel

+0

@ Daniel Размер варьируется и не является однородным. Не могли бы вы еще раз проверить? – nik

ответ

1

Я использовал этот Pice кода для генерации данных:

%generating some dummy data 
m=1000; 
s=100; 
t=100; 
cell_in=cell(m,1); 
for idx=1:m 
    cell_in{idx}=cell(randi(s),randi(t)); 
end 

Применяя некоторые незначительные изменения, я был в состоянии ускорить код с коэффициентом 5

%Minor modifications of the original code 
    %use arrays instead of cells for row and col 
    [row,col] = cellfun(@size,cell_in); 
    %claculate max(col) once 
    tcol=max(col); 
    %use cell instead of repmat to generate an empty cell 
    fcn_vert = @(x)([x,cell(size(x,1),tcol-size(x,2))]); 
    cell_out = cellfun(fcn_vert,cell_in,'Uni',0); % Taking up lot of time 
    cell_out = vertcat(cell_out{:}); 

Использование просто для петля еще быстрее, поскольку данные перемещаются только один раз

%new approac. Basic idea: move every data only once 
    [row,col] = cellfun(@size,cell_in); 
    trow=sum(row); 
    tcol=max(col); 
    r=1; 
    cell_out2 = cell(trow,tcol); 
    for idx=1:numel(cell_in) 
     cell_out2(r:r+row(idx)-1,1:col(idx))=cell_in{idx}; 
     r=r+row(idx); 
    end 
+0

Большое вам спасибо за решение. – nik

2

cellfun было найдено, что slower than loops (вид старого, но согласен с тем, что я видел). Кроме того, repmat также был хитом производительности в прошлом (хотя теперь это может быть другим). Попробуйте двухпетлевой код, который стремится выполнить свою задачу:

function cellOut = vert_cat(c) 

    nElem = length(c); 
    colPad = zeros(nElem,1); 
    nRow = zeros(nElem,1); 
    for k = 1:nElem 
     [nRow(k),colPad(k)] = size(c{k}); 
    end 
    colMax = max(colPad); 
    colPad = colMax - colPad; 

    cellOut = cell(sum(nRow),colMax); 
    bottom = cumsum(nRow) - nRow + 1; 
    top  = bottom + nRow - 1; 
    for k = 1:nElem 
     cellOut(bottom(k):top(k),:) = [c{k},cell(nRow(k),colPad(k))]; 
    end 

end 

Моего тестом для этого кода был

A = rand(20,20); 
A = mat2cell(A,ones(20,1),ones(20,1)); 
C = arrayfun(@(c) A(1:c,1:c),randi([1,15],1,5),'UniformOutput',false); 
ccat = vert_cat(c); 
+0

@ TroyHaskin Спасибо за решение – nik

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