【问题标题】:Reshape dataframe so that matching family members have their own column重塑数据框,以便匹配的家庭成员拥有自己的列
【发布时间】:2020-06-17 05:35:00
【问题描述】:

我有一个数据框...

df <- tibble(
  id = 1:5, 
  family = c("a","a","b","b","c"), 
  twin = c(1,2,1,2,1), 
  datacol1 = 11:15, 
  datacol2 = 21:25
  )

对于每一对双胞胎(同一个家庭的成员),我需要有一个包含其他双胞胎数据的第二个“datacol”。这应该只发生在匹配的双胞胎上,所以第 5 行(来自“c”族)应该有重复的空列。

理想情况下,到最后,数据将如下所示...

df <- tibble(
  id = 1:5, 
  family = c("a","a","b","b","c"), 
  twin = c(1,2,1,2,1), 
  datacol1 = 11:15,
  datacol1.b = c(12,11,14,13,NA),
  datacol2 = 21:25, 
  datacol2.b = c(22,21,24,23,NA)
  )

我添加了一张图片来帮助说明我想要达到的目的。

我希望能够对所有列或选定的列执行此操作,并且最好使用 tidyverse。

【问题讨论】:

    标签: r tidyverse data-wrangling


    【解决方案1】:

    我们也可以使用mutate_at

    library(dplyr)
    df %>% 
        group_by(family) %>%
        mutate_at(vars(starts_with('datacol')), list(`2` = 
               ~if(n() == 1) NA_integer_ else rev(.)))
    # A tibble: 5 x 7
    # Groups:   family [3]
    #     id family  twin datacol1 datacol2 datacol1_2 datacol2_2
    #  <int> <chr>  <dbl>    <int>    <int>      <int>      <int>
    #1     1 a          1       11       21         12         22
    #2     2 a          2       12       22         11         21
    #3     3 b          1       13       23         14         24
    #4     4 b          2       14       24         13         23
    #5     5 c          1       15       25         NA         NA
    

    【讨论】:

    • 昨晚我也在研究同样的方法。但我无法弄清楚那个列表部分。你时不时遇到这种情况吗?
    • @jazzurro 在这种情况下,当组的行数为 1 时,OP 希望它为 NA。但是,在某些情况下,您想按组获取值的sum,如果它们都是NA,如果我们使用na.rm = TRUE,它会返回0。如果OP希望它是NA ,然后我们做if(all(is.na(.))) NA_real_ else sum(., na.rm = TRUE)
    【解决方案2】:
    cols = c("datacol1", "datacol2")
    df %>%
        group_by(family) %>%
        mutate_at(vars(cols), function(x){
            if (n() == 2){
                rev(x)
            } else {
                NA
            }
        }) %>%
        ungroup() %>%
        select(cols) %>%
        rename_all(funs(paste0(., ".b"))) %>%
        cbind(df, .)
    

    基础R

    cols = c("datacol1", "datacol2")
    do.call(rbind, lapply(split(df, df$family), function(x){
        cbind(x, setNames(lapply(x[cols], function(y) {
            if (length(y) == 2) {
                rev(y)
            } else {
                NA
            }}),
            paste0(cols, ".b")))
    }))
    

    【讨论】:

      猜你喜欢
      • 2010-09-28
      • 2013-04-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-03
      • 1970-01-01
      • 2018-10-02
      • 1970-01-01
      • 2019-04-29
      相关资源
      最近更新 更多