根据其元素的成对从属关系对列表进行排序
Sort list based on pair-wise affiliation of its elements
给定一个元素列表,比如 [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]]
对于那些熟悉图论的人来说,这基本上是一个邻接矩阵。
什么是最快的排序列表的方法,使得列表中的距离与成对的从属关系最相关,即具有高从属关系的节点对应该彼此靠近。
有没有办法做到这一点(即使是贪心算法也可以)而不用过多地研究 MDS and ordination 理论?
作为奖励问题:
请注意,一些成对的从属关系可以完美地表示,例如列表 [1,2,3]
和成对的从属关系:
[[0, 0, 1]
[0, 0, 1]
[1, 1, 0]]
完美的顺序是 [1,3,2]
。但是有些隶属关系不能,比如这个:
[[0, 1, 1]
[1, 0, 1]
[1, 1, 0]]
任何订单都等同于 good/bad。
有没有办法判断订单的质量?从它代表成对隶属关系的角度来看?
这是一个经过简单测试的算法,它采用邻接矩阵,按出现顺序设置 elements/nodes,然后尝试找到平衡点。因为它是 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]
给定一个元素列表,比如 [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]]
对于那些熟悉图论的人来说,这基本上是一个邻接矩阵。
什么是最快的排序列表的方法,使得列表中的距离与成对的从属关系最相关,即具有高从属关系的节点对应该彼此靠近。
有没有办法做到这一点(即使是贪心算法也可以)而不用过多地研究 MDS and ordination 理论?
作为奖励问题:
请注意,一些成对的从属关系可以完美地表示,例如列表 [1,2,3]
和成对的从属关系:
[[0, 0, 1]
[0, 0, 1]
[1, 1, 0]]
完美的顺序是 [1,3,2]
。但是有些隶属关系不能,比如这个:
[[0, 1, 1]
[1, 0, 1]
[1, 1, 0]]
任何订单都等同于 good/bad。
有没有办法判断订单的质量?从它代表成对隶属关系的角度来看?
这是一个经过简单测试的算法,它采用邻接矩阵,按出现顺序设置 elements/nodes,然后尝试找到平衡点。因为它是 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]