【问题标题】:R - Copy values within a groupR - 在组内复制值
【发布时间】:2018-03-13 12:20:01
【问题描述】:

我有一个数据框,其中包含某人在过去 3 年(2016 年、2017 年、2018 年)中得分的总数,以及他们每年的分数列。

我的数据框如下所示:

myDF <- data.frame(ID =c(1,1,1,2,2,3,4),
 Dates= c("2016", "2017", "2018", "2016", "2017", "2018", "2016"),
 Total_Points = c(5, 5, 5, 4, 4, 2, 3),
 Points2016 = c(3, NA, NA, 2, NA, NA, 3),
 Points2017 = c(NA,1,NA,NA,2,NA,NA),
 Points2018= c(NA,NA,1, NA, NA, 2, NA))

问题是我想为每个组复制“Points2016”、“Points2017”和“Points2017”列的值,以便它们的条目看起来相同。

我不确定解释是否清楚,所以这将是我的预期输出:

myDF_final <- data.frame(ID =c(1,1,1,2,2,3,4),
               Dates= c("2016", "2017", "2018", "2016", "2017", "2018", "2016"),
               Total_Points = c(5, 5, 5, 4, 4, 2, 3),
               Points2016 = c(3, 3, 3, 2, 2, NA, 3),
               Points2017 = c(1,1,1,2,2,NA,NA),
               Points2018= c(1,1,1, NA, NA, 2, NA))

基本上,我希望每个 ID 的“Points201X”列具有相同的值。

【问题讨论】:

    标签: r copy replicate


    【解决方案1】:

    我认为您可以在两个方向上填写ID 组。使用dplyrtidyr,我们可以这样做:

    library(dplyr)
    library(tidyr)
    
    myDF %>% 
      group_by(ID) %>% 
      fill(Points2016, Points2017, Points2018) %>% 
      fill(Points2016, Points2017, Points2018, .direction = "up")
    

    返回:

      ID Dates Total_Points Points2016 Points2017 Points2018
    1  1  2016            5          3          1          1
    2  1  2017            5          3          1          1
    3  1  2018            5          3          1          1
    4  2  2016            4          2          2         NA
    5  2  2017            4          2          2         NA
    6  3  2018            2         NA         NA          2
    7  4  2016            3          3         NA         NA
    

    另外,如果你有很多年,比如 1970 - 2018 年,你可以这样做:

    myDF %>% 
      gather(points_year, points, -c(ID, Dates, Total_Points)) %>% 
      group_by(ID, points_year) %>% 
      fill(points) %>% 
      fill(points, .direction = "up") %>% 
      spread(points_year, points)
    

    以免每年都打字。但是,这涉及收集和传播数据,假设我们需要 fill 的变量遵循一致的命名约定,这可能是不必要的。在这种情况下,有一个一致的命名约定,我们可以使用dplyr 的后端tidyselect 来填充所有以单词“Points”开头的变量:

    myDF %>% 
      group_by(ID) %>% 
      fill(starts_with("Points"), .direction = "down") %>% 
      fill(starts_with("Points"), .direction = "up")
    

    另外,这似乎适用于 data.tablezoo

    library(data.table)
    library(zoo)
    
    dt <- as.data.table(myDF)
    
    dt <- dt[, names(dt)[4:6] := lapply(.SD, function(x) na.locf0(x)), by = ID, .SDcols = 4:6]
    dt <- dt[, names(dt)[4:6] := lapply(.SD, function(x) na.locf0(x, fromLast = TRUE)), by = ID, .SDcols = 4:6]
    

    这一个班轮似乎也可以一口气完成所有工作:

    dt[, names(dt)[4:6] := lapply(.SD, function(x) na.locf(x)), by = ID, .SDcols = 4:6]
    
       ID Dates Total_Points Points2016 Points2017 Points2018
    1:  1  2016            5          3          1          1
    2:  1  2017            5          3          1          1
    3:  1  2018            5          3          1          1
    4:  2  2016            4          2          2         NA
    5:  2  2017            4          2          2         NA
    6:  3  2018            2         NA         NA          2
    7:  4  2016            3          3         NA         NA
    

    【讨论】:

    • “聚集”在做什么? “points_year”和“points”列是什么?非常感谢
    • gather 正在获取一个广泛的数据集,并通过将其折叠成键值对来使其变长。 points_year 是我分配给键变量的名称,points 是我分配给值变量的名称。参见 tidyr.tidyverse.org/reference/gather.html
    • 谢谢!今晚我会试试,我的数据集很大,它说计算需要 4 小时 :)
    • 乐于助人。您可能想尝试data.table 解决方案,应该更快。不过我不是data.table 巫师 :)
    • 我觉得奇怪的是,dplyr 中没有像 .direction = "any" 这样的更“优雅”的解决方案。
    【解决方案2】:

    您也可以使用zoo::na.locf0 从顶部和底部填充NAs。

    library(tidyverse);
    library(zoo);
    myDF %>%
        group_by(ID) %>%
        mutate_at(vars(contains("Points20")), funs(na.locf0(., fromLast = F))) %>%
        mutate_at(vars(contains("Points20")), funs(na.locf0(., fromLast = T)))
    ## A tibble: 7 x 6
    ## Groups:   ID [4]
    #     ID Dates Total_Points Points2016 Points2017 Points2018
    #  <dbl> <fct>        <dbl>      <dbl>      <dbl>      <dbl>
    #1    1. 2016            5.         3.         1.         1.
    #2    1. 2017            5.         3.         1.         1.
    #3    1. 2018            5.         3.         1.         1.
    #4    2. 2016            4.         2.         2.        NA
    #5    2. 2017            4.         2.         2.        NA
    #6    3. 2018            2.        NA         NA          2.
    #7    4. 2016            3.         3.        NA         NA
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-14
      • 2012-07-25
      • 2014-06-05
      相关资源
      最近更新 更多