我正在处理相关矩阵,我想重新排列行和列,使平均相关度最高的列位于中间,第二个最好的列位于中间,第三个列位于中间,以此类推。
在一个例子中,这是原始矩阵
[[ 1. , -0.85240671, 0.93335528, 0.75431679, 0.81586527],
[-0.85240671, 1. , -0.874545 , -0.68551567, -0.8594703 ],
[ 0.93335528, -0.874545 , 1. , 0.7103762 , 0.86104527],
[ 0.75431679, -0.68551567, 0.7103762 , 1. , 0.73345121],
[ 0.81586527, -0.8594703 , 0.86104527, 0.73345121, 1. ]]
理想情况下,新的列/行顺序(使用Python索引)为3, 1, 2,0, 4。所以看起来像
[[1,-.686,.710,.754,.733],
[-.686,1,-.875,-.852,-.859],
[.710,-.875,1,.933,.861],
[.754,-.852,.754,1,.816],
[.733,-.859,.861,.816,1]]
我所知道的排序算法似乎都无法实现我的“对称”目标。我用numpy做矩阵。
有些矩阵不会有奇数维,所以我也希望有一种方法来处理矩阵的偶数维,如果可能的话。任何帮助都会很棒。
最佳答案
我不确定你问题的“确定最大相关性的顺序”部分,但这并不是问题的核心。
我认为,假设数组名为arr
,可以通过
corrs = arr.sum(axis=0)
corr_order = corrs.argsort()[::-1]
但问题的主要部分是按照这个“中间最大”的顺序填充矩阵。必须有一个更优雅的方法,但这就是我在您的列排序减少后获取列顺序的方法:
ndim = arr.shape[0]
inds_orig = list(range(ndim))
inds = []
for _ in range(ndim):
inds.append(inds_orig[(len(inds_orig)-1)//2])
del inds_orig[(len(inds_orig)-1)//2]
inds = np.array(inds)
现在,上面的
ndim=5
将给我们array([2, 1, 3, 0, 4])
这似乎正是你想要的:第一列(最大的)在中间,然后每一个后续的项目在交替的方面。
现在我们需要将这两个数组组合起来,得到原始数组的排序+重排版本。当我们真的想要得到基本索引时,使用数组来索引2D数组会触发奇特的索引。因此,我们需要
np.ix_
将我们的花式指数转换为等效的有效切片指数:res = np.empty_like(arr)
res[np.ix_(inds,inds)] = arr[np.ix_(corr_order,corr_order)]
其结果是
array([[ 1. , 0.7103762 , 0.75431679, 0.73345121, -0.68551567],
[ 0.7103762 , 1. , 0.93335528, 0.86104527, -0.874545 ],
[ 0.75431679, 0.93335528, 1. , 0.81586527, -0.85240671],
[ 0.73345121, 0.86104527, 0.81586527, 1. , -0.8594703 ],
[-0.68551567, -0.874545 , -0.85240671, -0.8594703 , 1. ]])
要检查此矩阵在我的“最大相关”定义中是否正确:
>>> print(res.sum(axis=0))
[ 2.51262853 2.63023175 2.65113063 2.55089145 -2.27193768]
如你所见:最大的在中间,然后一个在左边,然后一个在右边,然后第一个,然后最后一个。
除非我错了,另一个选项可能是左边的invert the sorting permutation,只有右边的索引是用一个索引数组索引到另一个索引数组中的。我不确定这是否比这个方法更清楚,所以我坚持这个方法。