重塑3D阵列并删除缺失值

时间:2017-07-20 14:57:40

标签: arrays matlab matrix nan reshape

我有一个NxMxT数组,其中数组的每个元素都是地球网格。如果网格在海洋上方,那么该值为999.如果网格在陆地上,则它包含观测值。 N是经度,M是纬度,T是月。 特别是,我有一个名为tmp60的阵列,从1960年到1969年,所以每个网格120个月。

为了测试1960年1月全球意味着什么,我写道:

tmpJan60=tmp60(:,:,1);
tmpJan60(tmpJan60(:,:)>200)=NaN;
nanmean(nanmean(tmpJan60))

这给了我5.855。

我对重塑功能感到困惑。我认为以下代码应该产生相同的平均值,即5.855,但它没有:

load tmp60

N1=size(tmp60,1)
N2=size(tmp60,2)
N3=size(tmp60,3)

reshtmp60 = reshape(tmp60, N1*N2,N3);
reshtmp60( reshtmp60(:,1)>200,: )=[];
mean(reshtmp60(:,1))

这给了我-1.6265,这是不正确的。

我已经在Excel中检查了结果(!)并且5.855是正确的,所以我假设我在重塑函数中犯了一个错误。

理想情况下,我想要一个矩阵,它采用每个网格,首先沿着N维,然后使720列(每列是一个月)。这些前720行将代表相同纬度的地球周围的一个经度带。接下来,我想将纬度增加1,因此另外720行增加120列。最终我想为所有360纬度做到这一点。 如果输入经度和纬度,比如第1列和第2列,则矩阵应如下所示:

temp = [-179.75 -89.75 -1  2 ...
        -179.25 -89.75 2  4 ...
           ...
         179.75 -89.75 5 9 ...
        -179.75 -89.25 2  5 ...
        -179.25 -89.25 3  4 ... 
          ...
        -179.75  89.75 2  3 ...
          ...
         179.75  89.75 6  9 ...]

所以temp(:,3)应该是所有1960年1月的观察结果。

一种方法是:

grid1 = tmp60(1,1,:);
g1 = reshape(grid1, [1,120]);
grid2 = tmp60(2,1,:);
g2 = reshape(grid2,[1,120]);
g = [g1;g2];

但显然非常麻烦。

我无法为N * M元素自动执行此过程,因此感谢您的评论!

A link to the file tmp60.mat

1 个答案:

答案 0 :(得分:1)

代码中的主要问题是处理nan。请注意以下示例:

a = randi(10,6);
a(a>7)=nan
m = [mean(a(:),'omitnan') mean(mean(a,'omitnan'),'omitnan')]

m =
       3.8421       3.6806

m中的两个元素都只是a中所有元素的均值。但他们是不同的!原因是将所有值的均值相加在一起,mean(a(:),'omitnan')就像汇总所有非-nan值,并除以我们求和的值的数量:

sum(a(:),'omitnan')/sum(~isnan(a(:)))==mean(a(:),'omitnan') % this is true

但是取第一维的平均值,得到6个均值:

sum(a,'omitnan')./sum(~isnan(a))==mean(a,'omitnan') % this is also true

当我们取它们的平均值时,我们除以一个更大的数字,因为已经省略了所有nan

mean(sum(a,'omitnan')./sum(~isnan(a)))==mean(a(:),'omitnan') % this is false

以下是我认为你想要的代码:

% this is exactly as your first test:
tmpJan60=tmn60(:,:,1);
tmpJan60(tmpJan60>200) = nan;
m1 = mean(mean(tmpJan60,'omitnan'),'omitnan')

% this creates the matrix as you want it:
result = reshape(permute(tmn60,[3 1 2]),120,[]).';
result(result>200) = nan;
r = reshape(result(:,1),720,360);
m2 = mean(mean(r,'omitnan'),'omitnan')

isequal(m1,m2)

要创建矩阵,首先要对尺寸进行置换,这样您想保留的尺寸(时间)将是第一个。然后将数组重新整形为Tx(lon * lat),因此所有时间步长都有120行,所有坐标组合都有259200列。剩下的就是转置它。

m1是您的第一个计算,m2是您尝试在第二个计算中执行的操作。它们在这里相等,但它们的值不是5.855,即使我使用你的代码。

但是,我认为正确的解决方案是将所有值的平均值放在一起:

mean(result(:,1),'omitnan')