基于 R 中的交替列,在数据帧中滑动 window 平均值
Sliding window of mean across dataframe, based on alternate column in R
我希望使用滑动 window 方法计算变量的平均值,但基于数据框中另一列的值。很难解释所以...
以这个示例数据框为例:
dist <- c(seq(1,100,by=1),seq(101,200,by=2))
value<- runif(150, min=0, max=10)
df <- as.data.frame(cbind(dist,value))
head(df)
我知道我可以用下面的代码计算滑动 window 均值:
zoo::rollapply(df$value, width=50, by=25, FUN=mean, na.rm=TRUE,align="left")
然而,这并不是我想要的。我想计算 mean(df$value)
当 df$dist
范围从 1-50
然后 25-75
然后 50-100
等等。
上面没有这样做,因为在我的数据集中我不能假设 df$dist
系统地计数(即不会错过随机数)。因此,简单地应用 window 向下移动一定数量的行将产生不正确的结果。
任何关于我将如何处理这个问题的建议都很棒。
提前致谢。
这里有几种选择。 (1) 没有包依赖性,(2) 使用 rollapply,因此与问题中的代码最相似,(3) 使用 SQL 并且代码最短。
1) Base R 如果问题是 dist 不包含 1 和它的最大值之间的每个数字,那么我们可以像这样迭代间隔:
Fun <- function(st, width, df, fun) {
fun(subset(df, dist >= st & dist <= st + width - 1)$value)
}
width <- 50
step <- 25
starts <- seq(1, max(df$dist), step)
data.frame(starts,
ends = starts + width - 1,
mean = sapply(starts, Fun, width, df, mean),
N = sapply(starts, Fun, width, df, length))
给予:
starts ends mean N
1 1 50 5.200910 50
2 26 75 4.710030 50
3 51 100 4.770270 50
4 76 125 4.880030 38
5 101 150 5.318415 25
6 126 175 5.575938 25
7 151 200 4.989383 25
8 176 225 3.918574 12
2) rollapply 另一种方法是扩展输入数据框,在这种情况下我们可以使用 rollapply。
library(zoo)
roll <- function(x, width, fun, step) {
fun2 <- function(x) fun(na.omit(x))
rollapply(x, width, by = step, fun2, partial = TRUE, align = "left")
}
width <- 50
step <- 25
m <- merge(df, data.frame(dist = 1:max(df$dist)), all = TRUE)
data.frame(starts,
ends = starts + width - 1,
mean = roll(m$value, width, mean, step),
N = roll(m$value, width, length, step)
)
给予:
starts ends mean N
1 1 50 5.200910 50
2 26 75 4.710030 50
3 51 100 4.770270 50
4 76 125 4.880030 38
5 101 150 5.318415 25
6 126 175 5.575938 25
7 151 200 4.989383 25
8 176 225 3.918574 12
3) sqldf 这可以使用带有指定左连接的 SQL 紧凑地制定。
library(sqldf)
width <- 50
step <- 25
starts <- data.frame(starts = seq(1, max(df$dist), step))
fn$sqldf("select starts, starts+$width-1 ends, avg(value) mean, count(value) N
from starts
left join df on dist between starts and ends
group by starts.rowid")
给予:
starts ends mean N
1 1 50 5.200910 50
2 26 75 4.710030 50
3 51 100 4.770270 50
4 76 125 4.880030 38
5 101 150 5.318415 25
6 126 175 5.575938 25
7 151 200 4.989383 25
8 176 225 3.918574 12
备注
为了使输入可重现,我们必须在使用任何随机数之前设置种子,所以在上面我们使用了这个:
set.seed(123)
dist <- c(seq(1, 100, by = 1), seq(101, 200, by = 2))
value <- runif(150, min = 0, max = 10)
df <- data.frame(dist, value)
我希望使用滑动 window 方法计算变量的平均值,但基于数据框中另一列的值。很难解释所以...
以这个示例数据框为例:
dist <- c(seq(1,100,by=1),seq(101,200,by=2))
value<- runif(150, min=0, max=10)
df <- as.data.frame(cbind(dist,value))
head(df)
我知道我可以用下面的代码计算滑动 window 均值:
zoo::rollapply(df$value, width=50, by=25, FUN=mean, na.rm=TRUE,align="left")
然而,这并不是我想要的。我想计算 mean(df$value)
当 df$dist
范围从 1-50
然后 25-75
然后 50-100
等等。
上面没有这样做,因为在我的数据集中我不能假设 df$dist
系统地计数(即不会错过随机数)。因此,简单地应用 window 向下移动一定数量的行将产生不正确的结果。
任何关于我将如何处理这个问题的建议都很棒。
提前致谢。
这里有几种选择。 (1) 没有包依赖性,(2) 使用 rollapply,因此与问题中的代码最相似,(3) 使用 SQL 并且代码最短。
1) Base R 如果问题是 dist 不包含 1 和它的最大值之间的每个数字,那么我们可以像这样迭代间隔:
Fun <- function(st, width, df, fun) {
fun(subset(df, dist >= st & dist <= st + width - 1)$value)
}
width <- 50
step <- 25
starts <- seq(1, max(df$dist), step)
data.frame(starts,
ends = starts + width - 1,
mean = sapply(starts, Fun, width, df, mean),
N = sapply(starts, Fun, width, df, length))
给予:
starts ends mean N
1 1 50 5.200910 50
2 26 75 4.710030 50
3 51 100 4.770270 50
4 76 125 4.880030 38
5 101 150 5.318415 25
6 126 175 5.575938 25
7 151 200 4.989383 25
8 176 225 3.918574 12
2) rollapply 另一种方法是扩展输入数据框,在这种情况下我们可以使用 rollapply。
library(zoo)
roll <- function(x, width, fun, step) {
fun2 <- function(x) fun(na.omit(x))
rollapply(x, width, by = step, fun2, partial = TRUE, align = "left")
}
width <- 50
step <- 25
m <- merge(df, data.frame(dist = 1:max(df$dist)), all = TRUE)
data.frame(starts,
ends = starts + width - 1,
mean = roll(m$value, width, mean, step),
N = roll(m$value, width, length, step)
)
给予:
starts ends mean N
1 1 50 5.200910 50
2 26 75 4.710030 50
3 51 100 4.770270 50
4 76 125 4.880030 38
5 101 150 5.318415 25
6 126 175 5.575938 25
7 151 200 4.989383 25
8 176 225 3.918574 12
3) sqldf 这可以使用带有指定左连接的 SQL 紧凑地制定。
library(sqldf)
width <- 50
step <- 25
starts <- data.frame(starts = seq(1, max(df$dist), step))
fn$sqldf("select starts, starts+$width-1 ends, avg(value) mean, count(value) N
from starts
left join df on dist between starts and ends
group by starts.rowid")
给予:
starts ends mean N
1 1 50 5.200910 50
2 26 75 4.710030 50
3 51 100 4.770270 50
4 76 125 4.880030 38
5 101 150 5.318415 25
6 126 175 5.575938 25
7 151 200 4.989383 25
8 176 225 3.918574 12
备注
为了使输入可重现,我们必须在使用任何随机数之前设置种子,所以在上面我们使用了这个:
set.seed(123)
dist <- c(seq(1, 100, by = 1), seq(101, 200, by = 2))
value <- runif(150, min = 0, max = 10)
df <- data.frame(dist, value)