Иерархия между и / или в операторе if - PullRequest
2 голосов
/ 12 июня 2019

У меня есть файл с именем data, внутри которого есть часть Data.ensemble, первые несколько строк которой выглядят следующим образом:

                Year Month Day Hour Min Temp
0   1635    1   2009    12  10  22  36  16.28
0   1635    2   2009    12  10  22  37  17.25
0   1635    3   2009    12  10  22  38  16.97
0   1635    4   2009    12  10  22  39  16.69
0   1635    5   2009    12  10  22  40  17.42

Я хочу извлекать температуру в декабре по минутам 0, 20, 30 и 40 каждый час. У меня проблемы с кодированием. Вот что я пытаюсь:

Month = 12;
Minute = [0 20 30 40];

if Data.ensemble(:, 5) == Month & (Data.ensemble(:, 8) == (Minute(1) | Minute(2) | Minute(3) | Minute(4)))
    Temperature = Data.ensemble(:, 10)
end

Похоже, что это не создает Temperature, и я ожидаю, что он просто скопирует весь столб, а не только температуру в течение правильных минут. Более того, я не совсем уверен, что скобки действительно используют правильную иерархию между и / или. Это должно быть всегда декабрь (12) и минуты (0, 20, 30 или 40).

Ответы [ 4 ]

3 голосов
/ 12 июня 2019

Вы можете использовать логическое индексирование :

%dummy data

x = datevec(now+[1:30]+170)

% x =
%
%   2019.0000     11.0000     30.0000     12.0000     56.0000     43.4885
%   2019.0000     12.0000      1.0000     12.0000     56.0000     43.4885
%   2019.0000     12.0000      2.0000     12.0000     56.0000     43.4885
%   2019.0000     12.0000      3.0000     12.0000     56.0000     43.4885
%   2019.0000     12.0000      4.0000     12.0000     56.0000     43.4885
%    ... 

%create a logical index to get each 10th,20th and 30th day of the month in december.
%we can use ismember to check several day at once.
index = ismember(x(:,3),[10,20,30]) & x(:,2) == 12
y     = x(index,:)

% y =
%
%   2019.000     12.000     10.000     12.000     59.000     13.826
%   2019.000     12.000     20.000     12.000     59.000     13.826

Если вы хотите использовать оператор if else, вам необходим цикл for для проверки каждой строки отдельно.

1 голос
/ 12 июня 2019

Вы неправильно понимаете, как логическое индексирование работает в MATLAB, но, кроме этого, у вас есть правильная идея.

Выражение (Minute(1) | Minute(2) | Minute(3) | Minute(4)) будет делать логическое or для скалярных элементов. Поскольку все они ненулевые (и скаляры), результат всегда равен 1. Поскольку ваша минута редко равна 1, вероятно, ничего не будет выбрано.

Выражение Data.ensemble(:, 5) == Month создает логический массив с тем же количеством элементов, что и строк в Data.ensemble. Некоторые из элементов могут быть 0, если данных больше, чем показано в примере. Это выражение, вероятно, дало вам предупреждение, так как логическое значение полученного массива неоднозначно:

  1. Вы можете установить его на 1, если какой-либо элемент 1
  2. Вы можете установить его на 0, если любой элемент равен 0
  3. Вы можете установить его в 1, если массив просто не пустой
  4. Любой другой критерий, который имеет смысл в контексте ...

Даже если бы конечное условие вышло 1, выражение Temperature = Data.ensemble(:, 10) просто установило бы Temperature на весь 10-й столбец.

Вместо этого вы хотите применить исправленную версию этого оператора if к каждой отдельной строке данных. Хитрость заключается в том, чтобы использовать логический массив для кодирования вашего состояния, а затем использовать этот логический массив в качестве индекса:

 month_is_12 = (Data.ensemble(:, 5) == Month);
 minute_is_good = ismember(Data.ensemble(:, 8), Minute);

ismember проверит каждый элемент 8-го столбца относительно массива Minute, чтобы определить, соответствует ли он любому из элементов. Это эквивалентно выполнению

minute_is_good = ((Data.ensemble(:, 8) == Minute(1)) | (Data.ensemble(:, 8) == Minute(2)) | (Data.ensemble(:, 8) == Minute(3)) | (Data.ensemble(:, 8) == Minute(4)));

Не только ismember выглядит лучше, но и позволяет вам изменять размер Minute без необходимости изменять ваш фактический код.

Теперь вам не нужно if, чтобы получить нужные данные:

Temperature = Data.endemble(month_is_12 & minute_is_good);
1 голос
/ 12 июня 2019

Вы можете использовать логическое индексирование :

tf = Data.ensemble(:,5) == Month & any(Data.ensemble(:,8) == Minute, 2);
Temperature = Data.ensemble(tf,9)

Или найти :

ind = find(Data.ensemble(:,5) == Month & any(Data.ensemble(:,8) == Minute, 2));
Temperature = Data.ensemble(ind,9)

Примечание: find медленнее, чем логическое индексирование.

Пояснение:

Data.ensemble(:,5) == Month возвращает вектор логического столбца с 1, где условие истинно и 0 для ложно. Для вашего примера результат будет:

5×1 logical array
   1
   1
   1
   1
   1

Data.ensemble(:,8) == Minute возвращает логическую матрицу, где каждый столбец для каждого элемента Minute. Для вашего примера результат будет:

  5×4 logical array
   0   0   0   0
   0   0   0   0
   0   0   0   0
   0   0   0   0
   0   0   0   1

any(Data.ensemble(:,8) == Minute, 2): чтобы получить один логический вектор, равный 1 для каждой строки, которая имеет 1 (= условие минуты соответствует), мы вызываем any для строк (второе измерение). Для вашего примера результат будет:

5×1 logical array
   0
   0
   0
   0
   1

Призвание:

any(Data.ensemble(:,8) == Minute, 2)

короче:

Data.ensemble(:,8) == Minute(1) | Data.ensemble(:,8) == Minute(2) | Data.ensemble(:,8) == Minute(3) | Data.ensemble(:,8) == Minute(4)
1 голос
/ 12 июня 2019

Вы близки, но если вы попытаетесь оценить свои логические условия, вы увидите, что это не работает:

>> Minute(1)|Minute(2)|Minute(3)|Minute(4)
ans = 1

И так (при условии, что я храню ваши данные в переменной A):

>> (A(:,8) == (Minute(1)|Minute(2)|Minute(3)|Minute(4)))
ans =

  0
  0
  0
  0
  0

Учитывая, что:

>> A(:,5) == Month
ans =

  1
  1
  1
  1
  1

Получаем:

>> A(:,5) == Month & (A(:,8)==(Minute(1)|Minute(2)|Minute(3)|Minute(4)))
ans =

  0
  0
  0
  0
  0

, что означает, что условие никогда не выполняется, а Temperature никогда не будет определено. Правильный способ сделать это (или я должен сказать, один из способов сделать это), используя логическое индексирование :

>> idx = ( A(:,8)==Minute(1)|A(:,8)==Minute(2)|A(:,8)==Minute(3)|A(:,8)==Minute(4)) & A(:,5) == Month

idx =

  0
  0
  0
  0
  1

Затем вы можете определить свою температуру как:

>> Temperature = A(idx,9)
Temperature =  17.420
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...