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

时间:2018-03-20 18:19:18

标签: r

假设您已获得以下数据框:

a <- data.frame(var = c(",1,2,3,", ",2,3,5,", ",1,3,5,5,"))

我正在寻找的是在a中创建变量flag_1,...,flag_7,其中包含各个值出现次数的信息。对于a,我希望得到以下结果:

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条件获得结果,但必须有更好的(更美观和更好的)解决方案。

3 个答案:

答案 0 :(得分:3)

一个选项是strsplittable,然后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

答案 1 :(得分:1)

首先,不要将字符串变成因子。没有什么好处。

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

完成。

答案 2 :(得分:0)

将值拆分并取消列入具有适当级别的因子

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