将字符列拆分为多个二进制 (0/1) 列
Split character column into several binary (0/1) columns
我有一个这样的字符向量:
a <- c("a,b,c", "a,b", "a,b,c,d")
我想做的是创建一个数据框,其中每个字符串中的单个字母由虚拟列表示:
a b c d
1] 1 1 1 0
2] 1 1 0 0
3] 1 1 1 1
我觉得我需要使用 read.table
和 reshape
的某种组合,但我真的很挣扎。任何帮助表示赞赏。
您可以尝试 cSplit_e
来自我的 "splitstackshape" 包:
library(splitstackshape)
a <- c("a,b,c", "a,b", "a,b,c,d")
cSplit_e(as.data.table(a), "a", ",", type = "character", fill = 0)
# a a_a a_b a_c a_d
# 1: a,b,c 1 1 1 0
# 2: a,b 1 1 0 0
# 3: a,b,c,d 1 1 1 1
cSplit_e(as.data.table(a), "a", ",", type = "character", fill = 0, drop = TRUE)
# a_a a_b a_c a_d
# 1: 1 1 1 0
# 2: 1 1 0 0
# 3: 1 1 1 1
还有 mtabulate
来自 "qdapTools":
library(qdapTools)
mtabulate(strsplit(a, ","))
# a b c d
# 1 1 1 1 0
# 2 1 1 0 0
# 3 1 1 1 1
一个非常直接的基础 R 方法是使用 table
以及 stack
和 strsplit
:
table(rev(stack(setNames(strsplit(a, ",", TRUE), seq_along(a)))))
# values
# ind a b c d
# 1 1 1 1 0
# 2 1 1 0 0
# 3 1 1 1 1
一个基础 R
- 但更长的解决方案:
el = unique(unlist(strsplit(a, ',')))
do.call(rbind, lapply(a, function(u) setNames(el %in% strsplit(u,',')[[1]]+0L, el))
# a b c d
#[1,] 1 1 1 0
#[2,] 1 1 0 0
#[3,] 1 1 1 1
另一个复杂的 base-R 解决方案:
x <- strsplit(a,",")
xl <- unique(unlist(x))
t(sapply(x,function(z)table(factor(z,levels=xl))))
这给出了
a b c d
[1,] 1 1 1 0
[2,] 1 1 0 0
[3,] 1 1 1 1
另一个选项是 tstrsplit()
来自 data.table:
library(data.table)
vapply(tstrsplit(a, ",", fixed = TRUE, fill = 0), ">", integer(length(a)), 0L)
# [,1] [,2] [,3] [,4]
# [1,] 1 1 1 0
# [2,] 1 1 0 0
# [3,] 1 1 1 1
在我写完这篇文章后,我注意到 Beauvel 上校的解决方案非常相似,但也许这足以成为一个单独的解决方案。没有使用包。
首先,我们将字符串拆分为一个向量列表,L
,然后计算它们的并集,u
。最后,我们为每个列表元素确定一个二进制向量并将它们 rbind
放在一起,使用 + 0
将结果从逻辑值转换为数字值并设置列名。
L <- strsplit(a, ",")
u <- Reduce(union, L)
m <- do.call(rbind, lapply(L, `%in%`, x = u)) + 0
colnames(m) <- u
给予:
> m
a b c d
[1,] 1 1 1 0
[2,] 1 1 0 0
[3,] 1 1 1 1
已添加 最后两行代码可以替换为以下任一代码:
do.call(rbind, lapply(lapply(L, factor, levels = u), table))
do.call(rbind, Map(function(x) sapply(u, `%in%`, x), L)) + 0
遗憾的是,base R 不提供矢量化字符串匹配功能,但 stringi
包提供。
library(stringi)
a=c("a,b,c", "a,b", "a,b,c,d")
1*outer(a,unique(unlist(strsplit(a,","))),stri_detect_regex)
# [,1] [,2] [,3] [,4]
#[1,] 1 1 1 0
#[2,] 1 1 0 0
#[3,] 1 1 1 1
我在 fastDummies
中使用 dummy_cols
取得了很多成功,它可以相当简单地解决这个问题,并且可以通过变量指定。
library(fastDummies)
a <- c("a,b,c", "a,b", "a,b,c,d")
a <- dummy_cols(a, split = ",")
产出
# .data .data_a .data_b .data_c .data_d
# 1 a,b,c 1 1 1 0
# 2 a,b 1 1 0 0
# 3 a,b,c,d 1 1 1 1
我有一个这样的字符向量:
a <- c("a,b,c", "a,b", "a,b,c,d")
我想做的是创建一个数据框,其中每个字符串中的单个字母由虚拟列表示:
a b c d
1] 1 1 1 0
2] 1 1 0 0
3] 1 1 1 1
我觉得我需要使用 read.table
和 reshape
的某种组合,但我真的很挣扎。任何帮助表示赞赏。
您可以尝试 cSplit_e
来自我的 "splitstackshape" 包:
library(splitstackshape)
a <- c("a,b,c", "a,b", "a,b,c,d")
cSplit_e(as.data.table(a), "a", ",", type = "character", fill = 0)
# a a_a a_b a_c a_d
# 1: a,b,c 1 1 1 0
# 2: a,b 1 1 0 0
# 3: a,b,c,d 1 1 1 1
cSplit_e(as.data.table(a), "a", ",", type = "character", fill = 0, drop = TRUE)
# a_a a_b a_c a_d
# 1: 1 1 1 0
# 2: 1 1 0 0
# 3: 1 1 1 1
还有 mtabulate
来自 "qdapTools":
library(qdapTools)
mtabulate(strsplit(a, ","))
# a b c d
# 1 1 1 1 0
# 2 1 1 0 0
# 3 1 1 1 1
一个非常直接的基础 R 方法是使用 table
以及 stack
和 strsplit
:
table(rev(stack(setNames(strsplit(a, ",", TRUE), seq_along(a)))))
# values
# ind a b c d
# 1 1 1 1 0
# 2 1 1 0 0
# 3 1 1 1 1
一个基础 R
- 但更长的解决方案:
el = unique(unlist(strsplit(a, ',')))
do.call(rbind, lapply(a, function(u) setNames(el %in% strsplit(u,',')[[1]]+0L, el))
# a b c d
#[1,] 1 1 1 0
#[2,] 1 1 0 0
#[3,] 1 1 1 1
另一个复杂的 base-R 解决方案:
x <- strsplit(a,",")
xl <- unique(unlist(x))
t(sapply(x,function(z)table(factor(z,levels=xl))))
这给出了
a b c d
[1,] 1 1 1 0
[2,] 1 1 0 0
[3,] 1 1 1 1
另一个选项是 tstrsplit()
来自 data.table:
library(data.table)
vapply(tstrsplit(a, ",", fixed = TRUE, fill = 0), ">", integer(length(a)), 0L)
# [,1] [,2] [,3] [,4]
# [1,] 1 1 1 0
# [2,] 1 1 0 0
# [3,] 1 1 1 1
在我写完这篇文章后,我注意到 Beauvel 上校的解决方案非常相似,但也许这足以成为一个单独的解决方案。没有使用包。
首先,我们将字符串拆分为一个向量列表,L
,然后计算它们的并集,u
。最后,我们为每个列表元素确定一个二进制向量并将它们 rbind
放在一起,使用 + 0
将结果从逻辑值转换为数字值并设置列名。
L <- strsplit(a, ",")
u <- Reduce(union, L)
m <- do.call(rbind, lapply(L, `%in%`, x = u)) + 0
colnames(m) <- u
给予:
> m
a b c d
[1,] 1 1 1 0
[2,] 1 1 0 0
[3,] 1 1 1 1
已添加 最后两行代码可以替换为以下任一代码:
do.call(rbind, lapply(lapply(L, factor, levels = u), table))
do.call(rbind, Map(function(x) sapply(u, `%in%`, x), L)) + 0
遗憾的是,base R 不提供矢量化字符串匹配功能,但 stringi
包提供。
library(stringi)
a=c("a,b,c", "a,b", "a,b,c,d")
1*outer(a,unique(unlist(strsplit(a,","))),stri_detect_regex)
# [,1] [,2] [,3] [,4]
#[1,] 1 1 1 0
#[2,] 1 1 0 0
#[3,] 1 1 1 1
我在 fastDummies
中使用 dummy_cols
取得了很多成功,它可以相当简单地解决这个问题,并且可以通过变量指定。
library(fastDummies)
a <- c("a,b,c", "a,b", "a,b,c,d")
a <- dummy_cols(a, split = ",")
产出
# .data .data_a .data_b .data_c .data_d
# 1 a,b,c 1 1 1 0
# 2 a,b 1 1 0 0
# 3 a,b,c,d 1 1 1 1