基于条件的 Rollmean

Rollmean based on conditions

基于下面的数据框,我想根据三个条件使用 rollmean 创建一个新列 - b 列中的值相互匹配,a 列中要平均的最小值为 2,我只想要对当前行下方的所有值进行平均。如果要平均的值的数量是 2 或更少,我想 return 一个空白值。

我假设我必须使用应用函数来执行此操作,但我不确定从哪里开始。

a=c(1,2,3,4,1,2,3,4,1,2,3,4)
b=c("X","X","X","X","Y","Y","Y","Y","Z","Z","Z","Z")
df=as.data.frame(cbind(a,b))

我希望最后的 table 看起来像:

Name    Value   Output
X        1         2.5
X        2         3
X        3  
X        4  
Y        1         2.5
Y        2         3
Y        3  
Y        4  
Z        1         2.5
Z        2         3
Z        3  
Z        4  

一个简单的tidverse解决方案。在每个组中,如果还剩两个以上的项目,则取当前索引 (row_number()) 到最终索引 (n()) 的平均值。

library(tidyverse)
df %>% 
  group_by(b) %>% 
  mutate(Output = map_dbl(row_number(), ~ifelse(n() - . < 3, NA, mean(a[.:n()]))))

数据

您创建数据的方式将 b 强制转换为字符向量(因为 cbind 构成了一个矩阵)。

简单使用:

a <- c(1,2,3,4,1,2,3,4,1,2,3,4)
b <- c("X","X","X","X","Y","Y","Y","Y","Z","Z","Z","Z")
df <- data.frame(a, b)

df <- data.frame(a = 1:4, b = rep(c('X', 'Y', 'Z'), each = 4))

注意问题中df的格式有误所以我们在下面修改了。我们可以这样使用 ave 。没有使用包。

df <- data.frame(a, b)
fun <- function(x) if (length(x) <= 2) NA else rev(cumsum(rev(x)) / c(NA, NA, 3:length(x)))
transform(df, Output = ave(a, b, FUN = fun))

给予:

   a b Output
1  1 X    2.5
2  2 X    3.0
3  3 X     NA
4  4 X     NA
5  1 Y    2.5
6  2 Y    3.0
7  3 Y     NA
8  4 Y     NA
9  1 Z    2.5
10 2 Z    3.0
11 3 Z     NA
12 4 Z     NA