簡體   English   中英

找到兩個 collections 之間的最高平均相似度/距離的有效方法是什么?

[英]What is an efficient way to find the highest average similarity/distance between two collections?

問題:

假設我有集合A和集合B的大小不一定相同。

然后我想為A中的每個aB中的每個b找到一組得分最高的對(a, 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 並單步調試了我的調試器。 即使不拋出異常,上述邏輯也不起作用。

主要問題是,即使我在跟蹤使用過的元素/坐標,我仍在查詢它們。 在這里,我決定采用不同的方法來實現這一目標:

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;
    }

聽起來您在描述經典的作業問題

問題實例有許多代理和許多任務。 可以分配任何代理來執行任何任務,產生的成本可能會因代理任務分配而異。 要求執行盡可能多的任務,每個任務最多分配一個代理,每個代理最多分配一個任務,以使分配的總成本最小化。

您有一堆要分配給不同任務(列)的代理(行),兩者之間的關系是一對一的。 你想最小化成本(最大化你的利潤/分數)。

解決此問題的一種選擇是使用Hungarian Algorithm

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM