【问题标题】:R: complete/expand a dataset with a new column addedR:完成/扩展数据集并添加新列
【发布时间】:2021-10-25 18:59:37
【问题描述】:

我有一个如下所示的数据集:

(可视化下面的数据集可能有助于您理解问题)

original <- data.frame(
  ID = c(rep("John", 3), "Steve"),
  A = c(rep(3, 3), 1),
  B = c(rep(4, 3), 2),
  b = c(2, 3, 2, 2),
  detail = c(rep("GOOOOD", 4))
)

变量ABb 中的值都是整数。变量b 在这个数据集中是不完整的,它实际上有从1 到B 的值。

我需要添加一个新变量a 来完成这个数据集,完成的数据集将如下所示:

completed1 <- data.frame(
  ID = c(rep("John", 12), rep("Steve", 2)),
  A = c(rep(3, 12), rep(1, 2)),
  a = c(rep(1, 4), rep(2, 4), rep(3, 4), rep(1, 2)),
  B = c(rep(4, 12), rep(2, 2)),
  b = c(rep(1:4, 3), 1, 2),
  detail = c(NA, "GOOOOD", "GOOOOD", NA, NA, "GOOOOD", rep(NA, 7), "GOOOOD")
)

变量a 中的值也是整数,a 的值从 1 到 A 的值。 b 中的值嵌套在a 的每个值中,a 中的值嵌套在ID 的每个因子中。

我认为以这种方式完成数据集最相关的函数是tidyr::complete()tidyr::expand(),但它们只能完成现有变量中的值组合,不能添加新列(变量)。

我知道挑战在于有多个位置可以在 detail 对应于新添加的值 a 通过嵌套关系,例如完成的数据集也可以是这样的:

completed2 <- data.frame(
  ID = c(rep("John", 12), rep("Steve", 2)),
  A = c(rep(3, 12), rep(1, 2)),
  a = c(rep(1, 4), rep(2, 4), rep(3, 4), rep(1, 2)),
  B = c(rep(4, 12), rep(2, 2)),
  b = c(rep(1:4, 3), 1, 2),
  detail = c(NA, "GOOOOD", rep(NA, 4), "GOOOOD", NA, NA, "GOOOOD", rep(NA, 3), "GOOOOD")
)

detail 中的值在完整数据集中的位置对我来说并不重要。我的实际数据集有超过 40,000 行,所以我真的需要一些东西来自动化它。

可以这样做吗? 非常感谢!!!

【问题讨论】:

    标签: r dataset


    【解决方案1】:

    使用for 循环非常混乱,它会给出GOOOOD 的非常随机的位置

    comp_dummy <- original %>%
      group_by(ID) %>%
      expand(A = A, a = 1:A, B = B, b = 1:B)
    
    original <- original %>%
      group_by(ID, A, B, b) %>%
      summarise(n = n())
    
    vec <- rep(NA_character_, nrow(comp_dummy))
    
    for (i in 1:nrow(original)){
      x <- original[i,]
      
      y <- comp_dummy %>%
        rownames_to_column(., "row") %>%
        filter(ID == x$ID, A == x$A, B == x$B, b == x$b)  %>%
        pull(row)
      z <- sample(y, x$n, replace = FALSE)  %>% as.numeric()
      print(z)
      vec[{z}] <- "GOOOOD"
    }
    
    comp_dummy$detail <- vec
    comp_dummy
    
       ID        A     a     B     b detail
       <chr> <dbl> <int> <dbl> <int> <chr> 
     1 John      3     1     4     1 NA    
     2 John      3     1     4     2 GOOOOD
     3 John      3     1     4     3 NA    
     4 John      3     1     4     4 NA    
     5 John      3     2     4     1 NA    
     6 John      3     2     4     2 NA    
     7 John      3     2     4     3 NA    
     8 John      3     2     4     4 NA    
     9 John      3     3     4     1 NA    
    10 John      3     3     4     2 GOOOOD
    11 John      3     3     4     3 GOOOOD
    12 John      3     3     4     4 NA    
    13 Steve     1     1     2     1 NA    
    14 Steve     1     1     2     2 GOOOOD
    

    【讨论】:

    • 这确实符合我在问题中提出的要求,所以我接受了这个答案。事实上,我过度简化了我的数据集,并且循环在我的实际数据集上不起作用(当打印值达到 3,000,000 时出现错误,我认为实际数据集太大了)。我编辑了问题并重新发布,看看你有没有兴趣:stackoverflow.com/questions/69732688/…
    • @JuanW814 我看了一下并添加了答案。
    【解决方案2】:

    我想知道是否执行两次complete,首先是a,然后是b 可以是一个解决方案。您可以调整不同的嵌套,如果需要,可以group_by

    根据a 的最大值是否来自ID 组内的A,您应调整/删除group_by(类似于a 组内的b

    library(dplyr)
    library(tidyr)
    
    original %>%
      dplyr::mutate(a = 1) %>%
      dplyr::group_by( ID ) %>%
      tidyr::complete( a = 1:max(A), nesting(ID, A, B, b), fill = list( detail = NA_character_)) %>%
      group_by( a ) %>%
      tidyr::complete( b = 1:max(B), nesting(ID, A, B, a), fill = list( detail = NA_character_)) %>%
      dplyr::ungroup()
    

    【讨论】:

    • 谢谢,但这会将Steve 下的b 中的级别从2 增加到4,这是不可能的。其实我把数据集简化了,所以我把问题编辑了一遍,看看你有没有兴趣:stackoverflow.com/questions/69732688/…
    • 然后只需执行group_by( ID, a ) 并从第二个nesting 中删除ID。使用group_by,您可以指定嵌套模式。那么Steve 只会出现两次。
    【解决方案3】:

    基本 R 解决方案

    do.call(
      rbind,
      by(original,list(original$ID),function(x){
        tmp=merge(
          unique(x),
          setNames(
            expand.grid(
              unique(x$ID),
              x$A[1],
              1:max(x$A),
              x$B[1],
              1:max(x$B)
            ),
            c("ID","A","a","B","b")
          ),
          by=c("ID","A","B","b"),
          all=T
        )
        tmp[order(tmp$a,tmp$b),c("ID","A","a","B","b","detail")]
      })
    )
    

    导致

               ID A a B b detail
    John.1   John 3 1 4 1   <NA>
    John.5   John 3 1 4 2 GOOOOD
    John.8   John 3 1 4 3 GOOOOD
    John.11  John 3 1 4 4   <NA>
    John.2   John 3 2 4 1   <NA>
    John.4   John 3 2 4 2 GOOOOD
    John.9   John 3 2 4 3 GOOOOD
    John.12  John 3 2 4 4   <NA>
    John.3   John 3 3 4 1   <NA>
    John.6   John 3 3 4 2 GOOOOD
    John.7   John 3 3 4 3 GOOOOD
    John.10  John 3 3 4 4   <NA>
    Steve.1 Steve 1 1 2 1   <NA>
    Steve.2 Steve 1 1 2 2 GOOOOD
    

    【讨论】:

    • 谢谢,但我不能在detail 中复制值!其实我在这个问题中把我的数据集过度简化了,所以我把问题编辑了一遍再贴出来,看看你有没有兴趣:stackoverflow.com/questions/69732688/…
    猜你喜欢
    • 2021-12-12
    • 2019-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-09
    • 2021-07-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多