【发布时间】: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)
【问题讨论】:
-
splitstackshapepackage 对此类任务有很大帮助。 -
正如@markus 提到的,您可以使用“splitstackshape”包——特别是
cSplit_e。像dat %>% cSplit_e("items", ",", type = "character", fill = 0, drop = TRUE) %>% tibble()这样的东西应该可以工作。
标签: r dataframe dplyr tidyverse