2013-06-25 4 views
0

Я вычитаю две матрицы друг от друга. dataClim - это средние данные за каждый месяц (12 месяцев) за 30-летний период. dataAll - ежедневные данные за 1257 дней. Мне нужно вычесть среднемесячные данные из ежедневных данных каждого месяца с 20100101 по 20130611 (t = 1:31 - январь, t = 32-57 - февраль, вплоть до декабря, затем 363: 393 - январь) ,MATLAB Матрицы вычитания более эффективны

Этот код работает, но мне было интересно, есть ли способ сделать его более эффективным и менее утомительным. Я не знаю, как я бы написать цикл, поскольку месяцы меняться число дней от 28 до 31.

% Create new array in which data_Anom is the anomaly 
% dataAnom = dataAll - dataClim 

% January 
dataAnom_1 = bsxfun(@minus, dataAll(:,:,[1:31, 363:393, 728:758, 1094:1124]), dataClim(:,:,1)); 

% February 
dataAnom_2 = bsxfun(@minus, dataAll(:,:,[32:57, 394:421, 759:787, 1125:1152]), dataClim(:,:,2)); 

% March 
dataAnom_3 = bsxfun(@minus, dataAll(:,:,[58:88, 422:452, 788:818, 1153:1183]), dataClim(:,:,3)); 

% April 
dataAnom_4 = bsxfun(@minus, dataAll(:,:,[89:118, 453:482, 819:848, 1184:1213]), dataClim(:,:,4)); 

% May 
dataAnom_5 = bsxfun(@minus, dataAll(:,:,[119:148, 483:513, 849:879, 1214:1244]), dataClim(:,:,5)); 

% June 
dataAnom_6 = bsxfun(@minus, dataAll(:,:,[149:178, 514:543, 880:909, 1245:1255]), dataClim(:,:,6)); 

% July 
dataAnom_7 = bsxfun(@minus, dataAll(:,:,[179:209, 544:574, 910:940]), dataClim(:,:,7)); 

% August 
dataAnom_8 = bsxfun(@minus, dataAll(:,:,[210:240, 575:605, 941:971]), dataClim(:,:,8)); 

% September 
dataAnom_9 = bsxfun(@minus, dataAll(:,:,[241:270, 606:635, 972:1001]), dataClim(:,:,9)); 

% October 
dataAnom_10 = bsxfun(@minus, dataAll(:,:,[271:301, 636:666, 1002:1032]), dataClim(:,:,10)); 

% November 
dataAnom_11 = bsxfun(@minus, dataAll(:,:,[302:331, 667:696, 1033:1062]), dataClim(:,:,11)); 

% December 
dataAnom_12 = bsxfun(@minus, dataAll(:,:,[332:362, 697:727, 1063:1093]), dataClim(:,:,12)); 

% Concatenate the seperate Anomalies 
dataAnom = cat(3, dataAnom_1, dataAnom_2, dataAnom_3, dataAnom_4, dataAnom_5, dataAnom_6, dataAnom_7, dataAnom_8, dataAnom_9, dataAnom_10, dataAnom_11, dataAnom_12); 

clear dataAnom_* 

Одна идея, которую я имел было сцепить дни каждого месяца вместе, а затем создать dataAnom для каждый месяц. Это, вероятно, еще медленнее.

% Concatenation days below to each month in dataAll into dataMon so that each month is placed together. This 
% makes it easier to do the anomaly subtraction later. 

