R:如何自动为值序列创建标志变量?

  • 本文关键字:创建 标志 变量 何自动 r
  • 更新时间 :
  • 英文 :


假设您获得以下数据帧:

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.numerictable函数来做到这一点),然后这只是将观察到的计数映射到一个表中的问题,该表还包括我们没有观察到的那些。

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