假设您获得以下数据帧:
a <- data.frame(var = c(",1,2,3,", ",2,3,5,", ",1,3,5,5,"))
我正在寻找的是创建变量flag_1,...,flag_7,其中包含相应值出现次数的信息。对于论坛,我期望以下结果:
var flag_1 flag_2 flag_3 flag_4 flag_5
",1,2,3," 1. 1. 1. 0. 0.
",2,3,5," 0. 1. 1. 0. 1.
",1,3,5,5," 1. 0. 1. 0. 2.
我设法使用嵌套的for循环和if条件来获得结果,但必须有一个更好(更美观,性能更好的)解决方案。
一种选择是执行strsplit
,获取table
,然后使用原始数据cbind
cbind(a, do.call(rbind, lapply(strsplit(as.character(a$var), ","),
function(x) table(factor(x[nzchar(x)], levels = 1:5, labels = paste0("flag_", 1:5))))))
# var flag_1 flag_2 flag_3 flag_4 flag_5
#1 ,1,2,3, 1 1 1 0 0
#2 ,2,3,5, 0 1 1 0 1
#3 ,1,3,5,5, 1 0 1 0 2
另一种选择是使用tidyverse
library(tidyverse)
str_extract_all(a$var, "[0-9]") %>%
map(~ as.integer(.x) %>%
as_tibble) %>%
bind_rows(.id = 'grp') %>%
count(grp, value = factor(value, levels = min(value):max(value))) %>%
spread(value, n, drop = FALSE, fill = 0) %>%
select(-grp) %>%
bind_cols(a, .) %>%
rename_at(vars(matches("^[0-9]+$")), ~ paste0("flag_", .))
# var flag_1 flag_2 flag_3 flag_4 flag_5
#1 ,1,2,3, 1 1 1 0 0
#2 ,2,3,5, 0 1 1 0 1
#3 ,1,3,5,5, 1 0 1 0 2
首先,不要将字符串变成因子。这没有什么好处。
a <- data.frame(var = c(",1,2,3,", ",2,3,5,", ",1,3,5,5,"),
stringsAsFactors = FALSE)
如果我们分小步从字符串到您的表非常简单。在这里,我为每个步骤编写(或重命名)一个函数,然后一次使用lapply
一个完成这些步骤。如果需要,可以在管道中将它们全部串在一起,但大致是这些步骤。
首先,我从字符串中提取数字。这涉及在逗号上拆分,摆脱空字符串,你有这些,因为你可以用逗号开始和结束字符串,但除此之外,该步骤就没有必要了。然后我们需要将字符串转换为数字,计算我们看到每个字符串的频率(我们可以分别使用as.numeric
和table
函数来做到这一点),然后这只是将观察到的计数映射到一个表中的问题,该表还包括我们没有观察到的那些。
pick_indices <- function(str) unlist(strsplit(str, split = ","))
remove_empty <- function(chrs) chrs[nchar(chrs) > 0]
get_indices <- as.numeric
to_counts <- table
to_flag_vect <- function(counts, len) {
vec <- rep(0, len)
names(vec) <- 1:len
vec[names(counts)] <- counts
vec
}
strings <- lapply(a$var, pick_indices)
cleaned <- lapply(strings, remove_empty)
indices <- lapply(cleaned, get_indices)
counts <- lapply(indices, to_counts)
flags <- lapply(counts, to_flag_vect, len = 5)
我们现在在一个列表中有标志计数,所以要使用你想要的列名进入你想要的表,我们只需这样做:
tbl <- do.call(rbind, flags)
colnames(tbl) <- paste0("flag_", 1:5)
tbl
做。
将值拆分并取消列出为具有适当水平的因子
x = strsplit(a$var, ",")
xp = factor(unlist(x), levels = seq_len(5))
创建一个索引,将xp
的值映射到它们来自的行
i = rep(seq_along(x), lengths(x))
使用xtabs()
按行交叉制表条目
xt = xtabs(~ i + xp)
并将结果的矩阵表示cbind()
为原始结果
> cbind(a, unclass(xt))
var 1 2 3 4 5
1 ,1,2,3, 1 1 1 0 0
2 ,2,3,5, 0 1 1 0 1
3 ,1,3,5,5, 1 0 1 0 2