如何将三维日常数据转换为每月?

时间:2017-06-01 06:56:00

标签: matlab loops matrix time-series

我有三维数据矩阵十年(2001-2010)。在每个文件中,数据矩阵是180 x 360 x 365/366(纬度x经度x每日降雨量)。例如:2001:180x360x365,2002:180x360x365,2003:180x360x365,2004:180x360x366 ........................... 2010:180x360x365

现在我想将每日降雨量转换为月降雨量(通过总结),并将所有年份合并到一个文件中。

所以我的最终输出将是180x360x120(纬度x经度x十年来的月降雨量)。

2 个答案:

答案 0 :(得分:0)

我相信你可以将它更快地用于工作,但它应该可以完成这项工作。 Haven没有经过适当的测试

% range of years
years = 2000:2016;
leap_years = [2000 2004 2008 2012 2016];

% Generating random data
nr_of_years = numel(years);
rainfall_data = cell(nr_of_years, 1);
for i=1:nr_of_years
    nr_of_days = 365;
    if ismember(years(i), leap_years);
        nr_of_days = 366;
    end
    rainfall_data{i} = rand(180, 360, nr_of_days);
end

您需要的实际代码位于

之下
% fixed stuff
months = 12;
nr_of_days = [31 28 31 30 31 30 31 31 30 31 30 31];
nr_of_days_leap = [31 29 31 30 31 30 31 31 30 31 30 31];

% building vectors of month indices for days
month_indices = [];
month_indices_leap = [];
for i=1:months
    month_indices_temp = repmat(i, nr_of_days(i), 1);
    month_indices_leap_temp = repmat(i, nr_of_days_leap(i), 1);
    month_indices = [month_indices; month_indices_temp];
    month_indices_leap = [month_indices_leap; month_indices_leap_temp];
end

% the result will be stored here
result = zeros(size(rainfall_data{i}, 1), size(rainfall_data{i}, 2), months*nr_of_years);

for i=1:nr_of_years
    % determining which indices to use depending if it is a leap year
    month_indices_temp = month_indices;
    if size(rainfall_data{i}, 3)==366
        month_indices_temp = month_indices_leap;
    end

    % data for the current year
    current_data = rainfall_data{i};
    % this holds the data for current year
    monthy_sums = zeros(size(rainfall_data{i}, 1), size(rainfall_data{i}, 2), months);
    for j=1:months
        monthy_sums(:,:,j) = sum(current_data(:,:,j==month_indices_temp), 3);
    end
    % putting it into the combined matrix
    result(:,:,((i-1)*months+1):(i*months)) = monthy_sums;
end

您可以使用datetimedatestrdatenum中的内置版本来实现更优雅的解决方案,但我不确定这些内容会更快或更短。

编辑:使用内置日期函数的替代方法

months = 12;
% where the result will be stored
result = zeros(size(rainfall_data{i}, 1), size(rainfall_data{i}, 2), months*nr_of_years);
for i=1:nr_of_years
    current_data = rainfall_data{i};
    % first day of the year
    year_start_timestamp = datenum(datetime(years(i), 1, 1));

    % holding current sums
    monthy_sums = zeros(size(current_data, 1), size(current_data, 2), months);

    % finding the month indices vector
    datetime_obj = datetime(datestr(year_start_timestamp:(year_start_timestamp+size(current_data, 3)-1)));
    month_indices = datetime_obj.Month;

    % summing
    for j=1:months
        monthy_sums(:,:,j) = sum(current_data(:,:,j==month_indices), 3);
    end 

    % result
    result(:,:,((i-1)*months+1):(i*months)) = monthy_sums;
end

第二个解决方案对我来说需要1.45秒,而第一个解决方案则需要1.2秒。两种情况的结果相同。希望这会有所帮助。

答案 1 :(得分:0)

这可能很耗时,但我想你可以使用某种形式的循环来按月迭代每年的数据,为每个月挑选适当数量的数据点,然后将其添加到最终数据集。下面(非常粗略)代码的效果可能有效:

years = ['2001','2002,'2003',...,'2010'];

months = ['Jan','Feb','Mar',...,'Dec'];

finalDataset=[];
for i=1:length(years)
    year = years(i);
    yearData=%% load in dataset for that year %%
    for j=1:length(months)
        month = months(j);
        switch month
             case {'Jan','Mar'}
                  days=30;
             case 'Feb'
                  days=28'
                  if(year=='2004' || year=='2008')
                     days=29;
                  end
              % then continue with cases to include each month
         end
         monthData=yearData(:,:,1:days) % extract the data for those months
         yearData(:,:,1:days)=[]; % delete data already extracted
         summedRain = % take mean of rainfall data
         monthSummed = % replace daily rainfall data with monthly rainfall, but keep latitude and longitude data
         finalDataset=[finalDataset; monthSummed];
      end
  end

道歉这是非常破旧的,我没有包含一些索引细节,但我希望这有助于至少说明一个想法?我也不完全确定'if'语句是否在'switch'语句中起作用,但如果没有,那么修正日可以添加到其他地方。