【问题标题】:how to stratify variable by group into new variables?如何按组将变量分层为新变量?
【发布时间】:2021-02-11 20:31:06
【问题描述】:

在 R(dplyr、data.table 等)中如何去:

group   var
a   0
a   0
a   1
a   0
b   1
b   1
b   0
c   1
c   0
c   1
c   1

到:

最好是动态的,例如使用可变数量的组。

【问题讨论】:

    标签: r dplyr data.table


    【解决方案1】:

    你可以这样做:

    d <- data.frame(group=sample(LETTERS[1:4],100,TRUE), var = rnorm(100))
    
    groupInds <- split(1:NROW(d),d$group)
    
    newColumns <- do.call("cbind",lapply(1:length(groupInds), function(k) {
      newColValues <- rep(NA,NROW(d)) #some init, you left blank, so I thought of NAs
      inds <- groupInds[[k]]
      newColValues[inds] <- d$var[inds]
      data.frame(newColValues)
    }))
    names(newColumns) <- paste0(names(groupInds),"_var")
    
    newdf <- cbind(d,newColumns)
    

    它在基础 R 中的所有内容。如果您知道可以使用矩阵,则可以将强制转换为 data.frame,因为性能原因,而不是重置 names,而是使用 colnames

    【讨论】:

      【解决方案2】:

      我们可以通过'group'拆分后使用bdiag

      library(Matrix)
      m1 <- as.matrix(bdiag(split(df1$var, df1$group)))
      colnames(m1) <- paste0(unique(df1$group), "_var")
      cbind(df1, m1)
      

      -输出

      #   group var a_var b_var c_var
      #1      a   0     0     0     0
      #2      a   0     0     0     0
      #3      a   1     1     0     0
      #4      a   0     0     0     0
      #5      b   1     0     1     0
      #6      b   1     0     1     0
      #7      b   0     0     0     0
      #8      c   1     0     0     1
      #9      c   0     0     0     0
      #10     c   1     0     0     1
      #11     c   1     0     0     1
      

      为了将值“0”与稀缺矩阵中创建的值区分开来,我们可以做一些replacement

      m1 <- as.matrix(bdiag(split(na_if(df1$var, 0), df1$group)))
      i1 <- is.na(m1)
      i2 <- m1 == 0 & !is.na(m1)
      m1[i1] <- 0
      m1[i2] <- NA
      colnames(m1) <- paste0(unique(df1$group), "_var")
      cbind(df1, m1)
      #  group var a_var b_var c_var
      #1      a   0     0    NA    NA
      #2      a   0     0    NA    NA
      #3      a   1     1    NA    NA
      #4      a   0     0    NA    NA
      #5      b   1    NA     1    NA
      #6      b   1    NA     1    NA
      #7      b   0    NA     0    NA
      #8      c   1    NA    NA     1
      #9      c   0    NA    NA     0
      #10     c   1    NA    NA     1
      #11     c   1    NA    NA     1
      

      或者这可以使用tidyverse 来完成,方法是将数据拆分为带有group 列的data.frame 的list,然后重命名“var”列并使用bind_rows,这将自动添加NA如果在list 元素中找不到该列,则元素

      library(dplyr)
      library(purrr)
      library(stringr)
      df1 %>%
          group_split(group) %>% 
          map(~ .x %>% 
             rename(!! str_c(first(.x$group), '_var') := var) %>%
             select(-group)) %>%
          bind_rows %>% 
          bind_cols(df1, .)
      

      -输出

      #   group var a_var b_var c_var
      #1      a   0     0    NA    NA
      #2      a   0     0    NA    NA
      #3      a   1     1    NA    NA
      #4      a   0     0    NA    NA
      #5      b   1    NA     1    NA
      #6      b   1    NA     1    NA
      #7      b   0    NA     0    NA
      #8      c   1    NA    NA     1
      #9      c   0    NA    NA     0
      #10     c   1    NA    NA     1
      #11     c   1    NA    NA     1
      

      数据

      df1 <- structure(list(group = c("a", "a", "a", "a", "b", "b", "b", "c", 
      "c", "c", "c"), var = c(0L, 0L, 1L, 0L, 1L, 1L, 0L, 1L, 0L, 1L, 
      1L)), class = "data.frame", row.names = c(NA, -11L))
      

      【讨论】:

        【解决方案3】:

        这是“data.table”的替代方案:

        library(data.table)
        cbind(df1, as.data.table(df1)[
          , dcast(.SD, .I ~ paste0(group, "_var"), value.var = "var")][
          , ".I" := NULL])
        #    group var a_var b_var c_var
        # 1      a   0     0    NA    NA
        # 2      a   0     0    NA    NA
        # 3      a   1     1    NA    NA
        # 4      a   0     0    NA    NA
        # 5      b   1    NA     1    NA
        # 6      b   1    NA     1    NA
        # 7      b   0    NA     0    NA
        # 8      c   1    NA    NA     1
        # 9      c   0    NA    NA     0
        # 10     c   1    NA    NA     1
        # 11     c   1    NA    NA     1
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-10-30
          • 1970-01-01
          • 2022-01-17
          • 2018-05-26
          • 2016-06-16
          • 1970-01-01
          • 2020-08-31
          • 2022-11-19
          相关资源
          最近更新 更多