从R中的变量列表创建一个变量?

时间:2019-04-22 14:23:04

标签: r dplyr tidyverse mutate

我在数据框中有一系列变量(超过100个),并且我想创建一个指示符变量,用于确定变量中是否存在特定的文本模式。以下是具有三个变量的示例。我发现一种解决方案是使用tidyr::unite(),然后使用dplyr::mutate(),但是我对不必统一变量的解决方案很感兴趣。

c1<-c("T1", "X1", "T6", "R5")
c2<-c("R4", "C6", "C7", "X3")
c3<-c("C5", "C2", "X4", "T2")

df<-data.frame(c1, c2, c3)

  c1 c2 c3
1 T1 R4 C5
2 X1 C6 C2
3 T6 C7 X4
4 R5 X3 T2

code.vec<-c("T1", "T2", "T3", "T4") #Text patterns of interest
code_regex<-paste(code.vec, collapse="|")

new<-df %>% 
  unite(all_c, c1:c3, remove=FALSE) %>% 
  mutate(indicator=if_else(grepl(code_regex, all_c), 1, 0)) %>% 
  select(-(all_c))

  c1 c2 c3 indicator
1 T1 R4 C5 1
2 X1 C6 C2 0
3 T6 C7 X4 0
4 R5 X3 T2 1

上面是产生所需结果的示例,但是我觉得好像tidyverse中应该有一种不必合并变量的方法。 SAS使用ARRAY语句和DO循环可以很轻松地处理此问题,我希望R具有处理此问题的好方法。

真正的数据框除了要搜索的“ c”字段外,还有许多其他变量,因此涉及搜索每一列的解决方案将需要将数据框设置为首先仅包含我要搜索的变量,然后再将数据重新加入与其他变量。

3 个答案:

答案 0 :(得分:6)

使用基数R,我们可以使用sapplygrepl在每一列中查找模式,并为匹配项大于0的行分配1。

df$indicator <- as.integer(rowSums(sapply(df, grepl, pattern = code_regex)) > 0)

df
#  c1 c2 c3 indicator
#1 T1 R4 C5         1
#2 X1 C6 C2         0
#3 T6 C7 X4         0
#4 R5 X3 T2         1

如果其他列很少,我们有兴趣仅将其应用于以"c"开头的列,我们可以使用grep进行过滤。

cols <- grep("^c", names(df))
as.integer(rowSums(sapply(df[cols], grepl, pattern = code_regex)) > 0)

使用dplyr我们可以做到

library(dplyr)

df$indicator <- as.integer(df %>%
              mutate_at(vars(c1:c3), ~grepl(code_regex, .)) %>%
              rowSums() > 0)

答案 1 :(得分:3)

我们可以使用tidyverse

library(tidyverse)
df %>%
    mutate_all(str_detect, pattern = code_regex) %>%
    reduce(`+`) %>% 
    mutate(df, indicator = .)
#  c1 c2 c3 indicator
#1 T1 R4 C5         1
#2 X1 C6 C2         0
#3 T6 C7 X4         0
#4 R5 X3 T2         1

或使用base R

Reduce(`+`, lapply(df, grepl, pattern = code_regex))
#[1] 1 0 0 1

答案 2 :(得分:1)

R为基础的apply

apply(df[cols], 1, function(x) sum(grepl(code_regex, x)))
# [1] 1 0 0 1