【问题标题】:Matching Two R Data Frames on Closeness在接近度上匹配两个 R 数据框
【发布时间】:2019-01-17 00:37:09
【问题描述】:

我有以下两个数据框:

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))

我想根据genderdays 过滤df2 以仅包含与df1 数据框中每一行最接近的匹配项,gender 优先。

例如,在df1 中,“Brandon”有gender == Mdays == 50。当我们只查看df2 中的gender == M 时,我们看到“Jared”在几天内最接近“Brandon”,因此“Jared”将被选为“Brandon”匹配。总的来说,生成的数据框如下所示:

# 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 紧密度。

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

  • df2 中的“Jared”与df1 中的“Brandon”和“Michael”距离相等。因为“Jared”已经匹配到“Brandon”,所以他不能也匹配到“Michael”。因此,与“Michael”的比赛继续进行到“Cy”,这是在genderdays 方面的下一个最佳剩余比赛。

【问题讨论】:

  • 您如何平衡genderdays 的重要性?编辑:抱歉没有看到你过滤性别。所以它是一个分层合并,您首先过滤性别然后获得最接近的日期匹配?
  • @JonnyPhelps 你是对的 - 分层合并,给予gender 优先级。

标签: r distance


【解决方案1】:

数据

首先,我将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 的选择。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-11-26
    • 2021-11-27
    • 1970-01-01
    • 2019-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多