Numpy - 如何按降序排序值/键对数组

-1 投票
3 回答
4276 浏览
提问于 2025-04-17 20:28

我在研究一个问题,链接在这里:如何快速对多个值和权重的项目进行排名。我想出了一个解决方案,但还有两个问题没有解决:

import numpy as np

# set up values
keys = np.array([
    ['key1'],
    ['key2'],
    ['key3']
])
values = np.matrix([
    [1.1, 1.2, 1.3, 1.4],
    [2.1, 2.2, 2.3, 2.4],
    [3.1, 3.2, 3.3, 3.4]
])
weights = np.matrix([10., 20., 30., 40.]).transpose()

# crunch the numbers
res = values * weights

# combine results with labels
items = np.hstack((np.array(res), keys))

# !First problem - .hstack has promoted the first column from float64 to S4:
# array([['130.', 'key1'],
#        ['230.', 'key2'],
#        ['330.', 'key3']], 
#       dtype='|S4')
# How can I force it to stay numeric?

items.sort(reverse=True)   # doesn't work, no 'reverse' argument

# !Second problem - how to sort the array in descending order?

3 个回答

0

感谢@ondro和@unutbu,最后我得到了这个结果:

import numpy as np

# set up values
keys = np.array(['key1', 'key2', 'key3'])
values = np.array([
    [1.1, 1.2, 1.3, 1.4],    # values1_x
    [2.1, 2.2, 2.3, 2.4],    # values2_x
    [3.1, 3.2, 3.3, 3.4]     # values3_x
])
weights = np.array([10., 20., 30., 40.])

# crunch the numbers
res = np.dot(values, -weights)   # negative of weights!

order = res.argsort(axis=0)  # sorting on negative value gives
                             # same order as reverse-sort; there does
                             # not seem to be any way to reverse-sort
                             # directly
sortedkeys = keys[order].tolist()

这个结果返回了 ['key3', 'key2', 'key1'] (这些是键,按照值和权重的点积反向排序的)。

2

你可以把 reskeys 合并成一个结构化的数组:

import numpy.lib.recfunctions as recfunctions
items = recfunctions.merge_arrays([res,keys])

因为 np.sort 没有 reverse=True 这个选项,所以我觉得你能做的最好的办法就是把返回的数组反转一下,比如用 items[::-1],或者直接取 res 的负值:

import numpy as np
import numpy.lib.recfunctions as recfunctions

# set up values
keys = np.array([
    ['key1'],
    ['key2'],
    ['key3']
])
values = np.matrix([
    [1.1, 1.2, 1.3, 1.4],
    [2.1, 2.2, 2.3, 2.4],
    [3.1, 3.2, 3.3, 3.4]
])
weights = np.matrix([10., 20., 30., 40.]).transpose()

# crunch the numbers
res = values * weights

# combine results with labels
res = np.asarray(-res)
items = recfunctions.merge_arrays([res,keys])
items.dtype.names = ['res', 'key']
items.sort(order=['res'])
print(items)

这样会得到:

[(-330.0, 'key3') (-230.0, 'key2') (-130.0, 'key1')]

需要注意的是,refunctions.merge_arrays 只是一个方便的 Python 函数。它使用了 zipnp.fromiter。如果能避免把 reskeys 合并,而是用 argsort 找到排序 res 的索引,然后用这些索引来重新排列 keys,那样会快得多:

import numpy as np

# set up values
keys = np.array([
    ['key1'],
    ['key2'],
    ['key3']
])
values = np.matrix([
    [1.1, 1.2, 1.3, 1.4],
    [2.1, 2.2, 2.3, 2.4],
    [3.1, 3.2, 3.3, 3.4]
])
weights = np.matrix([10., 20., 30., 40.]).transpose()

# crunch the numbers
res = values * weights

# combine results with labels
res = np.squeeze(np.asarray(res))
idx = np.argsort(res)[::-1]
print(keys[idx])
print(res[idx])

这样会得到:

[['key3']
 ['key2']
 ['key1']]
[ 330.  230.  130.]
1

你可以使用numpy数组的argsort方法来获取一个数组的排序索引,这个索引可以用来对另一个数组进行排序。

import numpy as np

# set up values
keys = np.array([
    ['key1'],
    ['key2'],
    ['key3']
])
values = np.array([
    [1.1, 1.2, 1.3, 1.4],
    [2.1, 2.2, 2.3, 2.4],
    [3.1, 3.2, 3.3, 3.4]
])
weights = np.array([10., 20., 30., 40.])

# crunch the numbers
res = np.dot(values, weights)

sortedkeys = keys[res.argsort(axis=0)[::-1]]

撰写回答