有条件地将嵌套(字符)列表中的 sorting/mutating 项放入 R 中的新列中
Conditionally sorting/mutating items from nested (character) lists into new columns in R
我有以下根据问卷创建的数据框:
id <- c(1, 2, 3, 4, 5)
type <- c("1,2,3", "2", "2,3,4", "4", "1")
ex_df <- data.frame(id, type, stringsAsFactors=F)
ex_df$type
是class字,每个数字代表一种棋子:
1 = pawn
2 = rook
3 = knight
4 = bishop
我想根据 ex_df$type
列中的字符为每种类型的棋子创建一个单独的列,指示 present/not 存在,其中 1
表示棋子是在列表中,0
它不在列表中。
最终数据框应如下所示:
'data.frame': 5 obs. of 6 variables:
$ id : num 1 2 3 4 5
$ type : chr "1,2,3" "2" "2,3,4" "4" ...
$ pawn : num 1 0 0 0 1
$ rook : num 1 1 1 0 0
$ knight: num 1 0 1 0 0
$ bishop: num 0 0 1 1 0
在table形式中:
id type pawn rook knight bishop
1 1,2,3 1 1 1 0
2 2 0 1 0 0
3 2,3,4 0 1 1 1
4 4 0 0 0 1
5 1 1 0 0 0
到目前为止,我尝试使用 strsplit()
将 ex_df$type
转换为包含数值的列表,然后将嵌套的 lapply()
与 dplyr 的 mutate()
结合使用 when_case()
但这没有用。我在使用嵌套列表时遇到问题,所以我的方法可能不正确?
我在发布之前进行了彻底的搜索,但感觉我在这里遗漏了一些非常明显的东西,比如我不知道的函数正是这样做的。也许我没有在正确的方向寻找解决方案?
我们可以使用 splitstackshape
中的 cSplit_e
在 type
中创建逗号分隔值的二进制表示,然后更改列名。
output <- splitstackshape::cSplit_e(ex_df, "type", type = "character", fill = 0)
names(output)[-c(1, 2)] <- c('pawn', 'rook', 'knight', 'bishop')
output
# id type pawn rook knight bishop
#1 1 1,2,3 1 1 1 0
#2 2 2 0 1 0 0
#3 3 2,3,4 0 1 1 1
#4 4 4 0 0 0 1
#5 5 1 1 0 0 0
我们可以使用tidyverse
来做到这一点
library(dplyr)
library(tidyr)
ex_df %>%
separate_rows(type, convert = TRUE) %>%
mutate(type = c('pawn', 'rook', 'knight', 'bishop')[type], n = 1) %>%
pivot_wider(names_from = type, values_from = n, values_fill = list(n = 0)) %>%
left_join(ex_df)%>%
select(names(ex_df), everything())
# id type pawn rook knight bishop
#1 1 1,2,3 1 1 1 0
#2 2 2 0 1 0 0
#3 3 2,3,4 0 1 1 1
#4 4 4 0 0 0 1
#5 5 1 1 0 0 0
我有以下根据问卷创建的数据框:
id <- c(1, 2, 3, 4, 5)
type <- c("1,2,3", "2", "2,3,4", "4", "1")
ex_df <- data.frame(id, type, stringsAsFactors=F)
ex_df$type
是class字,每个数字代表一种棋子:
1 = pawn
2 = rook
3 = knight
4 = bishop
我想根据 ex_df$type
列中的字符为每种类型的棋子创建一个单独的列,指示 present/not 存在,其中 1
表示棋子是在列表中,0
它不在列表中。
最终数据框应如下所示:
'data.frame': 5 obs. of 6 variables:
$ id : num 1 2 3 4 5
$ type : chr "1,2,3" "2" "2,3,4" "4" ...
$ pawn : num 1 0 0 0 1
$ rook : num 1 1 1 0 0
$ knight: num 1 0 1 0 0
$ bishop: num 0 0 1 1 0
在table形式中:
id type pawn rook knight bishop
1 1,2,3 1 1 1 0
2 2 0 1 0 0
3 2,3,4 0 1 1 1
4 4 0 0 0 1
5 1 1 0 0 0
到目前为止,我尝试使用 strsplit()
将 ex_df$type
转换为包含数值的列表,然后将嵌套的 lapply()
与 dplyr 的 mutate()
结合使用 when_case()
但这没有用。我在使用嵌套列表时遇到问题,所以我的方法可能不正确?
我在发布之前进行了彻底的搜索,但感觉我在这里遗漏了一些非常明显的东西,比如我不知道的函数正是这样做的。也许我没有在正确的方向寻找解决方案?
我们可以使用 splitstackshape
中的 cSplit_e
在 type
中创建逗号分隔值的二进制表示,然后更改列名。
output <- splitstackshape::cSplit_e(ex_df, "type", type = "character", fill = 0)
names(output)[-c(1, 2)] <- c('pawn', 'rook', 'knight', 'bishop')
output
# id type pawn rook knight bishop
#1 1 1,2,3 1 1 1 0
#2 2 2 0 1 0 0
#3 3 2,3,4 0 1 1 1
#4 4 4 0 0 0 1
#5 5 1 1 0 0 0
我们可以使用tidyverse
来做到这一点
library(dplyr)
library(tidyr)
ex_df %>%
separate_rows(type, convert = TRUE) %>%
mutate(type = c('pawn', 'rook', 'knight', 'bishop')[type], n = 1) %>%
pivot_wider(names_from = type, values_from = n, values_fill = list(n = 0)) %>%
left_join(ex_df)%>%
select(names(ex_df), everything())
# id type pawn rook knight bishop
#1 1 1,2,3 1 1 1 0
#2 2 2 0 1 0 0
#3 3 2,3,4 0 1 1 1
#4 4 4 0 0 0 1
#5 5 1 1 0 0 0