dataMon = cat(3, dataAll(:,:,1:31), dataAll(:,:,363:393), dataAll(:,:,728:758) , dataAll(:,:,1094:1124),... % January 
    dataAll(:,:,32:57), dataAll(:,:,394:421), dataAll(:,:,759:787), dataAll(:,:,1125:1152),... % February 
    dataAll(:,:,58:88), dataAll(:,:,422:452), dataAll(:,:,788:818), dataAll(:,:,1153:1183),... % March 
    dataAll(:,:,89:118), dataAll(:,:,453:482), dataAll(:,:,819:848), dataAll(:,:,1184:1213),... % April 
    dataAll(:,:,119:148), dataAll(:,:,483:513), dataAll(:,:,849:879), dataAll(:,:,1214:1244),... % May 
    dataAll(:,:,149:178), dataAll(:,:,514:543), dataAll(:,:,880:909), dataAll(:,:,1245:1255),... % June. Last entry goes up to 20130611, not the full month 
    dataAll(:,:,179:209), dataAll(:,:,544:574), dataAll(:,:,910:940),... % July 
    dataAll(:,:,210:240), dataAll(:,:,575:605), dataAll(:,:,941:971),... % August 
    dataAll(:,:,241:270), dataAll(:,:,606:635), dataAll(:,:,972:1001),... % Sept 
    dataAll(:,:,271:301), dataAll(:,:,636:666), dataAll(:,:,1002:1032),... % Oct 
    dataAll(:,:,302:331), dataAll(:,:,667:696), dataAll(:,:,1033:1062),... % Nov 
    dataAll(:,:,332:362), dataAll(:,:,697:727), dataAll(:,:,1063:1093)); % Dec 

