根据元素之间的配对关系对列表进行排序

6
给定一个元素列表,比如 [1,2,3,4],以及它们之间的配对关系,比如
[[0,  0.5, 1,  0.1]
 [0.5, 0,  1,  0.9]
 [ 1,  1,  0,  0.2]
 [0.1, 0.9, 0.2, 0]]

对于熟悉图论的人来说,这基本上是一个邻接矩阵

最快的方法是如何排序列表,使得列表中的距离与节点之间的关联度最相关,即具有高关联度的节点对应该彼此靠近。

是否有一种方法可以做到这一点(即使使用贪心算法也可以)而不会过多涉及MDSordination理论?

作为额外问题

请注意,某些节点之间的关联可以完全表示,例如对于列表[1,2,3]和节点之间的关联:

[[0, 0, 1]
 [0, 0, 1]
 [1, 1, 0]]

完美的顺序应该是[1,3,2]。但有些组织无法实现,比如这个:
[[0, 1, 1]
 [1, 0, 1]
 [1, 1, 0]]

任何顺序都是一样好/坏的。

有没有办法判断排序的质量?就是它如何很好地代表成对关系?


1
如果您同意的话,可以在 [cs.se] 上获得更好的答案。请标记并请求管理员迁移。 - AakashM
那么你的度量/优化目标究竟是什么?(例如L1/L2误差)? - sascha
最快的执行时间还是最快的实现时间? - David Eisenstat
@sascha,你说得对,你的例子是可行的。解决我的问题的方法是启发式算法,可以有效地最小化二次损失。我只是想指出,度量标准不是事先定义好的,因为你可以使用任何度量标准(甚至是非适当的度量标准,如余弦距离)将图嵌入到向量空间中。 - j-i-l
1
我编写了一个O(c * n^2 + n * log(n))的一维平衡求解器,它具有吸引力。它有可能给出一个可接受的近似值。 - Louis Ricci
显示剩余4条评论
1个回答

1
这是一个轻度测试过的算法,它采用邻接矩阵,按出现顺序设置元素/节点,然后尝试找到平衡状态。由于这是1d,我选择了一个非常简单的吸引力公式。也许添加排斥力会改善它。
/*
 * Sort the nodes of an adjacency matrix
 * @return {Array<number>} sorted list of node indices
 */
function sort1d(mat) {
    var n = mat.length;
    // equilibrium total force threshold
    var threshold = 1 / (n * n);
    var map = new Map(); // <index, position>
    // initial positions
    for(var i = 0; i < n; i++) {
        map.set(i, i);
    }
    // find an equilibrium (local minima)
    var prevTotalForce;
    var totalForce = n * n;
    do {
        prevTotalForce = totalForce;
        totalForce = 0;      
        for(var i = 0; i < n; i++) {
            var posi = map.get(i);
            var force = 0;
            for(var j = i + 1; j < n; j++) {
                var posj = map.get(j);
                var weight = mat[i][j];
                var delta = posj - posi;
                force += weight * (delta / n);
            }
            // force = Sum[i, j=i+1..n]( W_ij * ( D_ij / n )
            map.set(i, posi + force);
            totalForce += force;
        }
        console.log(totalForce, prevTotalForce);
    } while(totalForce < prevTotalForce && totalForce >= threshold);
    var list = [];
    // Map to List<[position, index]>
    map.forEach(function(v, k) { list.push([v, k]); });
    // sort list by position
    list.sort(function(a, b) { return a[0] - b[0]; });
    // return sorted indices
    return list.map(function(vk) { return vk[1]; });
}

var mat = [
    [0,  0.5, 1,  0.1],
    [0.5, 0,  1,  0.9],
    [1,  1,  0,  0.2],
    [0.1, 0.9, 0.2, 0]
];
var mat2 = [
    [0, 1, 1],
    [1, 0, 1],
    [1, 1, 0]
];
console.log(sort1d(mat)); // [2, 0, 1, 3]
console.log(sort1d(mat2)); // [0, 1, 2]

很酷,我一旦有时间就会仔细看看它。原则上,如果您的约束是只有一个节点可以占据列表中的一个插槽,那么这个约束实际上已经是一种排斥力(尽管只在局部起作用的非常奇怪的排斥力)。我想知道是否有比O(n^2)更快的方法来完成这个任务... - j-i-l
@jojo - 我将节点位置初始化为它们的整数索引,而不是像二维力导向显示中使用随机定位,这可能会改善结果。当施加力时,新位置是实数,因此它们只是数字线上的点,在最后的排序步骤中才成为数组中的插槽。更快的时间复杂度可能意味着更不准确的近似,也许可以通过创建 n 个列表,每个列表按相应的邻接矩阵行排序,然后将这些列表合并来实现。 - Louis Ricci
1
这里有一个初始化的想法:找到图的最小生成树(由于您有亲和力而不是距离,因此必须稍微调整MST成本函数)。然后,您可以在MST上迭代进行初始放置。要迭代树节点(可能具有任意数量的子节点),请迭代其一半的子节点,然后产生节点本身,然后迭代其余的子节点。 - Jerry Federspiel
@JerryFederspiel - 老实说,就我所知,这个一维版本甚至不需要最优起始位置才能收敛于一个答案。我并不确定如何以100%的准确性解决这个问题,可能需要解一组线性方程(或不等式),其中变量是最终列表的索引,而不等式则是各个顶点之间的权重。 - Louis Ricci
是的,它不应该需要最优位置来开始。我认为这可能会减少迭代次数,但我还没有测试过或做任何事情。感觉真正的解决方案应该接近于对MST进行顺序迭代......但这可能是因为我在亲和力中有一些隐含的“好处”假设,这些假设并不总是成立。即使在数据不好的情况下始终找到最佳解也可能与暴力搜索渐进等价。 - Jerry Federspiel
@JerryFederspiel,你关于特定配置趋近于暴力计算的时间尺度收敛的看法可能是正确的。至少在我看来,这不是一个没有好的解决方案的问题。然而,我相当有信心有一些贪心的方法可以得到一个可接受的解决方案。但是,诚实地说,我不知道这样的贪心方法应该是什么样子的。 - j-i-l

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接