根据向量中相似(不相同)的元素返回数据框子集?

Return a data frame subset based on similar (not identical) elements in a vector?

提问人:ElizaBeso000 提问时间:8/25/2023 更新时间:9/1/2023 访问量:35

问:

我有一个数据帧(暗淡 2914 x 6),其中一列是动物群和物种缩写的向量,例如“bird_F.pw”,我有一个单独的向量,其中包含几个物种缩写,例如“F.pw”。我正在尝试从数据框中提取动物组和物种缩写与缩写相似的所有数据行(即,我不知道前缀)。我想使用 %in% 和 %like% 等运算符,但我无法找到生成不相同匹配项的方法。

下面是一个示例数据帧:

df<-cbind(
c("A","B","C","D","E"),
c(1:5),
c("insect_F.vp","bird_L.ts","insect_P.qr","insect_V.cl","bird_H.dw"))
colnames(df) <- c("season","survey_id","pollinator")

这是我想在该数据帧中搜索的缩写向量:

abbrevs <- c("L.ts","P.qr","H.dw")

我的预期结果是:

output <- cbind(c("B","C","E"),c(2:3,5),c("bird_L.ts","insect_P.qr","bird_H.dw"))
colnames(output) <- colnames(df)
r 字符串匹配

评论


答:

3赞 Rui Barradas 8/25/2023 #1

这里有两种解决方案,基本 R 和带包。主要技巧是创建一个带有替代方案的复合模式()。这是用 完成的。美元符号与字符串的末尾匹配,因此必须结束正在搜索它的数据。stringr"|"pasteabbrevs

df <- data.frame(
  season = c("A","B","C","D","E"),
  survey_id = 1:5,
  pollinator = c("insect_F.vp","bird_L.ts","insect_P.qr","insect_V.cl","bird_H.dw")
)
abbrevs <- c("L.ts","P.qr","H.dw")

pat <- paste0(abbrevs, "$", collapse = "|")

# base R
i <- grepl(pat, df$pollinator)
# package stringr
j <- stringr::str_detect(df$pollinator, pat)

df[i, ]
#>   season survey_id  pollinator
#> 2      B         2   bird_L.ts
#> 3      C         3 insect_P.qr
#> 5      E         5   bird_H.dw

df[j, ]
#>   season survey_id  pollinator
#> 2      B         2   bird_L.ts
#> 3      C         3 insect_P.qr
#> 5      E         5   bird_H.dw

创建于 2023-08-24 with reprex v2.0.2

评论

1赞 MrFlick 8/25/2023
这也将匹配“insect_Hxdw”等值。这不太可能发生,但在这里将是一个通配符。.
1赞 LMc 8/25/2023
在调用中,您可以执行类似操作,以防止正则表达式引擎解释 和 之间的其他正则表达式模式。paste0paste0("\\Q", abbrevs, "\\E$", collapse = "|").\Q\E
3赞 TarJae 8/25/2023 #2

在基础 R 中,我们可以使用 family:apply

  1. 将矩阵 df 转换为数据帧。
  2. 使用 sapply 和 grepl,我们可以识别哪些行包含每个缩写。
  3. 然后,我们使用 apply 和 MARGIN = 1 来检查是否有任何缩写与每一行匹配。
  4. 最后,我们使用 df[...] 基于 apply(matches, 1, any) 逻辑向量进行子集。
df <- df <- as.data.frame(df)

df[apply(sapply(abbrevs, function(x) grepl(x, df$pollinator)), 1, any), ]


  season survey_id  pollinator
2      B         2   bird_L.ts
3      C         3 insect_P.qr
5      E         5   bird_H.dw
5赞 MrFlick 8/25/2023 #3

如果您不想为正则表达式而烦恼,可以使用这些替代方法。这是一个整洁的

find_any_fixed <- function(x, patterns) {
  purrr::map(patterns, ~stringr::str_detect(x, stringr::fixed(.x))) |> purrr::reduce(`|`)
}

这是一个基本的 R 版本

find_any_fixed <- function(x, patterns) {
  Map(function(.x) grepl(.x, x, fixed=TRUE), patterns) |> Reduce(`|`, x=_)
}

在这两种解决方案中,我确保使用“fixed”选项,因为当您使用正则表达式时,“.”表示特殊的东西。由于您似乎希望与句点完全匹配,因此您需要让搜索工具知道您没有使用正则表达式

您可以使用它来查找匹配的模式。这些示例假定是 data.frame ()。例如dfdf <- as.data.frame(df)

find_any_fixed(df$pollinator, abbrevs)
# [1] FALSE  TRUE  TRUE FALSE  TRUE

你可以用它来子集

# Tidyverse
df %>% filter(find_any_fixed(pollinator, abbrevs))
# Base R
subset(df, find_any_fixed(pollinator, abbrevs))
1赞 LMc 8/25/2023 #4

我认为这里的一个简单的解决方案是使用 .它既可读又矢量化:endsWith

df[sapply(df$pollinator, \(x) any(endsWith(x, abbrevs))),]

对于 的每个元素,请检查该元素是否以 中的任何值结尾。 将返回一个可用于筛选行的逻辑向量。df$pollinatorabbrevssapply

输出

  season survey_id  pollinator
2      B         2   bird_L.ts
3      C         3 insect_P.qr
5      E         5   bird_H.dw