【问题标题】:What is an efficient way to find the highest average similarity/distance between two collections?找到两个集合之间最高平均相似度/距离的有效方法是什么?
【发布时间】:2022-01-12 17:56:41
【问题描述】:

问题:

假设我有集合 A 和集合 B 不一定大小相等。

然后我想为A 中的每个aB 中的每个b 找到一组最高得分对。

主要规定A中的每个aB中的每个b只能使用一次。所以如果score(a1, b1) == score(a1, b2)我们只能保留两个分数之一。

下面是一个包含相似度矩阵的具体示例。每一行代表集合 A 的一个元素,每一列是集合 B 的一个元素。所以M[i][j] = score(a_i, b_j)

new double[][]{{1, 4, 1, 1}, // 4 occurs twice in a column
               {3, 1, 2, 3}, // 3 occurs twice in a row
               {1, 4, 1, 1}};

我们首先会说 (0,1) 包含第 1 行中的最高分。因此 a_0b_1 不再可用于任何匹配。

接下来,我们会说(1, 0)(1, 3) 包含第2 行中的最高分。由于两者都是公平游戏,我们选择(1, 0)。现在,a_1b_0 是禁区。

最后,我们看到第三行的最高分是(2, 1)。但是因为B 中的b_1 是针对的,所以我们必须选择别的东西。我们改为选择(2, 3)

所以我们没有重复的成对最高得分对是(a_0, b_1), (a_1, b_0), (a_2, b_3)

这是我尝试过的:

import org.apache.commons.math3.linear.Array2DRowRealMatrix;
import org.apache.commons.math3.linear.RealVector;
import org.apache.commons.math3.util.Pair;

 public static double rankBySimilarity(Array2DRowRealMatrix simMatrix) {

        Set<Integer> rowIdxs =
            IntStream.range(0, simMatrix.getRowDimension()).boxed().collect(Collectors.toSet());
        Set<Integer> colIdxs =
            IntStream.range(0, simMatrix.getColumnDimension()).boxed().collect(Collectors.toSet());

        Set<Pair<Integer, Integer>> bestScoreIdxs = new HashSet<>();

        for (int row : rowIdxs) {
            RealVector rowVec = simMatrix.getRowVector(row);
            int col = rowVec.getMaxIndex();
            bestScoreIdxs.add(new Pair<>(row, col));
            rowIdxs.remove(row);
            colIdxs.remove(col);

            if (rowIdxs.isEmpty() || colIdxs.isEmpty()) {
                break;
            }
        }

        double score = 0;
        for (Pair<Integer, Integer> coord : bestScoreIdxs) {
            int x = coord.getFirst();
            int y = coord.getSecond();
            score += simMatrix.getEntry(x, y);
        }

        return score / bestScoreIdxs.size();

    }

但是,这会引发异常,因为我正在迭代并同时更改集合。我已阅读并理解该错误。我想不出一个有效的替代方案。

也许继续使用相似矩阵不是一个好主意?欢迎任何建议或提示。

编辑 我刚刚用 rowIdxs.iterator() 替换了 rowIdxs 并逐步调试了我的调试器。上面的逻辑就算不抛出异常也不行。

【问题讨论】:

  • 我不完全理解您在寻找什么。 cowIdxs 上没有循环,那么您如何比较所有内容?我也没有看到 score 方法,当你让它听起来像是某种计算时,我会预料到的。也没有关于什么是“最好成绩”的比较。您只需将它们加在一起即可。
  • @Aldert 没有分数方法,因为分数是在相似度矩阵中预先计算的(正如我在问题中提到的,并且方法签名很明显)。谢谢。

标签: java algorithm


【解决方案1】:

主要问题是,即使我在跟踪使用过的元素/坐标,我仍在查询它们。在这里,我决定采取不同的方法来实现这一目标:

public static double rankBySimilarity(Array2DRowRealMatrix simMatrix) {
        Set<Integer> rowIdxs =
            IntStream.range(0, simMatrix.getRowDimension()).boxed().collect(Collectors.toSet());
        Set<Integer> colIdxs =
            IntStream.range(0, simMatrix.getColumnDimension()).boxed().collect(Collectors.toSet());

        List<List<Integer>> coords = new ArrayList<>(Sets.cartesianProduct(rowIdxs, colIdxs));
        List<Integer> setA = new ArrayList<>();
        List<Integer> setB = new ArrayList<>();

        Map<List<Integer>, Double> scores = new HashMap<>();
        coords.forEach(c -> scores.put(c, simMatrix.getEntry(c.get(0), c.get(1))));
        coords.sort(Comparator.comparing(scores::get).reversed());

        double score = 0;
        int requiredMet = 0;
        int required = Math.min(rowIdxs.size(), colIdxs.size());
        for (List<Integer> coord : coords) {
            int x = coord.get(0);
            int y = coord.get(1);

            if (!setA.contains(x) && !setB.contains(y)) {
                setA.add(x);
                setB.add(y);
                score += scores.get(coord);
                requiredMet += 1;
            }
            if (requiredMet == required) {
                break;
            }
        }

        return required == 0 ? 0 : score / required;
    }

【讨论】:

    【解决方案2】:

    听起来你在描述经典的Assignment Problem

    问题实例有许多代理和许多任务。可以分配任何代理来执行任何任务,产生的成本可能会因代理任务分配而异。要求执行尽可能多的任务,每个任务最多分配一个代理,每个代理最多分配一个任务,以使分配的总成本最小化。

    您有一堆要分配给不同任务(列)的代理(行),两者之间的关系是一对一的。您想最小化成本(最大化您的利润/得分)。

    解决此问题的一种方法是使用Hungarian Algorithm

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-10-28
      • 1970-01-01
      • 1970-01-01
      • 2010-09-10
      • 1970-01-01
      • 2010-11-03
      相关资源
      最近更新 更多