2010-11-11 2 views
1

У меня есть строка кода в Matlab, который читает:Как уменьшить требования к памяти функции «найти» Matlab?

output = find(input); 

, где вектор-столбец «выход» содержит все индексы в векторе-столбце «вход», элементы которой равны нулю. Например, если:

input = [1 3 4 0 0 2 0]; 

затем результат, output = find (input); будет:

output = 
    1 
    2 
    3 
    6 

, соответствующий 1 ("1"), 2-й ("3"), 3 ("4") и 6 ("2") индексы массива "вход", которые отличны от нуля ,

Поскольку мой массив «ввода» очень велик, эта строка кода потребляет всю мою локальную ОЗУ плюс огромную часть виртуальной памяти, заставляя систему замедляться при сканировании.

Кто-нибудь знает хороший способ (или каким-либо образом) уменьшить требования к памяти для такой операции? Я думал о том, чтобы поместить код «найти» в цикле, но поскольку размер массива «output» (и, следовательно, индексация этого массива) зависит от результата операции «Найти», я не вижу, как это возможно Сделай так. Из идей.

Заранее благодарим за любые комментарии/предложения. -gkk

ответ

2

Если у вас достаточно оперативной памяти для хранения массива одинакового размера input, вы можете заменить вызов find на

output = 1:length(input); 
output = output(input~=0); 

Если input имеет менее чем 2^32-1 элементов, вы можете инициализируйте его как uint32 и, таким образом, сохраните память.

Лучший способ может быть конвертировать input массив sparse, что экономит память, если input содержит много нулей, а затем использовать find на что, то есть

input = sparse(input); 
output = find(input); 

EDIT

Для выполнения операции find в деталях, я бы сделал следующее:

nIn = length(input); 
blockLength = 100000; 
nBlocks = ceil(nIn/blockLength); %# work in chunks of 100k entries 
out = cell(nBlocks,1); 
for i=1:nBlocks 
    out{i} = (i-1)*blockLength+1:i*blockLength; %# assign as your favorite integer format here 
    out{i} = out{i}(input(out{i})~=0); 
end 
out = cat(1,out{:}); 
+0

Благодаря Jonas, мне нравятся ваши первые 2 строки кода выше, очень умно! К сожалению, размер массива составляет 16 ГБ (уже с использованием класса uint32), и у меня всего 10 ГБ локальной оперативной памяти. Я попытаюсь использовать вашу технику на куски, чтобы извлечь ненулевые элементы, очистить «ввод» и скомпоновать куски (возможно, это сработает). – ggkmath

+1

@ggkmath: Я добавил предложение о том, как вы можете выполнить операцию в джонках. – Jonas

+0

Спасибо, Джонас, я думаю, что в одной из строк есть опечатка (ей не хватает +1) и следует читать: out {i} = (i-1) * blockLength + 1: i * blockLength. Хорошо работает, спасибо – ggkmath

3

Если у вас есть ненулевые значения, чем нули, может быть, вы можете работать с дополнением, а именно: output=find(input==0) вместо значения по умолчанию, которое эквивалентно output=find(input~=0)

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

>> output1 = find(input); 
>> output2 = (input~=0); 
>> whos output* 
    Name   Size   Bytes Class  Attributes 

    output1  1x4    32 double    
    output2  1x7     7 logical  

примечание как она хранится в виде вектора «булевы», который один байт каждый (по сравнению с 8 байт для «двойной»)

+0

+1 для двух дополнительных хороших, дополнительных идей! – Jonas

+0

Спасибо Amro, я должен был упомянуть, что массив «input» - это класс int8, который уже 1B на элемент. Я надеялся, что у Matlab был двоичный или булевский класс, который был 1 бит (0 или 1), но я не мог найти такого, что упоминалось где-либо. – ggkmath

+0

Логическая индексация, похоже, имеет идентичные требования к памяти, такие как функция «Найти». Хорошие предложения. – ggkmath

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