创建新列以指示列名在另一个字符串向量中的位置(使用dplyr,purrr和stringr)

and*_*ece 1 r stringr dplyr purrr

鉴于此示例数据:

require(stringr)
require(tidyverse)

labels <- c("foo", "bar", "baz")
n_rows <- 4

df <- 1:n_rows %>%
  map(~ data.frame(
      block_order=paste(sample(labels, size=length(labels), replace=FALSE),
                        collapse="|"))) %>%
  bind_rows()

df
  block_order
1 foo|bar|baz
2 baz|bar|foo
3 foo|baz|bar
4 foo|bar|baz
Run Code Online (Sandbox Code Playgroud)

我想为每个字符串生成一个列labels,它|在每行的分隔序列中获取该字符串的位置值.

期望的输出:

  block_order foo bar baz
1 foo|bar|baz   1   2   3
2 baz|bar|foo   3   2   1
3 foo|baz|bar   1   3   2
4 foo|bar|baz   1   2   3
Run Code Online (Sandbox Code Playgroud)

我一直在尝试dplyr/ purrrsetup中的不同变体,比如这个例子,我map在每个值中label,然后尝试在block_order使用match时获得它的位置str_split:

labels %>%
  map(~ df %>%
        transmute(!!.x := match(!!.x, str_split(block_order, 
                                                "\\|", 
                                                simplify=TRUE)))) %>%
  bind_cols(df, .)
Run Code Online (Sandbox Code Playgroud)

但这会产生意外的输出:

  block_order foo bar baz
1 foo|bar|baz   1   5   2
2 baz|bar|foo   1   5   2
3 foo|baz|bar   1   5   2
4 foo|bar|baz   1   5   2
Run Code Online (Sandbox Code Playgroud)

我不确定这些数字代表什么,或者为什么它们都是一样的.

如果有人能帮助我弄清楚(a)如何在dplyr/ purrr框架中实现我想要的输出,以及(b)为什么这里提出的解决方案给出了它的输出,我将非常感激.

akr*_*run 5

我们可以通过分拆"的block_order" |通过,环路listvectorS使用lapply,获得与指数match,rbindvectorS和其分配给创建新列

labels <- c("foo", "bar", "baz")
df[labels] <- do.call(rbind, lapply(strsplit(df$block_order, "|",
         fixed = TRUE), match, table = labels))
Run Code Online (Sandbox Code Playgroud)

或类似的想法 tidyverse

library(tidyverse)
str_split(df$block_order, "[|]") %>%
       map(~ .x %>% 
              match(table= labels)) %>% 
      do.call(rbind, .) %>% 
      as_tibble %>% 
      set_names(labels) %>%
      bind_cols(df, .)
#   block_order foo bar baz
#1 foo|bar|baz   1   2   3
#2 baz|bar|foo   3   2   1
#3 foo|baz|bar   1   3   2
#4 foo|bar|baz   1   2   3
Run Code Online (Sandbox Code Playgroud)

另一种选择是使用separate_rows,将其重塑为"长"格式并将spread其重新格式化

rownames_to_column(df, 'rn') %>%
    separate_rows(block_order) %>% 
    group_by(rn) %>% 
    mutate(ind = match(block_order, labels), labels = factor(labels, levels = labels)) %>%
    select(-block_order) %>%
    spread(labels, ind) %>% 
    ungroup %>%
    select(-rn) %>% 
    bind_cols(df, .)
Run Code Online (Sandbox Code Playgroud)