【问题标题】:Select unique x and y pairs to minimize a value选择唯一的 x 和 y 对以最小化一个值
【发布时间】:2019-02-20 08:33:50
【问题描述】:

我需要为每个 ID.y 选择一个唯一的 ID.x(形成唯一对),以最小化距离值,从最低距离值开始。我觉得这有点像数独谜题,因为每个 x 和 y 只能使用一次,因此来自每对的信息可以匹配其他对。

在下面的示例中,ID.x 55 比 ID.x 56 更适合 ID.y 1,因为 ID.x 56 更适合 ID.y 2。同样,ID.x 58 可以匹配到 ID.y 4,因为任何其他可用选项将是更大的距离,然后 ID.y 5 可以在距离 4 处获取 ID.x 59。但是,ID.y 7 无法匹配,因为 ID.x 61 和ID.x 62 同样接近。

例子:

DT = data.table(
  ID.x = c("55", "55", "55", "55", "55", "55", "55", "56", "56", "56", "56", "56", "56", "56", "57", "57", "57", "57", "57", "57", "57", "58", "58", "58", "58", "58", "58", "58", "59", "59", "59", "59", "59", "59", "59", "60", "60", "60", "60", "60", "60", "60", "61", "61", "61", "61", "61", "61", "61", "62", "62", "62", "62", "62", "62", "62"),
  ID.y = c("1", "2", "3", "4", "5", "6", "7", "1", "2", "3", "4", "5", "6", "7", "1", "2", "3", "4", "5", "6", "7", "1", "2", "3", "4", "5", "6", "7", "1", "2", "3", "4", "5", "6", "7", "1", "2", "3", "4", "5", "6", "7", "1", "2", "3", "4", "5", "6", "7", "1", "2", "3", "4", "5", "6", "7"),
  distance = c("2", "3", "3", "4", "6", "6", "7", "2", "1", "2", "5", "5", "5", "6", "4", "4", "3", "5", "5", "5", "6", "5", "5", "5", "4", "4", "5", "6", "7", "7", "7", "6", "4", "6", "7", "6", "6", "6", "6", "4", "2", "5", "7", "7", "7", "7", "5", "5", "5", "6", "6", "6", "6", "4", "4", "5")
  )

目标:

   ID.x ID.y distance
1:   55    1        2
2:   56    2        1
3:   57    3        3
4:   58    4        4
5:   59    5        4
6:   60    6        2
7:   NA    7        NA

第一次尝试inspired by this question 不起作用:

DT[DT[, .I[distance == min(distance)], by=ID.x]$V1][DT[, .I[1], by = ID.y]$V1]

更新: 针对@chinsoon12 和@paweł-chabros 的回答,这里有一个更新的data.table,它修复了一些问题。它交换 x 和 y(我最初的问题是将 x 与 y 匹配,但更自然的解释是 y 与 x)。此示例删除了 ID.y 7 的模糊匹配。在此示例中,最小距离匹配 ID.x 63。另外,我还添加了一个新的 ID.y 8,以阐明何时无法进行明确匹配(它匹配 ID.y 8)。 x 64 和 65 一样好)。答案不应随意选择匹配项。

DT = data.table(
  ID.y = c("55", "55", "55", "55", "55", "55", "55", "55", "56", "56", "56", "56", "56", "56", "56", "56", "57", "57", "57", "57", "57", "57", "57", "57", "58", "58", "58", "58", "58", "58", "58", "58", "59", "59", "59", "59", "59", "59", "59", "59", "60", "60", "60", "60", "60", "60", "60", "60", "61", "61", "61", "61", "61", "61", "61", "61", "62", "62", "62", "62", "62", "62", "62", "62", "63", "63", "63", "63", "63", "63", "63", "63", "64", "64", "64", "64", "64", "64", "64", "64", "65", "65", "65", "65", "65", "65", "65", "65"),
  ID.x = c("1", "2", "3", "4", "5", "6", "7", "8", "1", "2", "3", "4", "5", "6", "7", "8", "1", "2", "3", "4", "5", "6", "7", "8", "1", "2", "3", "4", "5", "6", "7", "8", "1", "2", "3", "4", "5", "6", "7", "8", "1", "2", "3", "4", "5", "6", "7", "8", "1", "2", "3", "4", "5", "6", "7", "8", "1", "2", "3", "4", "5", "6", "7", "8", "1", "2", "3", "4", "5", "6", "7", "8", "1", "2", "3", "4", "5", "6", "7", "8", "1", "2", "3", "4", "5", "6", "7", "8"),
  distance = c(2, 3, 3, 4, 6, 6, 7, 15, 2, 1, 2, 5, 5, 5, 6, 15, 4, 4, 3, 5, 5, 5, 6, 15, 5, 5, 5, 4, 4, 5, 6, 15, 7, 7, 7, 6, 4, 6, 7, 15, 6, 6, 6, 6, 4, 2, 5, 15, 7, 7, 7, 7, 5, 5, 6, 15, 6, 6, 6, 6, 4, 4, 10, 15, 11, 11, 11, 11, 11, 11, 5, 12, 11, 11, 11, 11, 11, 11, 11, 1, 11, 11, 11, 11, 11, 11, 11, 1)
  )