% Create dataAnom 
dataAnom1 = bsxfun(@minus, dataAll(:,:,1:124), dataClim(:,:,1); 
dataAnom2 = bsxfun(@minus, dataAll(:,:,125:238:), dataClim(:,:,1); 
. 
. 
. 
dataAnom12 = ... 

% Combine 
dataAnom = cat(3, dataAnom1, dataAnom2, dataAnom3,....); 
+1

Как и в сторону , почему бы вам не использовать лучшую матричную структуру? то есть '12x31xNumOfYears'? В течение месяцев, которые не являются 31 день, вы можете использовать 'NaN', чтобы представить отсутствующий день. – KronoS

+0

Почему февраль от 32-57? Если ваши данные не структурированы должным образом, все должно быть жестко запрограммировано, и это будет сосать. –

+0

Февраль - 28 дней или 29 дней. В данных просто перечисляются дни один за другим. X и y матрицы - lat и lon по всему миру, а z - количество дней с 20100101 по 20130611. Я не думаю, что это хорошая идея просто добавить в NaN, чтобы каждый месяц составлять 31 день или что-то в этом роде. – shizishan

ответ

1

В то время как я все еще держаться на то, что вы должны реорганизовать данные, вы можете также использовать возможности datenum, чтобы помочь вам. Ниже будет сделать вашу жизнь намного проще, чем пытаться ввести вручную дни:

clear all; clc; 

% Init Data 
dataAll = rand(1437,159,1258); 

% Starting date of sampling. Note that this assumes each day there was a sample, and only one sample 
startDate = datenum('01-01-2010'); 
dateList = [0:1257] + startDate; 
[yr, mn, ~, ~, ~, ~] = datevec(dateList); 

% extract data depending on month that sample was taken 
jan = dataAll(:,:,mn == 1); 
feb = dataAll(:,:,mn == 2); 
mar = dataAll(:,:,mn == 3); 
... % and so forth 

Это должно получить желаемые результаты, которые вы ищете.Отсюда вы можете сделать ваши полученные расчеты:

dataAnom_1 = bsxfun(@minus, jan, dataClim(:,:,1)); 

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

jan2010 = dataAll(:,:,(mn == 1 & yr == 2010); 
feb2010 = dataAll(:,:,(mn == 2 & yr == 2010); 
... % and so forth 
+0

Спасибо. Это сработало. Но я обнаружил, что не могу сделать это полностью, потому что это объединяет все январь, а затем весь фев (это моя ошибка, когда я этого не осознавал).Это разрушает порядок дней. – shizishan

+0

@ user2258883 Что вы подразумеваете под этим "разрушает порядок дней"? – KronoS

+0

'jan = dataAll (:,:, mn == 1);' помещает все январь вместе. Поэтому, когда я делаю 'dataAnom_1 = bsxfun (@minus, jan, dataClim (:,:, 1)),' позже, я в конечном итоге вычитаю все январь из dataClim. Когда я совмещаю dataAnom_1, dataAnom_2 и т. Д. Обратно в большую матрицу, это в конечном итоге ошибочно, потому что я заканчиваю графику аномалий 4 разных Januaries, затем 4 февраля и т. Д. Вместе вместо графического отображения в январе 2010, феврале 2010 г. .. Январь 2011, февраль 2011, ... – shizishan

1

не могли бы вы сделать

% January 
dataAnom1 = bsxfun(@minus, dataAll(:,:,[1:31 363:393 728:758 1094:1124]), dataClim(:,:,1)); 

? Я думаю, что это то же самое.

И если да, то вы можете сделать

dataAnom1=zeros(size(dataAll,1),size(dataAll,2), 128*12); 
for v=1:12 
    dataAnom1(:,:,1+((v-1)*128:v*128)) = bsxfun(@minus, dataAll(:,:,[1:31 363:393 728:758 1094:1124]+(v-1*32)), dataClim(:,:,v)); 
end 

(индексирования может быть немного выключено)

+0

О, похоже, я просто забыл скобки, когда я пробовал это раньше. Благодарю. – shizishan

+0

Дело в том, что каждый месяц имеет 31 или 30 дней, а в феврале - 28 или 29 дней. Я не знаю, как это учитывать в коде. – shizishan

+1

А, я понимаю. Да, это может быть неудобно работать с такими месяцами. Вы могли бы поместить каждую информацию месяца в 12-элементную ячейку и использовать векторное выражение для данных в ячейке? Например. 'MonthData = cell (12,1); MonthData {1} = dataAll (:,:, 1:31); ', а затем используйте' bsxfun (@ минус, MonthData {1}, dataClim (:,:, 1)); вы можете затем обернуть их в structs или ячейки в течение многих лет, если это необходимо: 'Years = struct (4); Годы (1) .year = 2009; Годы (1) .Data = MonthData; ' –

3

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

В это простейшая вы могли бы использовали схему, как этот: 31x12xNumYears, которая будет производить что-то вроде этого:

Data = NaN(31x12xNumYears); % Blank Init 
Data(1:31,1,1) = Rand(31,1); % January's populated values 
Data(1:28,2,1) = Rand(28,1); % February's populated values 
... % and so forth 

Преимущество здесь в том, что матричные операции намного проще сделать, и у вас есть лучшее понимание что фактически представляют данные. Например, учитывая, что dataClim средней Monthy более 30 лет (матрица должна быть 12x30) и dataAll является ежедневным чтением (матрица должна быть 31x12x30), вы можете сделать следующее:

subValues = NaN(31,12,30); 
for yr = 1:30 
    for mn = 1:12 
     subValues(1:31,mn,yr) = dataAll(1:31,mn,yr) - dataClim(mn,yr); 
    end 
end 

с добавленным информацию, которую вы мне дали, я думаю, что это тип структуры, который вы, возможно, ищете: days x months x years x 3, где три представляют lat, long и dataValue ваших данных. Так, например:

test = rand(31,12,30,3); 
lat = test(1:end,1:end,1:end,1); 
long = test(1:end,1:end,1:end,2); 
data = test(1:end,1:end,1:end,3); 
+0

Дело в том, что мои данныеAll содержат данные для каждой точки lat и lon по всему миру, поэтому я не могу ее изменить, не теряя счет какой точки на земном шаре соответствует каждой ячейке. Может быть, я просто не понимаю, что вы говорите, но я не уверен, как я могу его перестроить, чтобы сделать его проще. – shizishan

+0

@ user2258883, чтобы уточнить, вместо того, чтобы быть единственным значением за каждый день, это значение lat и lon? – KronoS

+0

Значения lat и lon находятся в другой матрице. X - это матрица 1437x159 с 1: 360 (длинная), идущая вниз по первому столбцу и повторяющаяся для всех столбцов. Y - тот же размер с -89,5 до -50 (широта Юг), проходящий через первый ряд и повторяющий все строки. dataAll (1437x159x1258) - это данные, соответствующие этим точкам через 1258 дней (мои индексы выше ошибочны, так как вы указали, что я отсутствовал два дня в феврале, а индексы были основаны на отсутствии этих двух дней). Таким образом, dataAll (1,1,1) будет составлять концентрацию морского льда на 1 (лон), -89,5 (лат), день 1 (20100101). – shizishan

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

  • Нет связанных вопросов^_^