【问题标题】:Find average values of a column in terms of date range of another column in R根据R中另一列的日期范围查找一列的平均值
【发布时间】:2016-02-10 18:46:50
【问题描述】:

我有两个如下所示的数据框:

> 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 相对较新,并且很难分解它。如果我应该澄清我的例子,请告诉我。

【问题讨论】:

    标签: r date average na


    【解决方案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)
        }
    )
    

    【讨论】:

    • 没错。我注意到并做了必要的修改。谢谢。
    • 这很好用。你介意走过你的脚步吗?我正在尝试了解您对函数 (z) 所做的操作。 @submartingale
    • 不过,这不会将NA 视为零。
    • @Stibu 是的,你是对的。它忽略 NA 而不是用 0 替换它们。将 NA 视为 0 很简单,只需在顶部添加一行:x$Group.Size&lt;-x$Group.Size[is.na(x$Group.Size)]
    【解决方案2】:
    #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)))
    

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        【解决方案4】:

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

        然后使用Map() 将此函数应用于y 的所有行,并作为新列添加到y

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

        is(x$Date, "Date")
        

        如果它们没有类Date,您可以使用转换它们

        x$Date <- as.Date(x$Date)
        

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

        【讨论】:

        • 我的输出是正确的。我的解决方案与您提出的解决方案之间的区别在于 meanna.rm = TRUE 在计算平均值时将省略 NA 值,而 OP 要求将 NA 视为零。另外,我决定使用length,因为可能缺少日期。
        【解决方案5】:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-06-05
          • 1970-01-01
          • 1970-01-01
          • 2022-11-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多