使用 rollmean 过滤掉具有阈值的 NA

Using rollmean filtering out NA with threshold

我正在尝试将 rollapply mean 函数应用于具有大量缺失数据和散布在整个缺失数据中的单点的数据框。使用我当前的 rollapply 形式,只需要一个非 NaN 值并将其平均为所有周围的值。我的目标是保留至少有一半平均值的值,并删除超过 50% NaN 数据的所有值。下面是我做的一个简单的例子

library(zoo)

a <- c(0:20)
ind <- c(10:15)
ind2 <- c(10:12,14)
b <- a
b[ind] <- NaN
c <- a
c[ind2] <- NaN
df <- data.frame(a=a,b=b,c=c)
dfroll <- as.data.frame(rollapply(df,width=5,mean,na.rm=T,fill=NA))

结果如下data.frame

dfroll
    a    b        c
1  NA   NA       NA
2  NA   NA       NA
3   2  2.0  2.00000
4   3  3.0  3.00000
5   4  4.0  4.00000
6   5  5.0  5.00000
7   6  6.0  6.00000
8   7  6.5  6.50000
9   8  7.0  7.00000
10  9  7.5  7.50000
11 10  8.0 10.00000
12 11  NaN 12.00000
13 12  NaN 13.00000
14 13 15.0 13.66667
15 14 15.5 14.25000
16 15 16.0 15.50000
17 16 16.5 16.00000
18 17 17.0 17.00000
19 18 18.0 18.00000
20 NA   NA       NA
21 NA   NA       NA

对于此示例,我希望所有具有 >= 3 NaN 个值的值都产生 NaN。这将是 b 列上的 10:15 行和 c 列上的 10:13 行。如果单元格周围的数据有限,我将如何设置此阈值以通过 NaN 而不是平均值?

想要的结果:

bdesired <- dfroll$b
bdesired[c(10:15)] <- NaN
cdesired <- dfroll$c
cdesired[c(10:13)] <- NaN
dfdesired <- data.frame(a=dfroll$a,b=bdesired,c=cdesired)
 dfdesired
    a    b        c
1  NA   NA       NA
2  NA   NA       NA
3   2  2.0  2.00000
4   3  3.0  3.00000
5   4  4.0  4.00000
6   5  5.0  5.00000
7   6  6.0  6.00000
8   7  6.5  6.50000
9   8  7.0  7.00000
10  9  NaN      NaN
11 10  NaN      NaN
12 11  NaN      NaN
13 12  NaN      NaN
14 13  NaN 13.50000
15 14  NaN 14.33333
16 15 16.0 16.00000
17 16 16.5 16.50000
18 17 17.0 17.00000
19 18 18.0 18.00000
20 NA   NA       NA
21 NA   NA       NA

使用 across(everything() 你可以对所有列进行操作,然后使用 rollsum(is.na()) 我们计算 NAs 的数量,只有当它不是 3 或更高时我们计算rollmean.

我只注意到 c-variable 的某些值在 dfrolldfdesired 中略有不同。我的结果与 dfroll.

中的结果相符
library(tidyverse)

df %>% 
  mutate(across(everything(), 
                ~ifelse(rollsum(is.na(.x), 5, fill = NA) > 2, NaN, rollmean(.x, 5, fill = NA, na.rm = T))))


    a    b        c
1  NA   NA       NA
2  NA   NA       NA
3   2  2.0  2.00000
4   3  3.0  3.00000
5   4  4.0  4.00000
6   5  5.0  5.00000
7   6  6.0  6.00000
8   7  6.5  6.50000
9   8  7.0  7.00000
10  9  NaN      NaN
11 10  NaN      NaN
12 11  NaN      NaN
13 12  NaN      NaN
14 13  NaN 13.66667
15 14  NaN 14.25000
16 15 16.0 15.50000
17 16 16.5 16.00000
18 17 17.0 17.00000
19 18 18.0 18.00000
20 NA   NA       NA
21 NA   NA       NA

1) 定义一个函数,如果其输入中有 thresh 或更多 NA 并且 returns 意味着 returns NaN non-NA 的其他情况。然后与 rollapply 一起使用。如果需要,使用 as.data.frame 将其转换为数据框,但由于数据完全是数字,将其作为矩阵可能就足够了。

w <- 5
thresh <- w/2

Mean <- function(x, thresh) if (sum(is.na(x)) > thresh) NaN else mean(x,na.rm=TRUE)
rollapply(df, w, Mean, thresh = thresh, fill = NA)

2) 另一种可能性是检查每个单元格中是否有超过阈值的 NA,如果是 return NaN,否则 return 滚动意思。如果需要数据框,请再次对结果使用 as.data.frame。 (1) 比这个有优势,它只调用 roll* 一次而不是两次。

w <- 5
thresh <- w/2

ifelse(rollsum(is.na(df), w, fill = NA) > thresh, NaN, 
    rollmean(df, w, na.rm = TRUE, fill = NA))