是否有一个 R 函数可以将一列拆分为任意数量的多个以字段命名的列?
Is there an R function that splits a column into an arbitrary number of multiple field-named columns?
例如,我有一个如下所示的数据框:
df = data.frame(x=c('a, b, c','b, c', 'd, e'))
理想情况下,我最终会得到一个如下所示的数据框:
df.transformed = data.frame(x.a = c(1,0,0),
x.b = c(1,1,0),
x.c = c(1,1,0),
x.d = c(0,0,1),
x.e = c(0,0,1))
其中 x
中每个可能的逗号分隔值都已分开。
我已经多次为这个问题编写手动解决方案,但这是我在调查数据中多次遇到的问题,让我想知道为什么它没有包含在像 tidyr
这样的包中,因为该包中的 separate
函数似乎不太有用。我希望能够在加载必要的包后在一行中执行此操作。
添加行号列,将 x
分隔成行,并在 x
中的每个元素前加上 x.
。然后 运行 table
并将其转换为数据框。如果不需要在每个名称前加上 paste
行,则可以省略;如果不需要数据框(table 即可),则可以省略最后一行。
library(dplyr)
library(tidyr)
df %>%
mutate(row = 1:n()) %>%
separate_rows(x) %>%
mutate(x = paste("x", x, sep = ".")) %>%
table %>%
as.data.frame.matrix
给予:
x.a x.b x.c x.d x.e
1 1 1 1 0 0
2 0 1 1 0 0
3 0 0 0 1 1
请注意,如果我们省略可选行,那么我们将得到:
df %>%
mutate(row = 1:n()) %>%
separate_rows(x) %>%
table
给予:
x
row a b c d e
1 1 1 1 0 0
2 0 1 1 0 0
3 0 0 0 1 1
这可以通过 qdapTools
完成,我们将 'x' 拆分为 ,
后跟零个或多个空格并使用 mtabulate
library(qdapTools)
mtabulate(strsplit(as.character(df$x), ",\s*"))
# a b c d e
#1 1 1 1 0 0
#2 0 1 1 0 0
#3 0 0 0 1 1
或者我们使用tidyverse
方法
library(tidyverse)
rownames_to_column(df, 'rn') %>% #add row names
separate_rows(x) %>% #split the rows into long format
mutate(i = 1) %>% #create a column of 1s
spread(x, i, fill = 0) %>% #spread to wide format
select(-rn) %>% #remove unnecessary columns
rename_all(funs(paste0("x.", .))) #rename if needed
# x.a x.b x.c x.d x.e
#1 1 1 1 0 0
#2 0 1 1 0 0
#3 0 0 0 1 1
注意:仅发布我的评论作为解决方案
或者另一个选项来自 base R
table
- 未使用包
table(stack(setNames(strsplit(as.character(df$x), ",\s*"), seq_len(nrow(df))))[2:1])
# values
#ind a b c d e
# 1 1 1 1 0 0
# 2 0 1 1 0 0
# 3 0 0 0 1 1
例如,我有一个如下所示的数据框:
df = data.frame(x=c('a, b, c','b, c', 'd, e'))
理想情况下,我最终会得到一个如下所示的数据框:
df.transformed = data.frame(x.a = c(1,0,0),
x.b = c(1,1,0),
x.c = c(1,1,0),
x.d = c(0,0,1),
x.e = c(0,0,1))
其中 x
中每个可能的逗号分隔值都已分开。
我已经多次为这个问题编写手动解决方案,但这是我在调查数据中多次遇到的问题,让我想知道为什么它没有包含在像 tidyr
这样的包中,因为该包中的 separate
函数似乎不太有用。我希望能够在加载必要的包后在一行中执行此操作。
添加行号列,将 x
分隔成行,并在 x
中的每个元素前加上 x.
。然后 运行 table
并将其转换为数据框。如果不需要在每个名称前加上 paste
行,则可以省略;如果不需要数据框(table 即可),则可以省略最后一行。
library(dplyr)
library(tidyr)
df %>%
mutate(row = 1:n()) %>%
separate_rows(x) %>%
mutate(x = paste("x", x, sep = ".")) %>%
table %>%
as.data.frame.matrix
给予:
x.a x.b x.c x.d x.e
1 1 1 1 0 0
2 0 1 1 0 0
3 0 0 0 1 1
请注意,如果我们省略可选行,那么我们将得到:
df %>%
mutate(row = 1:n()) %>%
separate_rows(x) %>%
table
给予:
x
row a b c d e
1 1 1 1 0 0
2 0 1 1 0 0
3 0 0 0 1 1
这可以通过 qdapTools
完成,我们将 'x' 拆分为 ,
后跟零个或多个空格并使用 mtabulate
library(qdapTools)
mtabulate(strsplit(as.character(df$x), ",\s*"))
# a b c d e
#1 1 1 1 0 0
#2 0 1 1 0 0
#3 0 0 0 1 1
或者我们使用tidyverse
方法
library(tidyverse)
rownames_to_column(df, 'rn') %>% #add row names
separate_rows(x) %>% #split the rows into long format
mutate(i = 1) %>% #create a column of 1s
spread(x, i, fill = 0) %>% #spread to wide format
select(-rn) %>% #remove unnecessary columns
rename_all(funs(paste0("x.", .))) #rename if needed
# x.a x.b x.c x.d x.e
#1 1 1 1 0 0
#2 0 1 1 0 0
#3 0 0 0 1 1
注意:仅发布我的评论作为解决方案
或者另一个选项来自 base R
table
- 未使用包
table(stack(setNames(strsplit(as.character(df$x), ",\s*"), seq_len(nrow(df))))[2:1])
# values
#ind a b c d e
# 1 1 1 1 0 0
# 2 0 1 1 0 0
# 3 0 0 0 1 1