我们假设我有一个矩阵,其中每列与一个值相关联。例如:
A = [[ 7.41, 5.44, 4.75, 0.35, 6.50],
[ 9.59, 5.68, 8.72, 7.88, 5.04],
[ 3.61, 2.79, 3.36, 4.05, 5.81],
[ 3.35, 4.52, 0.35, 5.47, 3.35],
[ 8.69, 3.79, 9.86, 1.90, 7.80]]
和第0列,第1列,第2列,第3列和第4列分别具有值C = [3, 3, 3, 2, 3]
。
现在,我想根据值A
对它们进行排序,即具有最高值的列是第一列,等等。我会得到:
S = sort C in decreasing order
S = [4, 2, 1, 0, 3]
但是C
中存在许多联系,所以我需要在第一个最小值时打破这些联系。如果总是有关系,请将它们分解为最小值,等等。否则,任意断开关系。
在我的示例中,我应该断开列4, 2, 1
和0
之间的联系,因为它们在C
中具有相同的值。 (注意。列3
是最后一个,因为它具有最低值并且是唯一的。)因此,让我们看一下[0, 1, 2, 4]
列中的第i个最小值。
列[0, 1, 2, 4]
中的第一个最小值为M1 = [3.35, 2.79, 0.35, 3.35]
,第二个最小值为M2 = [3.61, 3.79, 3.36, 5.04]
。 (在这个例子中,我们只需要查看第二个最小值。)我们有:
2
在M1
中具有最小值,它首先出现。2
列之后,列1
,因为它具有第二个最小值。0
和列4
具有相同的第一个最小值。我们必须看到他们的第二个最小值M2
。由于3.61<5.04
,列0
位于列4
之前。 因此最终排序的列是
Final = [2, 1, 0, 4, 3]
如何在Python中实现这种排序?
答案 0 :(得分:2)
按降序值和已排序列对列进行排序。这样,列将首先按其最小值进行比较,将第二个最小值进行比较,依此类推:
# transpose to list of columns
a_trans = list(zip(*A)) # Py3
a_trans = zip(*A) # Py2
# zip columns with indeces and values
cols_c = list(zip(range(len(C)), C, a_trans)) # Py3
cols_c = zip(range(len(C)), C, a_trans) # Py2
# sort by desc value and sorted column
cols_c.sort(key=lambda x: (-x[1], sorted(x[2])))
现在您可以构建已排序的原始矩阵:
# extract columns and transpose back to rows
A_sort = list(map(list, zip(*(c for i, val, c in cols_c)))) # Py3
A_sort = map(list, zip(*(c for i, val, c in cols_c))) # Py2
[[4.75, 5.44, 7.41, 6.5, 0.35],
[8.72, 5.68, 9.59, 5.04, 7.88],
[3.36, 2.79, 3.61, 5.81, 4.05],
[0.35, 4.52, 3.35, 3.35, 5.47],
[9.86, 3.79, 8.69, 7.8, 1.9]]
或只是有序的indeces:
indeces = [i for i, val, c in cols_c]
[2, 1, 0, 4, 3]
如果你不介意有一个迭代器而不是元组或某事。同样,你可以省略一些演员电话。
一些参考文献:
答案 1 :(得分:1)
您可以根据列表C
中给出的权重进行排序,然后使用heapq.nsmallest
打破每列中至少两个最小值的关系:
import heapq
import pprint
A = [[ 7.41, 5.44, 4.75, 0.35, 6.50],
[ 9.59, 5.68, 8.72, 7.88, 5.04],
[ 3.61, 2.79, 3.36, 4.05, 5.81],
[ 3.35, 4.52, 0.35, 5.47, 3.35],
[ 8.69, 3.79, 9.86, 1.90, 7.80]]
C = [3, 3, 3, 2, 3]
A_by_cols = zip(*A) # tranpose A so we can sort by columns
f = sorted(enumerate(A_by_cols),
key=lambda x: (-C[x[0]], heapq.nsmallest(2, x[1])]))
pprint.pprint(f)
# [(2, (4.75, 8.72, 3.36, 0.35, 9.86)),
# (1, (5.44, 5.68, 2.79, 4.52, 3.79)),
# (0, (7.41, 9.59, 3.61, 3.35, 8.69)),
# (4, (6.5, 5.04, 5.81, 3.35, 7.8)),
# (3, (0.35, 7.88, 4.05, 5.47, 1.9))]
然后,您可以通过剥离索引和转置来重新创建列表的最终列表:
A_final = list(zip(*(x for _, x in f)))
pprint.pprint(A_final)
[(4.75, 5.44, 7.41, 6.5, 0.35),
(8.72, 5.68, 9.59, 5.04, 7.88),
(3.36, 2.79, 3.61, 5.81, 4.05),
(0.35, 4.52, 3.35, 3.35, 5.47),
(9.86, 3.79, 8.69, 7.8, 1.9)]