紧密匹配两个R数据帧

时间:2019-01-16 15:54:23

标签: r distance

我有以下两个数据帧:

df1 <- data.frame(group = rep("A", 5),
                  name = c("Brandon",
                           "Kyler",
                           "Trent",
                           "Lesa",
                           "Michael"),
                  gender = c("M", "F", "M", "F", "M"),
                  days = c(50, 45, 32, 60, 48))

df2 <- data.frame(group = rep("B", 10),
                  name = c("Erica", 
                           "Jared",
                           "Sara",
                           "Helen",
                           "Tom",
                           "Ron",
                           "Cy",
                           "Lynn",
                           "Ken",
                           "Judy"),
                  gender = c("F", "M", "F", "F", "M", "M", "M", "F", "M", "F"),
                  days = c(47, 49, 62, 80, 74, 30, 55, 58, 63, 25))

我想过滤df2,使其仅包含与df1gender基于days的{​​{1}}数据框中的每一行最接近的匹配项优先。

例如,在gender中,“布兰登”具有df1gender == M。当我们仅查看days == 50中的gender == M时,我们发现“ Jared”在几天之内最接近“ Brandon”,因此将为“ Brandon”匹配选择“ Jared”。总体而言,结果数据框架如下所示:

df2

其他规则:

  • 这是分层合并,其中# group name gender days # B Jared M 49 # B Erica F 47 # B Ron M 30 # B Lynn F 58 # B Cy M 55 匹配优先于gender紧密度。

  • 请注意,有两个等距选项与days中的“ Lesa”匹配(“ Sara”和“ Lynn”)。随机选择两者之一以匹配“ Lesa”。在上面的最后一个数据框中,示例选择了“ Lynn”。

  • df1中的“ Jared”与df2中的“ Brandon”和“ Michael”的距离相等。因为“ Jared”已经与“ Brandon”匹配,所以他也不能与“ Michael”匹配。因此,与“ Michael”的比赛继续至“ Cy”,这是就df1gender而言第二好的比赛。

1 个答案:

答案 0 :(得分:2)

数据

首先,我将stringsAsFactors = FALSE添加到您的输入数据帧中,因为使用字符串比解决方案中的因数更容易。

df1 <- data.frame(group = rep("A", 5),
              name = c("Brandon",
                       "Kyler",
                       "Trent",
                       "Lesa",
                       "Michael"),
              gender = c("M", "F", "M", "F", "M"),
              days = c(50, 45, 32, 60, 48),
              stringsAsFactors = FALSE)

df2 <- data.frame(group = rep("B", 10),
                  name = c("Erica", 
                           "Jared",
                           "Sara",
                           "Helen",
                           "Tom",
                           "Ron",
                           "Cy",
                           "Lynn",
                           "Ken",
                           "Judy"),
                  gender = c("F", "M", "F", "F", "M", "M", "M", "F", "M", "F"),
                  days = c(47, 49, 62, 80, 74, 30, 55, 58, 63, 25),
                  stringsAsFactors = FALSE)

解决方案

library(tidyverse)

# empty dataframe for the output
df2_new <- data.frame(group = character(),
                      name = character(),
                      gender = character(),
                      days = numeric(),
                      stringsAsFactors = FALSE)

for(i in 1:nrow(df1)){

  # add the row of interest to the output dataframe
  df2_new[i,] <- df2 %>% 
    mutate(day_diff = abs(days - df1$days[i])) %>%
    filter(gender == df1$gender[i]) %>% 
    slice(which.min(day_diff)) %>%
    select(-day_diff)

  # remove the newly added row from the original dataset
  df2 <- df2 %>%
    filter(!(name %in% df2_new$name))

}

这是我想到的第一个解决方案。在这种情况下,正如您所说的那样,随着for循环的进行,df2中的行将被删除

  

想要过滤df2,使其仅包含与df1中每一行最接近的匹配项

输出

df2_new

  group  name gender days
1     B Jared      M   49
2     B Erica      F   47
3     B   Ron      M   30
4     B  Sara      F   62
5     B    Cy      M   55

在我的情况下,代码选择了Sara而不是Lynn,但这是50/50的选择。