所以当我第一次阅读问题(上一个编辑)时,我认为您想要计数列(而不是是否包含字符串),但无论如何它都是有用的代码,所以我留下了它。以下是基本 R 和 stringr 包的选项:
首先让我们制作一个具有相似数据的示例 data.frame
# stringsAsFactors = FALSE would be smart here, but let's not assume...
df <- data.frame(x = c('a, b, c, a', 'b, b, c', 'd, a'))
看起来像
> df
x
1 a, b, c, a
2 b, b, c
3 d, a
基础 R
使用strsplit 来制作分离字符串的向量列表,使用as.character 将因子强制转换为有用的形式,
list <- strsplit(as.character(df$x), ', ')
然后制作一个唯一字符串列表
lvls <- unique(unlist(list))
制作包含列
使用sapply 循环遍历data.frame/list 的行。 (此答案中的所有sapply 函数都可以替换为for 循环,但出于速度原因,这通常被认为是R 中的不良风格。)测试每个字符串中是否存在唯一字符串,然后更改为整数格式。将结果 (transposed) 设置为 df 的新列,每个唯一字符串对应一个。
df[, lvls] <- t(sapply(1:nrow(df), function(z){as.integer(lvls %in% list[[z]])}))
> df
x a b c d
1 a, b, c, a 1 1 1 0
2 b, b, c 0 1 1 0
3 d, a 1 0 0 1
要将值保留为布尔值 TRUE/FALSE 而不是整数,只需删除 as.integer。
制作计数列
使用外部sapply 循环遍历data.frame/list 的行,而内部循环遍历每个行中的唯一字符串,并通过对TRUE 值求和来计算出现次数。将结果 (transposed) 设置为 df 的新列,每个唯一字符串对应一个。
df[, lvls] <- t(sapply(1:nrow(df), function(z){
sapply(seq_along(lvls), function(y){sum(lvls[y] == list[[z]])})
}))
> df
x a b c d
1 a, b, c, a 2 1 1 0
2 b, b, c 0 2 1 0
3 d, a 1 0 0 1
stringr
stringr 可以让这些任务变得更加简单。
首先,在df$x 中找到唯一的字符串。用str_split 拆分字符串(可以取一个因子),用unlist 将它们展平成一个向量,然后找到唯一的:
library(stringr)
lvls <- unique(unlist(str_split(df$x, ', ')))
制作包含列
str_detect 允许我们只遍历唯一的字符串,而不是行:
df[, lvls] <- sapply(lvls, function(y){as.integer(str_detect(df$x, y))})
制作计数列
str_count 大大简化了我们的语法,再次只循环lvls:
df[,lvls] <- sapply(lvls, function(y){str_count(df$x, y)})
两者的结果与上述基数 R 中的结果相同。