【问题标题】:How to convert 3-dimensional daily data into monthly?如何将 3 维每日数据转换为每月数据?
【发布时间】:2017-11-02 04:31:36
【问题描述】:

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

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

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

【问题讨论】:

  • 最大的问题是月份不统一(天数不同)
  • 是的,2004 年和 2008 年是闰年。

标签: matlab loops matrix time-series


【解决方案1】:

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

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' 语句中工作,但如果没有,可以在其他地方添加天数修正。

【讨论】:

    【解决方案2】:

    我相信您可以将其矢量化以更快地工作,但它应该可以完成这项工作。没有正确测试

    % 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 秒。两种情况的结果相同。希望这会有所帮助。

    【讨论】:

      猜你喜欢
      • 2018-08-19
      • 2015-10-31
      • 1970-01-01
      • 1970-01-01
      • 2013-05-02
      • 2015-06-19
      • 1970-01-01
      • 1970-01-01
      • 2020-07-06
      相关资源
      最近更新 更多