根据 R 中另一列的日期范围查找一列的平均值
Find average values of a column in terms of date range of another column in R
我有两个如下所示的数据框:
> head(y,n=4)
Source: local data frame [6 x 3]
Start Date End Date Length
1 2006-06-08 2006-06-10 3
2 2006-06-12 2006-06-14 3
3 2006-06-18 2006-06-21 4
4 2006-06-24 2006-06-25 2
和
> head(x,n=19)
Date Group.Size
413 2006-06-07 6
414 2006-06-08 3
415 2006-06-09 1
416 2006-06-10 3
417 2006-06-11 15
418 2006-06-12 12
419 2006-06-13 NA
420 2006-06-14 4
421 2006-06-15 8
422 2006-06-16 3
423 2006-06-17 1
424 2006-06-18 3
425 2006-06-19 10
426 2006-06-20 2
427 2006-06-21 7
428 2006-06-22 6
429 2006-06-23 2
430 2006-06-24 1
431 2006-06-25 0
我正在寻找一种在数据框 y 中添加新列的方法,该列将显示数据框 x 的平均值 Group.Size(四舍五入为最接近的整数),具体取决于给定的开始日期和结束日期y 中提供的日期。
例如,在 y 的第一行,我有 6/8/06 到 6/10/06。这是 3 天的长度,所以我希望新列的数字为 2,因为数据框 x 中相应日期的相应 Group.Size 值为 3、1 和 3(平均值 = 2.33,四舍五入到最接近的整数是 2).
如果我的数据框 x 中有一个 NA,我想将其视为 0。
此任务涉及多个步骤,可能有一个简单的方法...我对 R 比较陌生,很难分解它。如果我应该澄清我的例子,请告诉我。
这是一个应用于数据框行的解决方案 y
:
library(dplyr)
get_mean_size <- function(start, end, length) {
s <- sum(filter(x, Date >= start, Date <= end)$Group.Size, na.rm = TRUE)
round(s/length)
}
y$Mean.Size = Map(get_mean_size, y$Start_Date, y$End_Date, y$Length)
y
## Start_Date End_Date Length Mean.Size
## 1 2006-06-08 2006-06-10 3 2
## 2 2006-06-12 2006-06-14 3 5
## 3 2006-06-18 2006-06-21 4 6
## 4 2006-06-24 2006-06-25 2 0
它使用了 dplyr
包中的两个函数:filter()
和 mutate()
。
首先,我定义了函数 get_mean_size
,该函数假定使用 y
中一列的三个值:Start_Date
、End_Date
和 length
。它首先使用过滤器从 x
中选择相关行并对列 Group.Size
求和。使用 na.rm = TRUE
告诉 sum()
忽略 NA
值,这与将它们设置为零相同。然后通过除以 length
并四舍五入计算平均值。请注意,round
四舍五入为偶数,因此 0.5 四舍五入为 0,而 1.5 四舍五入为 2。
此函数然后使用 Map()
应用于 y
的所有行,并作为新列添加到 y
。
关于 x
和 y
中日期的最后说明。此解决方案假定日期存储为 Date
对象。您可以使用 e. g.,
is(x$Date, "Date")
如果他们没有class Date
,您可以使用
转换它们
x$Date <- as.Date(x$Date)
(y$Start_Date
和 y$End_Date
也类似)。
有很多方法,但这里是一种方法。我们可以先用 lapply
创建一个日期位置列表(SN:确保日期按时间顺序排列)。然后我们将函数 round(mean(Group.Size))
映射到每个值:
lst <- lapply(y[1:2], function(.x) match(.x, x[,"Date"]))
y$avg <- mapply(function(i,j) round(mean(x$Group.Size[i:j], na.rm=TRUE)), lst[[1]],lst[[2]])
y
# StartDate EndDate Length avg
# 1 2006-06-08 2006-06-10 3 2
# 2 2006-06-12 2006-06-14 3 8
# 3 2006-06-18 2006-06-21 4 6
# 4 2006-06-24 2006-06-25 2 0
假设 x$Date
、y$StartDate
和 y$EndDate
属于 class Date
(或 character
),则以下 apply
方法应该可以解决问题:
y$AvGroupSize<- apply(y, 1, function(z) {
round(mean(x$Group.Size[which(x$Date >= z[1] & x$Date <=z[2])], na.rm=T),0)
}
)
#Replace missing values in x with 0
x[is.na(x)] <- 0
#Create new 'Group' variable and loop through x to create groups
x$Group <-1
j <- 1
for(i in 1:nrow(x)){
if(x[i,"Date"]==y[j,"StartDate"]){
x[i,"Group"] <- j+1
if(j<nrow(y)){
j <- j+1
} else{
j <- j
}
}else if(i>1){
x[i,"Group"] <- x[i-1,"Group"]
}else {
x[i,"Group"] <- 1
}
}
#Use tapply function to get the rounded mean of each Group
tapply(x$Group.Size, x$Group, function(z) round(mean(z)))
这是一个不同的dplyr
解决方案
library(dplyr)
na2zero <- function(x) ifelse(is.na(x),0,x) # Convert NA to zero
ydf %>%
group_by(Start_Date, End_Date) %>%
mutate(avg = round(mean(na2zero(xdf$Group.Size[ between(xdf$Date, Start_Date, End_Date) ])), 0)) %>%
ungroup
## Start_Date End_Date Length avg
## (time) (time) (int) (dbl)
## 1 2006-06-08 2006-06-10 3 2
## 2 2006-06-12 2006-06-14 3 5
## 3 2006-06-18 2006-06-21 4 6
## 4 2006-06-24 2006-06-25 2 0
我有两个如下所示的数据框:
> head(y,n=4)
Source: local data frame [6 x 3]
Start Date End Date Length
1 2006-06-08 2006-06-10 3
2 2006-06-12 2006-06-14 3
3 2006-06-18 2006-06-21 4
4 2006-06-24 2006-06-25 2
和
> head(x,n=19)
Date Group.Size
413 2006-06-07 6
414 2006-06-08 3
415 2006-06-09 1
416 2006-06-10 3
417 2006-06-11 15
418 2006-06-12 12
419 2006-06-13 NA
420 2006-06-14 4
421 2006-06-15 8
422 2006-06-16 3
423 2006-06-17 1
424 2006-06-18 3
425 2006-06-19 10
426 2006-06-20 2
427 2006-06-21 7
428 2006-06-22 6
429 2006-06-23 2
430 2006-06-24 1
431 2006-06-25 0
我正在寻找一种在数据框 y 中添加新列的方法,该列将显示数据框 x 的平均值 Group.Size(四舍五入为最接近的整数),具体取决于给定的开始日期和结束日期y 中提供的日期。
例如,在 y 的第一行,我有 6/8/06 到 6/10/06。这是 3 天的长度,所以我希望新列的数字为 2,因为数据框 x 中相应日期的相应 Group.Size 值为 3、1 和 3(平均值 = 2.33,四舍五入到最接近的整数是 2).
如果我的数据框 x 中有一个 NA,我想将其视为 0。
此任务涉及多个步骤,可能有一个简单的方法...我对 R 比较陌生,很难分解它。如果我应该澄清我的例子,请告诉我。
这是一个应用于数据框行的解决方案 y
:
library(dplyr)
get_mean_size <- function(start, end, length) {
s <- sum(filter(x, Date >= start, Date <= end)$Group.Size, na.rm = TRUE)
round(s/length)
}
y$Mean.Size = Map(get_mean_size, y$Start_Date, y$End_Date, y$Length)
y
## Start_Date End_Date Length Mean.Size
## 1 2006-06-08 2006-06-10 3 2
## 2 2006-06-12 2006-06-14 3 5
## 3 2006-06-18 2006-06-21 4 6
## 4 2006-06-24 2006-06-25 2 0
它使用了 dplyr
包中的两个函数:filter()
和 mutate()
。
首先,我定义了函数 get_mean_size
,该函数假定使用 y
中一列的三个值:Start_Date
、End_Date
和 length
。它首先使用过滤器从 x
中选择相关行并对列 Group.Size
求和。使用 na.rm = TRUE
告诉 sum()
忽略 NA
值,这与将它们设置为零相同。然后通过除以 length
并四舍五入计算平均值。请注意,round
四舍五入为偶数,因此 0.5 四舍五入为 0,而 1.5 四舍五入为 2。
此函数然后使用 Map()
应用于 y
的所有行,并作为新列添加到 y
。
关于 x
和 y
中日期的最后说明。此解决方案假定日期存储为 Date
对象。您可以使用 e. g.,
is(x$Date, "Date")
如果他们没有class Date
,您可以使用
x$Date <- as.Date(x$Date)
(y$Start_Date
和 y$End_Date
也类似)。
有很多方法,但这里是一种方法。我们可以先用 lapply
创建一个日期位置列表(SN:确保日期按时间顺序排列)。然后我们将函数 round(mean(Group.Size))
映射到每个值:
lst <- lapply(y[1:2], function(.x) match(.x, x[,"Date"]))
y$avg <- mapply(function(i,j) round(mean(x$Group.Size[i:j], na.rm=TRUE)), lst[[1]],lst[[2]])
y
# StartDate EndDate Length avg
# 1 2006-06-08 2006-06-10 3 2
# 2 2006-06-12 2006-06-14 3 8
# 3 2006-06-18 2006-06-21 4 6
# 4 2006-06-24 2006-06-25 2 0
假设 x$Date
、y$StartDate
和 y$EndDate
属于 class Date
(或 character
),则以下 apply
方法应该可以解决问题:
y$AvGroupSize<- apply(y, 1, function(z) {
round(mean(x$Group.Size[which(x$Date >= z[1] & x$Date <=z[2])], na.rm=T),0)
}
)
#Replace missing values in x with 0
x[is.na(x)] <- 0
#Create new 'Group' variable and loop through x to create groups
x$Group <-1
j <- 1
for(i in 1:nrow(x)){
if(x[i,"Date"]==y[j,"StartDate"]){
x[i,"Group"] <- j+1
if(j<nrow(y)){
j <- j+1
} else{
j <- j
}
}else if(i>1){
x[i,"Group"] <- x[i-1,"Group"]
}else {
x[i,"Group"] <- 1
}
}
#Use tapply function to get the rounded mean of each Group
tapply(x$Group.Size, x$Group, function(z) round(mean(z)))
这是一个不同的dplyr
解决方案
library(dplyr)
na2zero <- function(x) ifelse(is.na(x),0,x) # Convert NA to zero
ydf %>%
group_by(Start_Date, End_Date) %>%
mutate(avg = round(mean(na2zero(xdf$Group.Size[ between(xdf$Date, Start_Date, End_Date) ])), 0)) %>%
ungroup
## Start_Date End_Date Length avg
## (time) (time) (int) (dbl)
## 1 2006-06-08 2006-06-10 3 2
## 2 2006-06-12 2006-06-14 3 5
## 3 2006-06-18 2006-06-21 4 6
## 4 2006-06-24 2006-06-25 2 0