从数据帧2中的数据帧1找到紧密匹配

问题描述

我有两个数据帧,对于数据帧1中的每个特定行,我试图根据已定义的重要标准(班次,年龄,水平)从数据帧2中找到最接近的匹配项。例如,假设我有数据帧1:

shift_1 <- c(1,1,2)
length_1 <- c(100,120,5,70)
level_1<- c(1,3,4)
age_1 <- c(4.5,3.2,2.5)

df_1 <- data.frame(shift_1,level_1,age_1,length_1)

  shift_1 level_1 age_1 length_1
1       1       1   4.5      100
2       1       3   3.2      120
3       0       5   3.0        5
4       2       4   2.5       70

对于这个数据帧的每一行,我想在数据帧2中找到最接近的匹配,如下所示:

shift_2 <- c(1,2,0)
length_2 <- c(100,200,40,180,10)
level_2<- c(3,4,5)
age_2 <- c(2.5,5.5,2.2,3.1,5)

df_2 <- data.frame(shift_2,level_2,age_2,length_2)

  shift_2 level_2 age_2 length_2
1       1       3   2.5      100
2       1       4   5.5      200
3       2       4   2.2       40
4       1       3   3.1      180
5       0       5   5.0       10

基于以下条件: 完全匹配必须。级别必须完全匹配。年龄的差价为20%

如果找到匹配项:我们要添加匹配行的索引号匹配信息,否则我们将输入NA。所以预期的结果是这样的:

  shift_r level_r age_r length_r index shift_match level_match age_match length_match
1       1       1   4.5      100    NA          NA          NA        NA           NA
2       1       3   3.2      120     4           1           3       3.1          180
3       0       5   3.0        5    NA          NA          NA        NA           NA
4       2       4   2.5       70     3           2           4       2.2           40

能否请您告知我该如何处理?有没有可以简化此任务的库?

解决方法

您需要“非等价”或“范围”联接。这是在R的public static void main(String[] args) { int x = 2; int [] myArray = {1,2,3,4,5}; for (int i = 0; i < myArray.length; i++) { if(x == myArray[i]) { //do something } } } } fuzzyjoin包中实现的。由于SQL也支持它,因此人们也可以使用data.table

遗憾的是,sqldf本机不支持此功能。由于此操作在SQL中受支持,因此如果您的数据在数据库中,则dplyr将允许使用其dbplyr,但不是本机使用。

首先,我们需要添加20%的公差:

sql_on

fuzzyjoin

df_1$age_1_start <- df_1$age_1 * 0.8
df_1$age_1_end <- df_1$age_1 * 1.2
df_1
#   shift_1 level_1 age_1 length_1 age_1_start age_1_end
# 1       1       1   4.5      100        3.60      5.40
# 2       1       3   3.2      120        2.56      3.84
# 3       0       5   3.0        5        2.40      3.60
# 4       2       4   2.5       70        2.00      3.00

data.table

fuzzyjoin::fuzzy_left_join(
  df_1,df_2,by = c("shift_1" = "shift_2","level_1" = "level_2","age_1_start" = "age_2","age_1_end" = "age_2"),match_fun = list(`==`,`==`,`<=`,`>=`))
#   shift_1 level_1 age_1 length_1 age_1_start age_1_end shift_2 level_2 age_2 length_2
# 1       1       1   4.5      100        3.60      5.40      NA      NA    NA       NA
# 2       1       3   3.2      120        2.56      3.84       1       3   3.1      180
# 3       0       5   3.0        5        2.40      3.60      NA      NA    NA       NA
# 4       2       4   2.5       70        2.00      3.00       2       4   2.2       40

此软件包倾向于根据右边的名称来重命名左边的(library(data.table) DT_1 <- as.data.table(df_1) # must include age_1_start and age_1_end from above DT_2 <- as.data.table(df_2) DT_2[DT_1,on = .(shift_2 == shift_1,level_2 == level_1,age_2 >= age_1_start,age_2 <= age_1_end)] # shift_2 level_2 age_2 length_2 age_2.1 age_1 length_1 # 1: 1 1 3.60 NA 5.40 4.5 100 # 2: 1 3 2.56 180 3.84 3.2 120 # 3: 0 5 2.40 NA 3.60 3.0 5 # 4: 2 4 2.00 40 3.00 2.5 70 )连接,这可能会令人沮丧。为此,您随后需要进行一些清理。

sqldf

DT_1

如果您知道SQL,那么最后一个可能是最直观和最容易理解的。但是请记住,对于较大的框架,它会将整个框架复制到内存存储SQLite实例中……这不是“免费的”。

sqldf::sqldf( "select t1.*,t2.* from df_1 t1 left join df_2 t2 on t1.shift_1 = t2.shift_2 and t1.level_1 = t2.level_2 and t1.age_1_start <= t2.age_2 and t1.age_1_end >= t2.age_2") # shift_1 level_1 age_1 length_1 age_1_start age_1_end shift_2 level_2 age_2 length_2 # 1 1 1 4.5 100 3.60 5.40 NA NA NA NA # 2 1 3 3.2 120 2.56 3.84 1 3 3.1 180 # 3 0 5 3.0 5 2.40 3.60 NA NA NA NA # 4 2 4 2.5 70 2.00 3.00 2 4 2.2 40 实现为您提供了强大的功能,它的参数对我而言似乎很容易理解。结果正如我期望的那样命名。但是,这是三个实现中最慢的一个(使用此数据)。 (仅当您的真实数据“非常”大时才应对此加以考虑。)

如果您还不知道fuzzyjoin,尽管它的速度非常快,但它的R的方言可能会让不了解情况的人模糊不清。我相信它具有data.table一样强大的功能,尽管我还没有测试所有极端情况,以查看其中一个是否支持另一种不支持的东西。

fuzzyjoin