首页 > 解决方案 > 使用第二个数据帧值按值过滤数据帧

问题描述

我总是遇到循环问题,所以我在这里问。2个数据框。1 个非常大,1 个小得多。下面的示例版本。

Dataframe 1

ID        Value
1         apples
1         apples
1         bananas
1         grapes
1         mangoes
1         oranges
1         grapes
1         apples
1         grapes
2         apples
2         apples
2         passionfruits
2         bananas
2         apples
2         apples
2         passionfruits
2         grapes
2         mangoes
2         apples
3         apples
3         bananas
3         oranges
3         apples
3         grapes
3         grapes
3         passionfruits
3         passionfruits
3         oranges
4         apples
4         oranges
4         mangoes
4         bananas
4         grapes
4         grapes
4         grapes
4         apples
4         oranges
4         grapes
4         mangoes
4         mangoes
4         apples
4         oranges
5         passionfruits
5         apples
5         oranges
5         oranges
5         mangoes
5         grapes
5         apples
5         bananas

Dataframe 2

Value
apples
apples
bananas
grapes
mangoes
mangoes
grapes
apples
apples

数据帧 1 中的不同 ID 被视为集合。数据框 2 的整体将与其中一组近似或精确匹配。我知道有很多代码可以使用整个数据帧 2 与 1 匹配进行过滤。但这不是我需要的。我要求它在附加条件的情况下按值顺序过滤。条件应该是之前的值是否匹配。

因此,在此示例中,第一个值没有任何反应,因为所有 ID 都有“苹果”。第二个值 = 'apples' 给定先前的值 ='apples' 过滤掉 ID = 4,因为它不包含连续出现两次的 'apples'。现在在过滤后的数据帧 1 中,我们搜索第三个值,依此类推。它仅在数据帧 1 中保留 1 个 ID 集时停止。因此在这种情况下,在第 3 次迭代之后。结果应该是

Dataframe 1

ID        Value
1         apples
1         apples
1         bananas
1         grapes
1         mangoes
1         oranges
1         grapes
1         apples
1         grapes

标签: rdataframefilter

解决方案


一种可能的方法data.table(改编自我的回答here):

# load packages
library(data.table)

# create a function which calculates match-score with 'df2$Value'
maxscore <- function(x, y) {
  m <- mapply('==', shift(x, type = 'lead', n = 0:(length(y) - 1)), y)
  max(rowSums(m, na.rm = TRUE))
}

# calculate the match-score for each group
# and filter out the other groups
setDT(df1)[, score := maxscore(Value, df2$Value), by = ID
           ][score == max(score)][, score := NULL][]

这使:

   ID   Value
1:  1  apples
2:  1  apples
3:  1 bananas
4:  1  grapes
5:  1 mangoes
6:  1 oranges
7:  1  grapes
8:  1  apples
9:  1  grapes

您也可以在 -chain 中使用该功能dplyr(但您仍然需要data.table-package 用于shift-function):

library(dplyr)
df1 %>% 
  group_by(ID) %>% 
  mutate(m = maxscore(Value, df2$Value)) %>% 
  ungroup() %>% 
  filter(m == max(m)) %>% 
  select(-m)

-function 的另一种实现maxscore(灵感来自@doscendo's answer here):

maxscore2 <- function(x, y) {
  w <- which(x == y[1])
  v <- sapply(w, function(i) sum(x[i:(i+(length(y)-1))] == y, na.rm = TRUE))
  max(v)
}

推荐阅读