R: Spread data.frame/tibble 使用共享密钥和缺失数据

R: Spread data.frame/tibble with shared keys and missing data

我有一个两栏 table,我想展开。我知道这是一个非常受欢迎且经过充分探索的主题,但是,我尝试了几种方法但没有得到我想要的。欢迎任何建议和投诉。

我的table里面装满了三个女人的数据。总共有 5 个类别,一般来说,每个类别都充满了价值。但是一些女性的数据缺失,导致整行缺失的原因 - 请注意 Jane 缺失有关 weight 的信息。

a = data.frame(categories = c("name", "sex", "age", "weight", "high", 
                              "name", "sex", "age", "high", 
                              "name", "sex", "age", "weight", "high"),
               values = c("Emma", "female", "32", "72", "175",
                          "Jane", "female", "28", "165",
                          "Emma", "female", "42", "63", "170")) 

   categories values
1        name   Emma
2         sex   female
3         age     32
4      weight     72
5        high    175
6        name   Jane
7         sex female
8         age     28
9        high    165
10       name   Emma
11        sex female
12        age     42
13     weight     63
14       high    170

我想从 categories - 列和 values - 行中获取。但是主要有两个问题:

1) 密钥是共享的 - 两个 Emmas(因此我不能使用 spreadreshape

2) 某些类别可能会丢失 - 例如 Jane 的体重(因此我不能使用 pivotsplit

最后,我想重塑数据以获得这样的 table:

     name  sex    age  weight  high
     Emma  female 32   72      175
     Jane  female 28   NA      165
     Emma  female 42   63      170

假设每个条目始终存在 'name',我们可以创建一个标识符列并使用 pivot_wider 进行整形。

library(dplyr)

a %>%
  group_by(grp = cumsum(categories == 'name')) %>%
  tidyr::pivot_wider(names_from = categories, values_from = values) %>%
  ungroup %>%
  select(-grp)

#  name  sex    age   weight high 
#  <chr> <chr>  <chr> <chr>  <chr>
#1 Emma  female 32    72     175  
#2 Jane  female 28    NA     165  
#3 Emma  female 42    63     170  

data.table 中的相同逻辑:

library(data.table)
dcast(setDT(a), cumsum(categories == 'name')~categories, value.var = 'values')

假设所有条目都以 name 开头,并在基数 R 中使用 magrittr 进行清洁:

library(magrittr)
split(a, cumsum(a$categories == "name")) %>% 
  lapply(function(x) setNames(x[[2L]], x[[1L]])[unique(a$categories)]) %>% 
  do.call(rbind, .) %>% 
  data.frame()

  name    sex age weight high
1 Emma female  32     72  175
2 Jane female  28   <NA>  165
3 Emma female  42     63  170

同样玩 data.table:

library(data.table)
split(a, cumsum(a$categories == "name")) %>% 
  lapply(transpose, make.names = "categories") %>% 
  rbindlist(fill = TRUE)