【问题标题】:replace nan values with the mean of other rows用其他行的平均值替换 nan 值
【发布时间】:2013-01-13 06:03:01
【问题描述】:

考虑以下示例:

Jday = datenum('2007-01-01 00:00','yyyy-mm-dd HH:MM'):1:...
    datenum('2009-12-31 23:00','yyyy-mm-dd HH:MM');
Jday2 = datenum('2008-01-01 00:00','yyyy-mm-dd HH:MM'):1:...
    datenum('2010-12-31 23:00','yyyy-mm-dd HH:MM');

Data{1} = [Jday;1+(length(Jday)-1).*rand(1,length(Jday))]';
Data{2} = [Jday2;1+(length(Jday)-1).*rand(1,length(Jday))]';
Data{3} = [Jday;1+(length(Jday)-1).*rand(1,length(Jday))]';

for i = 1:length(Data);
    d_nan{i} = floor(1+(length(Jday)-1).*rand(1,100));
end

for i = 1:length(Data);
    a(i) = length(d_nan{i});
    for ii = 1:a(i);
        Data{i}(d_nan{i}(ii),2) = nan;
    end
end

在此示例中,我有一个单元格数组“数据”,其中包含三个单元格数组,每个单元格数组的第一列包含第二列中值的儒略日期。每个元胞数组中有许多 nan 值。我想用该特定朱利安日期的其他单元格中的值的平均值替换每个单元格数组中的 nan 值。我的问题很复杂,因为三个单元格没有同时显示数据(尽管 Data{1} 和 Data{3} 具有相同的日期。)如果三个单元格之间的儒略日期相同,则可以通过使用来解决此问题isnan 找到 nans 的位置,然后用其他行的 nanmean 替换这些行(在其他单元格中)。

谁能提出解决这个问题的有效方法?感谢您的宝贵时间

【问题讨论】:

  • 你能保证所有的元胞数组都是相同的维度吗?如果是,那你为什么不使用 N×6 矩阵来存储所有内容?
  • 不,我不能保证它们的尺寸相同。每个单元格代表一个不同的位置,这会发生变化。
  • 那么如果NaN 值在其他数组中没有匹配的日期会发生什么?
  • 在这种情况下,它将保持为 nan。
  • 你检查我的解决方案了吗?

标签: matlab nan mean


【解决方案1】:

一个可能的解决方案是:

  1. 连接所有数据并定位NaN 值:

    D = [vertcat(Data{:})];
    nanidx = find(isnan(D(:, 2)));
    
  2. 对于连接矩阵D中此类NaN值的每个索引k,查找具有相同日期的其他条目:

    entries = find(D(:, 1) == D(k, 1));
    
  3. 从这些条目中过滤非NaN 值,并将k 位置处的原始NaN 替换为平均值:

    values = D(~isnan(D(entries, 2)) & ~ismember(entries, nanidx), 2);
    D(k, 2) = mean(values);
    
  4. 将所有内容转换回元胞数组:

    Data = mat2cell(D, cellfun('length', Data), 2)';
    

这是最终的、适合复制粘贴的代码:

D = [vertcat(Data{:})];
nanidx = find(isnan(D(:, 2)));
for k = transpose(nanidx(:))
    entries = find(D(:, 1) == D(k, 1));
    values = D(~isnan(D(entries, 2)) & ~ismember(entries, nanidx), 2);
    D(k, 2) = mean(values);
end
Data = mat2cell(D, cellfun('length', Data), 2)';

【讨论】:

    【解决方案2】:

    不确定您是否看到了编辑(我是新用户,所以仍在学习它是如何工作的),所以这里有一个解决方案,可以满足您的要求,并在其他两个没有相同日期的地方留下 NaN .

    for i = 1:3
        for j = 1:length(Jday)
            if isnan(Data{i}(j,2))
                d = Data{i}(j,1);
                if (~isempty(find(Data{:,1}==d,1)) && ...
                    ~isempty(find(Data{:,2}==d,1)) && ...
                    ~isempty(find(Data{:,3}==d,1)))
                    Data{i}(j,2) = nanmean([ ...
                        Data{1}(find(Data{:,1}==d,1),2) ...
                        Data{2}(find(Data{:,2}==d,1),2) ...
                        Data{3}(find(Data{:,3}==d,1),2) ]);
                end
            end
        end
    end
    

    【讨论】:

    • 您应该使用编辑链接来改进您之前的答案,而不是将其作为单独的答案发布。
    【解决方案3】:

    这可能会解决您的问题,尽管它并不完全符合您的要求。在每个 NaN 值处,将其替换为当天插值的平均值,并从插值中移除 NaN。

    for i = 1:3
        for j = 1:length(Jday)
            if isnan(Data{i}(j,2))
                d = Data{i}(j,1);
                Data{i}(j,2) = mean([ ...
                    interp1(Data{1}(find(~isnan(Data{1}(:,2))),1),Data{1}(find(~isnan(Data{1}(:,2))),2),d) ...
                    interp1(Data{2}(find(~isnan(Data{2}(:,2))),1),Data{2}(find(~isnan(Data{2}(:,2))),2),d) ...
                    interp1(Data{3}(find(~isnan(Data{3}(:,2))),1),Data{3}(find(~isnan(Data{3}(:,2))),2),d)]);
            end
        end
    end
    

    【讨论】:

    • 插值不会真正适用于我的数据,但感谢您的建议
    • 我没有意识到你可以离开 NaN。添加了一个解决方案来做你最初要求的事情:)
    猜你喜欢
    • 2018-04-30
    • 2013-04-01
    • 2014-10-03
    • 2019-03-21
    • 2016-01-08
    • 2018-09-18
    • 2013-09-12
    相关资源
    最近更新 更多