2016-01-08 3 views
2

У меня есть массив ячеек в MATLAB, который содержит некоторые матрицы в порядке убывания размера (например, [512x512 double] [256x256 double] [128x128 double] и т. Д.).Минимальные значения массивов ячеек в MATLAB

Теперь я хочу найти и уничтожить (превращаются в нули) 100 наименьшие элементы матриц в массиве ячеек вообще (не в каждой матрице по отдельности). Например, наименьший элемент может быть в матрице 128x128, следующий в матрице 512x512 и так далее.

Как я могу сделать это наиболее эффективно?

На следующий мой супер-медленный код для случая трех таких клеточных массивов - H, D, V (percent2zero является параметром для процентов элементов, чтобы стереть из массива клеток всего):

details=[H;D;V]; 
for k=1:3 
    numOfLevels=length(details(k,:)); 
    TotalCoeffs=0; 
    minimalInEachLevel=zeros(1,numOfLevels); 
    for i=1:numOfLevels 
     temp=cell2mat(details(k,i)); 
     TotalCoeffs=TotalCoeffs+numel(temp); 
     minimalInEachLevel(i) = min(min(abs(temp))); 
    end 
    CoeffsToBeRemoved=percent2zero*TotalCoeffs/100; 
    for i=1:CoeffsToBeRemoved 
     for j=1:numOfLevels 
      temp=cell2mat(details(k,j)); 
      minimalInEachLevel(j) = min(min(abs(temp))); 
     end 
     [val,ind]=min(minimalInEachLevel); 
     temp=cell2mat(details(k,ind)); 
     temp(find(abs(temp==val),1))=0; 
     details(k,ind)=mat2cell(temp,size(temp,1),size(temp,2));   
    end 
end 
+0

