r语言 - 根据T/F列只粘贴矢量的一部分



假设我有一个数据框架,其中包含显示颜色的物种。

df<-data.frame(name=paste("spec",1:5),
ind=c("blue;green","red","green","red;green;blue",""))

(蓝色和红色)的颜色实际上是有意义的。我可以对它们进行grepl()然后得到T/f列

df$isredorblue<-grepl("blue|red",df$ind)

但是现在我想知道有意义的颜色中哪一个显示在一个列中。

期望的结果是:

> df
name            ind isredorblue searchcolor
1 spec 1     blue;green        TRUE        blue
2 spec 2            red        TRUE         red
3 spec 3          green       FALSE       other
4 spec 4 red;green;blue        TRUE    red;blue
5 spec 5                      FALSE       other

我试过用[^]+ gsub,但这并没有真正起作用,因为它匹配所有字母so " "或";e"或";d"不是"red">

>     gsub("[^red]+","",df$ind)
[1] "eree"    "red"     "ree"     "redreee" ""    

现在我正在考虑使用strsplit…但似乎不知道下一步该怎么做

blabla<-strsplit(df$ind, split=";") 

blabla<-blabla[-which(!blabla %in% c("red","blue"))]
> blabla
[[1]]
[1] "red"

请记住这是一个表示,我的实际数据框架要大得多,并且有不同的指示器"颜色"这对不同的东西很重要所以我需要能够在尽可能少的步骤中生成这些列

有两种方法。

  1. Using regex -

这将从color创建一个regex模式,以便从数据中的ind列中提取。如果没有提取值,则将空白替换为'other'

color <- c('red', 'blue')
pat <- paste0(color, collapse = '|')
df$is_color_present <- grepl(pat, df$ind)
df$searchcolor <- sapply(stringr::str_extract_all(df$ind, pat), paste0, collapse = ';')
df$searchcolor[df$searchcolor == ''] <- 'other'
df
#    name            ind is_color_present searchcolor
#1 spec 1     blue;green             TRUE        blue
#2 spec 2            red             TRUE         red
#3 spec 3          green            FALSE       other
#4 spec 4 red;green;blue             TRUE    red;blue
#5 spec 5                           FALSE       other
  1. 不使用tidyverse-

我们在;上获得长格式拆分的数据,并且只保留color中存在的那些值。

library(dplyr)
library(tidyr)
df %>%
separate_rows(ind, sep = ';') %>%
group_by(name) %>%
summarise(is_color_present = any(ind %in% color), 
searchcolor = paste0(ind[ind %in% color], collapse = ';'), 
searchcolor = replace(searchcolor, searchcolor == '', 'other'))

这里有一个简洁的解决方案:

library(dplyr)
library(stringr)

首先将所有目标颜色定义为一个向量:

targets <- c('red', 'blue')

现在使用转换为正则表达式交替模式的向量,在新列中提取所需的颜色:

df %>%
mutate(colors = str_extract_all(ind, paste0(targets, collapse = "|")))
name            ind    colors
1 spec 1     blue;green      blue
2 spec 2            red       red
3 spec 3          green          
4 spec 4 red;green;blue red, blue
5 spec 5 

如果你有很多颜色名称,其中一些可能有相同的字母(比如"red"one_answers"darkred"),您可能希望在颜色名称周围换行单词边界:

df %>%
mutate(colors = str_extract_all(ind, paste0("\b(",paste0(targets, collapse = "|"), ")\b")))

这是另一个dplyr解决方案(虽然不是最简洁的):

df %>%
mutate(
blue = ifelse(grepl("blue", ind), "blue","other"),
red = ifelse(grepl("red", ind), "red","other"),
target = ifelse(blue=="blue"|red=="red", paste(red, blue), "other"),
target = sub("^other\s(?=blue|red)|(?<=blue|red)\sother$", "", target, perl = TRUE)) %>%
select(-c(3:5))
name            ind   target
1 spec 1     blue;green     blue
2 spec 2            red      red
3 spec 3          green    other
4 spec 4 red;green;blue red blue
5 spec 5                   other

数据:

df<-data.frame(name=paste("spec",1:5),
ind=c("blue;green","red","green","red;green;blue",""))