2016-12-27 4 views
3

я создал следующую трехмерную матрицу макета:Заменить значения с NaN или Inf при соблюдении определенных условий

mockup(:,:,1) = ... 
    [100, 100, 100; ... 
    103, 95, 100; ... 
    101, 85, 100; ... 
    96, 90, 102; ... 
    91, 89, 99; ... 
    97, 91, 97; ... 
    105, 83, 100]; 

mockup(:,:,2) = ... 
    [50, NaN, NaN; ... 
    47, NaN, 40; ... 
    45, 60, 45; ... 
    47, 65, 45; ... 
    51, 70, 45; ... 
    54, 65, 50; ... 
    62, 80, 55]; 

Я также определен percentTickerAvailable = 0.5.

В результате столбцы представляют собой цены акций трех разных активов. Для дальнейшей обработки мне нужно манипулировать значениями NaN следующим образом.

  1. Если процентное соотношение NaN в любой заданной ROW больше 1 - percentTickerAvailable, замените все значения в этих конкретных строках на NaN. То есть, если недостаточно ресурсов, у которых есть цены в этой конкретной строке, полностью игнорируйте строку.
  2. Если процентное количество NaN в любой заданной ROW меньше или равно 1 - percentTickerAvailable, замените соответствующие NaN на -inf.

Для того, чтобы быть ясно, «процент NaNs в любой данной строке» вычисляется следующим образом: Количество NaNs в любой данной строке, разделенной на число столбцов.

Скорректированный макете матрица должна выглядеть следующим образом:

mockupAdj(:,:,1) = ... 
    [100, 100, 100; ... 
    103, 95, 100; ... 
    101, 85, 100; ... 
    96, 90, 102; ... 
    91, 89, 99; ... 
    97, 91, 97; ... 
    105, 83, 100]; 

mockupAdj(:,:,2) = ... 
    [NaN, NaN, NaN; ... 
    47, -inf, 40; ... 
    45, 60, 45; ... 
    47, 65, 45; ... 
    51, 70, 45; ... 
    54, 65, 50; ... 
    62, 80, 55]; 

До сих пор я сделал следующее:

function vout = ranking(vin, percentTickerAvailable) 

percentNonNaN = 1 - sum(isnan(vin), 2)/size(vin, 2); 
NaNIdx = percentNonNaN < percentTickerAvailable; 
infIdx = percentNonNaN > percentTickerAvailable & ... 
    percentNonNaN < 1; 
[~, ~, numDimVin] = size(vin); 

for i = 1 : numDimVin 
    vin(NaNIdx(:,:,i) == 1, :, i) = NaN; 
end 

about = vin; 

end % EoF 

Позвонив mockupAdj = ranking(mockup, 0.5) это уже превращает первую строку в mockup(1,:,2) правильно {'NaN', 'NaN', 'NaN'}. Тем не менее, я борюсь со вторым моментом. С infIdx Я уже успешно идентифицировал строки, соответствующие второму условию. Но я не знаю, как правильно использовать эту информацию для замены единственного NaN в mockup(2,2,2) с помощью -inf.

Любой совет приветствуется.

ответ

3

1)

Процент NaN в любой данной строке должно быть меньше, чем 1

... Вы говорите о соотношении? В этом случае это бесполезная проверка, поскольку это всегда будет иметь место. Или говорить о процентах? В этом случае ваш код не выполняет то, что вы описываете. Мое предположение - отношение.

2) Основываясь на моей догадке, у меня есть следующий вопрос: после вашего описания не следует макетировать (2,2,2) оставаться NaN? Существует 33% (< 50%) из NaN в этой строке, поэтому он не выполняет свое состояние 2.

3) на основе ответов я считающихся логично, я бы изменил percentNaN = sum(isnan(vin), 2)/size(vin, 2); для удобства чтения и NaNIdx = percentNaN > percentTickerAvailable; соответственно. Теперь просто добавьте одну линию перед вашей петлей:

vin(isnan(vin)) = -inf; 

Почему? Потому что вы заменяете все NaN на -inf. Позже те, которые соблюдают условие 1, будут перезаписаны на NaN снова, по петле. Вам не нужен InfIdx.

4) Помните, что ваша функция не может вернуть vout на данный момент. Просто позволь ему вернуть вино, и с тобой все будет в порядке.

+0

Lionel, вы несколько верны. Я перепутал эти два условия. Я редактировал свой оригинальный пост. – Andi

+0

Скажите, будет ли мое решение работать для вас :) Я тестировал его на моем, и он работает! Просто сохраните свой код и добавьте в него одну строку! –

4

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

Несколько вещей, чтобы отметить:

  • На стадии NaN замещения, я использую «трюк», где 0/0 вычисляется в NaN.
  • В стадии замены Inf я использую логическую маскировку/индексирование для доступа к правильным элементам в vin.

R2016b и новее:

function vin = ranking (vin, percentTickerAvailable) 
    % Find percentage of NaNs on each line: 
    pNaN = mean(isnan(vin), 2, 'double'); 
    % Fills rows with NaNs: 
    vin = vin + 0 ./ (1 - (pNaN >= percentTickerAvailable)); 
    % Replace the rest with -Inf 
    vin(isnan(vin) & pNaN < percentTickerAvailable) = -Inf; 
end 

До R2016b:

function vin = rankingOld (vin, percentTickerAvailable) 
    % Find percentage of NaNs on each line: 
    pNaN = mean(isnan(vin), 2, 'double'); 
    % Fills rows with NaNs: 
    vin = bsxfun(@plus, vin, 0 ./ (1 - (pNaN >= percentTickerAvailable))); 
    % Replace the rest with -Inf 
    vin(bsxfun(@and, isnan(vin), pNaN < percentTickerAvailable)) = -Inf; 
end 
1

Вы можете также использовать логическую индексацию для достижения этой задачи:

x(:,:,1) = ... 
    [100, 100, 100; ... 
    103, 95, 100; ... 
    101, 85, 100; ... 
    96, 90, 102; ... 
    91, 89, 99; ... 
    97, 91, 97; ... 
    105, 83, 100]; 

x(:,:,2) = ... 
    [50, NaN, NaN; ... 
    47, NaN, 40; ... 
    45, 60, 45; ... 
    47, 65, 45; ... 
    51, 70, 45; ... 
    54, 65, 50; ... 
    62, 80, 55]; 

    % We fix the threshold 
    tres = 0.5; %fix the threshold. 

    % We check if a value = NaN or not. 
    in = isnan(x); 
    % Which line have more than 50% of NaN ?. 
    ind = (sum(in,2)./(size(x,2)))>0.5 
    % We generate an index 
    [x1,~,x3] = ind2sub(size(ind),ind); 
    % We set the NaN index to 0 if the line contains less than 50 % of NaN. 
    in(x1,:,x3) = 0; 

    % We calculate the new values. 
    x(in) = -inf; 
    x(x1,:,x3) = NaN; 
Смежные вопросы