根据下面的数据框,我想基于三个条件使用rollmean创建一个新列 - 列b中的值彼此匹配,列a中要平均的最小值是2,我只想要平均当前行以下的所有值。如果要平均的值的数量是2或更少,我想返回一个空白值。
我假设我必须使用apply函数来执行此操作,但我不知道从哪里开始。
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))
我希望决赛桌看起来像:
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
答案 0 :(得分:3)
一个简单的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))
答案 1 :(得分:0)
请注意,问题中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