根据R中另一列的日期范围查找列的平均值

时间:2016-02-10 18:46:51

标签: r date average na

我有两个看起来像这样的数据框:

> 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,因为相应的Group.Size值对于数据框x中的相应日期是3,1和3(均值= 2.33,舍入到最接近的整数是2)。

如果我的数据帧x中有NA,我想将其视为0.

这个任务涉及多个步骤,可能有一个简单明了的方法......我对R来说相对较新,并且很难将其分解。如果我要澄清我的例子,请告诉我。

5 个答案:

答案 0 :(得分:1)

假设x$Datey$StartDatey$EndDate属于班级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)
    }
)

答案 1 :(得分:1)

#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)))

答案 2 :(得分:1)

这是一个不同的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

答案 3 :(得分:0)

这是一个适用于数据框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中的一个列中的三个值来定义函数yStart_DateEnd_Datelength。它使用过滤器从x中选择相关行,并对列Group.Size求和。使用na.rm = TRUE告诉sum()忽略NA值,这与将它们设置为零相同。然后通过除以length和舍入来计算平均值。请注意,round将一半舍入到偶数,因此0.5舍入为0,而1.5舍入为2.

然后使用y将此功能应用于Map()的所有行,并将其添加为y的新列。

关于xy中日期的最终说明。此解决方案假定日期存储为Date对象。您可以使用e进行检查。克,

is(x$Date, "Date")

如果他们没有课程Date,您可以使用

进行转换
x$Date <- as.Date(x$Date)

(同样适用于y$Start_Datey$End_Date)。

答案 4 :(得分:0)

有很多方法,但这里有一个。我们可以先用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