预期结果:

   ID.y ID.x distance
1:   55    1        2
2:   56    2        1
3:   57    3        3
4:   58    4        4
5:   59    5        4
6:   60    6        2
7:   63    7        5
8:   NA    8        NA

I'm using this code is to complete a fuzzy join using stringdist_join, as described in this question. 我有两个需要匹配的数据集(因此是 ID.x 和 ID.y)。就我而言,我的前测和后测分数需要与多个不可靠的特征相匹配。

【问题讨论】:

  • 我认为如果下一个结果取决于前一个结果,则需要循环。
  • 你能解释一下为什么 ID.x 62 和 ID.y 7 距离 5 不可行吗?
  • ID.y 7 的问题在于它与 ID.x 61 和 ID.x 62 的匹配度相同(都是 dist 5)。在这个例子中,我没有看到任何方式来选择另一个,除非是任意的,所以我认为最好将 ID.y 7 保留为 NA。如果我们反过来做,为每个 ID.x 选择一个唯一的 ID.y,为什么 61 不匹配 7 而 62 得到 NA?再一次(在这种反向情况下),似乎最好的解决方案是让 61 和 62 都从 ID.y 获得不匹配。

标签: r dplyr data.table


【解决方案1】:

我不清楚为什么 ID.x 62 和 ID.y 7 距离 5 不可行。

假设 ID.x 62、ID.y 7 和距离 5 是可以接受的,使用data.table 的可能方法:

setorder(DT, distance)
choseny <- c()
ans <- DT[,
    {
        y <- setdiff(ID.y, choseny)[1L]
        choseny <- c(choseny, y)  
        .(ID.y=y, dist=.SD[ID.y==y, distance[1L]])
    },
    by=.(ID.x)]
setorder(ans, ID.x)[]

输出:

   ID.x ID.y dist
1:   55    1    2
2:   56    2    1
3:   57    3    3
4:   58    4    4
5:   59    5    4
6:   60    6    2
7:   61 <NA> <NA>
8:   62    7    5

【讨论】:

    【解决方案2】:

    我不确定这是否真的是理想的解决方案,但它应该会有所帮助。不是超级优雅,但它看起来很像所需的输出。

     DT[, .(ID.y
         , distance
         , Row.Num = rank(distance)
         , Row.Num.ID = rank(ID.y)), by = list(ID.x)][, .SD[Row.Num == min(Row.Num) ], by = ID.x][, .SD[Row.Num.ID == min(Row.Num.ID) ], by = ID.x] 
     >  ID.x ID.y distance Row.Num Row.Num.ID
    1:   55    1        2     1.0          1
    2:   56    2        1     1.0          2
    3:   57    3        3     1.0          3
    4:   58    4        4     1.5          4
    5:   59    5        4     1.0          5
    6:   60    6        2     1.0          6
    7:   61    5        5     2.0          5
    8:   62    5        4     1.5          5
    

    【讨论】:

    • 重要的部分是独特的方面。每个 ID.x 和 ID.y 只能在输出中出现一次,这样距离对于每对来说是可能的最低值。它必须是一对一的匹配。
    【解决方案3】:

    我不太了解data.table,所以我只能给你tidyverse 解决方案。但也许它会帮助你:)

    library(tidyverse)
    
    ID_y <- unique(DT$ID.y)
    
    DT %>%
      as_tibble() %>%
      group_by(ID.x) %>%
      mutate(min_dist = min(distance)) %>%
      arrange(min_dist) %>%
      nest() %>%
      mutate(data = data %>% map(~ {
        min_row <- .x %>%
          filter(ID.y %in% ID_y) %>%
          filter(distance == min(distance)) %>%
          slice(1)
        ID_y <<- ID_y[ID_y != min_row$ID.y]
        min_row
      })) %>%
      unnest() %>%
      select(-min_dist) %>%
      arrange(ID.x)
    

    我正在保存ID.y 的所有唯一值。然后我计算所有组合的最小距离,并按此最小距离排列,以首先在map 循环中处理这些组合。在过滤了最小距离后,我从向量中删除了ID.y,所以其他ID.x 只在左边的ID.y 中搜索。

    【讨论】:

    • 如果您删除 slice(1),则此代码有效,然后添加以下三行:DT &lt;- as.data.table(DT)DT[, num_matches := .N, by = .(ID.x)]DTunique &lt;- unique(DT[num_matches &gt; 1, ID.y := NA])
    • 但是,我的数据集中出现以下错误:Warning messages: 1: In ID_y != min_row$ID.y : longer object length is not a multiple of shorter object length
    猜你喜欢
    • 2023-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-20
    • 1970-01-01
    • 1970-01-01
    • 2010-10-21
    相关资源
    最近更新 更多