【问题标题】:reshape dataframe efficiently with dplyr in r [duplicate]在 r [重复] 中使用 dplyr 有效地重塑数据帧
【发布时间】:2020-11-23 14:24:34
【问题描述】:

我有一个这样的数据框。

id = letters[1:5]
items = c('A,B,C,D,E',
          'C,D,E,A,B',
          'E,D,C',
          'B,A',
          'A')
dat = tibble(id = id, items =items)

> dat
# A tibble: 5 x 2
  id    items    
  <chr> <chr>    
1 a     A,B,C,D,E
2 b     C,D,E,A,B
3 c     E,D,C    
4 d     B,A      
5 e     A     

我想将items 拆分成小块,让其他变量替换它们(var A 到 var B)。

我想要什么dat 格式:

final.dat = tibble(
  id = id,
  A  = c(1, 1, 0, 1, 1),
  B  = c(1, 1, 0, 1, 0),
  C  = c(1, 1, 1, 0 ,0),
  D  = c(1, 1, 1, 0, 0),
  E  = c(1, 1, 1, 0, 0)
)

> final.dat
# A tibble: 5 x 6
  id        A     B     C     D     E
  <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
1 a         1     1     1     1     1
2 b         1     1     1     1     1
3 c         0     0     1     1     1
4 d         1     1     0     0     0
5 e         1     0     0     0     0

这是我的代码,但我认为它是多余的。

我的代码中还有一个BUG:当我用map(as.data.frame)替换map(as_tibble)时,值全是NA

有没有更有效的方法来做到这一点?

任何帮助将不胜感激!

# get id
id = dat[,1]

# reshape items
items <- dat[,2]

# function that let the first row to colnames and then add a row that all value is 1. Finally, remove the first row
make.title <- function(data){
  row.1 <- unlist(slice(data, 1))
  colnames(data) <- row.1
  data <- rbind(data, rep(1, ncol(data)))
  data <- slice(data, -1)
  data
}

# final.dat.2 is what I wanted
final.dat.2 <-  
  split(items, seq(nrow(items))) %>% 
  map(unlist) %>% 
  map(~str_split(., pattern = ',')) %>% 
  map(unlist) %>% 
  map(rbind) %>% 
  map(as_tibble) %>% 
  map(make.title) %>% 
  bind_rows() %>% 
  transmute(across(.cols = everything(), ~replace_na(., 0))) %>% 
  bind_cols(id)

# bug occur
final.dat.3 <-  
  split(items, seq(nrow(items))) %>% 
  map(unlist) %>% 
  map(~str_split(., pattern = ',')) %>% 
  map(unlist) %>% 
  map(rbind) %>% 
  map(as.data.frame) %>%  # as dataframe
  map(make.title) %>% 
  bind_rows() %>% 
  transmute(across(.cols = everything(), ~replace_na(., 0))) %>% 
  bind_cols(id)

【问题讨论】:

  • splitstackshape package 对此类任务有很大帮助。
  • 正如@markus 提到的,您可以使用“splitstackshape”包——特别是cSplit_e。像dat %&gt;% cSplit_e("items", ",", type = "character", fill = 0, drop = TRUE) %&gt;% tibble() 这样的东西应该可以工作。

标签: r dataframe dplyr tidyverse


【解决方案1】:

试试这个。您可以使用tidyverse 中的separate_rows()pivot_wider() 来达到预期的输出:

library(dplyr)
library(tidyr)
#Code
newdf <- dat %>% separate_rows(items,sep=',') %>%
  mutate(Val=1) %>%
  pivot_wider(names_from = items,values_from=Val,values_fill=0)

输出:

# A tibble: 5 x 6
  id        A     B     C     D     E
  <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
1 a         1     1     1     1     1
2 b         1     1     1     1     1
3 c         0     0     1     1     1
4 d         1     1     0     0     0
5 e         1     0     0     0     0

【讨论】:

    【解决方案2】:

    我们也可以

    library(dplyr)
    library(tidyr)
    df %>%
       mutate(items = strsplit(items, ",")) %>%
      unnest(c(items)) %>%
      mutate(Val = 1) %>%
      pivot_wider(names_from = items, values_from = Val, values_fill = 0)
    

    或者mtabulate的选项

    library(qdapTools)
    cbind(dat['id'], mtabulate(strsplit(dat$items, ",")))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-02-05
      • 2018-05-07
      • 1970-01-01
      • 2017-04-05
      • 2011-12-22
      • 1970-01-01
      • 2010-12-04
      相关资源
      最近更新 更多