2017-06-01 4 views
1

J'ai une matrice de données tridimensionnelle pour dix ans (2001-2010). Dans chaque fichier, la matrice de données est de 180 x 360 x 365/366 (latitude x longitude x précipitations quotidiennes). par exemple: 2001: 180x360x365, 2002: 180x360x365, 2003: 180x360x365, 2004: 180x360x366 ........................... 2010: 180x360x365Comment convertir les données quotidiennes en 3 dimensions en mensuel?

Maintenant, je veux convertir cette pluie quotidienne en précipitations mensuelles (en sommant) et combiner toutes les années dans un fichier. Donc, ma sortie finale sera de 180 x 360 x 120 (latitude x longitude x précipitations mensuelles sur dix ans).

+0

Le plus gros problème avec ceci est la non-uniformité des mois (ils ont différents nombre de jours) –

+0

Oui, pendant la période 2004 et 2008 sont des années bissextiles. – SONY

Répondre

0

Je suis sûr que vous pouvez vectoriser cela pour travailler plus vite, mais cela devrait faire l'affaire. Je n'ai pas testé correctement

% 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 

Le code réel que vous avez besoin est ci-dessous

% 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 

Vous pouvez probablement obtenir une solution plus élégante à l'aide à construire datetime, datestr et datenum, mais je ne suis pas sûr que ceux ne être beaucoup plus rapide ou plus court.

EDIT: Une alternative utilisant des fonctions intégrées de date

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 

Cette 2ème solution a pris 1,45 secondes pour moi, par rapport à 1,2 secondes pour la première solution. Les résultats étaient les mêmes pour les deux cas. J'espère que cela t'aides.

0

Cela peut prendre du temps, mais je suppose que vous pourriez utiliser une forme de boucle pour parcourir chaque mois les données de chaque année, choisir le nombre approprié de points de données pour chaque mois, puis ajouter cela à un ensemble de données final. Quelque chose à l'effet du code (très approximative) ci-dessous peuvent travailler:

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 

Toutes mes excuses, il est très mauvais état et je n'ai pas compris certains détails d'indexation, mais je l'espère, qui aide à au moins illustrant une idée? Je ne suis pas non plus entièrement sûr que les instructions 'if' fonctionnent dans les instructions 'switch', mais l'amendement de jours peut être ajouté ailleurs si ce n'est pas le cas.