Посмотрите на [ 'cellfun'] (http://nl.mathworks.com/help/matlab/ref/cellfun.html) – Adriaan

+0

Привет ... так в чем дело? Помогли ли мы вам? – rayryeng

+0

Если один из ответов разрешил ваш вопрос, пожалуйста, рассмотрите [его принятие] (http://meta.stackexchange.com/q/5234/179419), нажав галочку. Это означает, что вы нашли решение, и это уже не открытый вопрос. Если на ваш вопрос не ответил, пожалуйста, объясните, чего не хватает. – Daniel

ответ

2

Одна вещь, которую я могу предложить, - разместить каждое значение по всем матрицам в один одномерный вектор, отсортировать вектор и выбрать 100 наименьших значений. Используйте cellfun и sort, чтобы сделать это первым шагом. Логика этого заключается в том, что если мы собираем все значения по всем матрицам и помещаем их в один вектор, то сортируем весь вектор, мы выберем 100 наименьших значений вместе, как вы уже упоминали.

После того, как вы найдете эти 100 наименьших значений, вам придется перебирать каждую ячейку, тогда вы можете использовать intersect, чтобы увидеть, есть ли какие-либо элементы в каждой матрице в массиве ячеек, которые являются общими для 100 наименьших значений. Вы можете использовать второй вывод intersect, а затем использовать его для индексирования в каждую ячейку и установить значения равными 0. Поскольку вы имеете дело с ячейками, и каждая ячейка отличается от другого, цикл является единственным вариантом.

Нечто подобное приходит на ум. Это при условии, что details является массив ячеек, где каждая ячейка представляет собой матрицу:

%// Create single 1D vector of all values 
vals = cellfun(@(x) reshape(x, [], 1), details, 'uni', 0); 
vals = cat(1, vals{:}); 

%// Sort the UNIQUE values and grab the 100 smallest values 
vals = unique(vals); 
vals = vals(1:100); 

%// Loop through each cell, determine those values that are among 
%// the 100 smallest and set to 0 
for ii = 1 : numel(details) 
    [~,ind,~] = intersect(details{ii}, vals); 
    details{ii}(ind) = 0; 
end 

unique находит уникальные значения в массиве или матрице, но также имеет дополнительное преимущество сортировки уникальных значений тоже. Таким образом, этот код найдет 100 самых маленьких и уникальных значений для обработки ваших ячеек.

1

Я немного поиграл с этим и в основном придумал то же, что и Rayryeng. Идея состоит в том, чтобы перестроить каждую матрицу в 1D-вектор, отсортировать каждый из векторов и отслеживать исходные индексы, а затем начать обнуление наименьших элементов в начале 1D векторов, используя индексы несортированного 1D-вектора для возврата к 2D-матрице и нулю эти элементы. Я думаю, что это относится к 1D векторам как очереди. Во всяком случае, я разработал функцию, которая будет следовать этому процессу для массива ячеек, содержащего 3 матрицы. Это не красиво или оптимизировано или обобщено для массива ячеек с любым количеством матриц, но я не думаю, что это было бы трудно улучшить.

function [X] = wipeCellMinima(X,percent2zero) 
%wipeCellMinima 

x1 = X{1}; 
x2 = X{2}; 
x3 = X{3}; 

l1 = length(x1); 
l2 = length(x2); 
l3 = length(x3); 

%reshape each matrix into a 1D vector and sort them, keeping sorted indices 
[q1,I1] = sort(reshape(x1,1,l1^2)); 
[q2,I2] = sort(reshape(x2,1,l2^2)); 
[q3,I3] = sort(reshape(x3,1,l3^2)); 

%total number of elements to be "wiped" 
n = fix((l1^2 + l2^2 + l3^2)*percent2zero*0.01); 

i1 = 1; 
i2 = 1; 
i3 = 1; 

%treat the reshaped and sorted matrices kind of like queues 
for j = 1:n 
    %Find the smallest value indexed in sort1 by i1, in sort2 by i2, 
    %and in sort3 by i3. 
    [~,idx_min] = min([q1(i1),q2(i2),q3(i3)]); 
    if(idx_min == 1) 
     %The smallest element in all matrices is the first one in the 
     %sorted version of x1. Use it's index in the unsorted version of q1 
     %to set the corresponding element in x1 to zero. And increment i1. 

     %In the unsorted version of q1, the I1(i1)th element needs to be 
     %set to zero. The correct row and column can be extracted from the 
     %size of the original matrix x1 and the position of the element in 
     %the 1D vector. 
     row = mod(I1(i1),l1); 
     if(row == 0) 
      row = l1; 
      col = I1(i1)/l1; 
     else 
      col = floor(I1(i1)/l1) + 1; 
     end 
     x1(row,col) = 0; 
     i1 = i1 + 1; 
    elseif(idx_min == 2) 
     row = mod(I2(i2),l2); 
     if(row == 0) 
      row = l2; 
      col = I2(i2)/l2; 
     else 
      col = floor(I2(i2)/l2) + 1; 
     end 
     x2(row,col) = 0; 
     i2 = i2 + 1; 
    else 
     row = mod(I3(i3),l3); 
     if(row == 0) 
      row = l3; 
      col = I3(i3)/l3; 
     else 
      col = floor(I3(i3)/l3) + 1; 
     end 
     x3(row,col) = 0; 
     i3 = i3 + 1; 
    end 
end 

X = {x1,x2,x3}; 

end 
+0

Может ли этот код обрабатывать случай, когда массив коэффициентов, используемых для удаления значений в массивах ячеек, имеет дубликаты? – rayryeng

+0

Я думаю, это зависит от того, что вы подразумеваете под «ручкой». Он будет устанавливать фиксированное количество элементов в ноль каждый раз, в зависимости от общего количества элементов во всех матрицах и 'percent2zero', но он не будет преимущественно нулевым элементом в соответствии с порядком матриц в массиве ячеек или чем-либо как это. –

-3
n = sum(cellfun('prodofsize',details),2); 
CoeffsToBeRemoved = round(percent2zero/100*n); 
for i = 1:size(details,1) 
    tmp = cellfun(@(x)x(:),details(i,:),'un',0); 
    tmp = sort(abs(vertcat(tmp{:}))); 
    val = tmp(CoeffsToBeRemoved(i)); 
    for j = 1:size(details,2) 
     details{i,j} = details{i,j}.*(abs(details{i,j})>val); 
    end 
end 
+0

Добро пожаловать в SO. Можете ли вы предоставить некоторую информацию о том, как это решает проблему OP? Что именно вы изменили и почему это помогает? Чистый блок кода может быть трудно обрабатывать. ;) – m00am

+0

Может ли этот код обрабатывать случай, когда массив коэффициентов, используемых для удаления значений в массивах ячеек, имеет дубликаты? Также будет полезно пояснить, как работает этот код. – rayryeng

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