在Python中映射数字数组以有效地进行排序

在Python中映射数字数组以有效地进行排序,python,arrays,numpy,Python,Arrays,Numpy,嗨,我正在尝试将一组数字映射到它们的等级。例如[2,5,3]将变成[0,2,1] 我目前正在使用np.where查找数组中的秩,但这需要很长时间,因为我必须对一个非常大的数组(超过200万个数据点)执行此操作 如果有人对我如何做到这一点有任何建议,我将不胜感激 [编辑]这是更改特定行的代码当前的样子: def change_nodes(row): a = row new_a = node_map[node_map[:,1] == a][0][0] return new_a [编辑

嗨,我正在尝试将一组数字映射到它们的等级。例如[2,5,3]将变成[0,2,1]

我目前正在使用np.where查找数组中的秩,但这需要很长时间,因为我必须对一个非常大的数组(超过200万个数据点)执行此操作

如果有人对我如何做到这一点有任何建议,我将不胜感激

[编辑]这是更改特定行的代码当前的样子:

def change_nodes(row): 
  a = row
  new_a = node_map[node_map[:,1] == a][0][0]
  return new_a
[编辑2]重复的数字还应具有相同的排名

[编辑3]此外,唯一数字在排名中只应计算一次。例如,这个列表的排名[2,3,3,4,5,7,7,7,7,8,1]是:

{1:0,2:1,3:2,4:3,5:4,7:5,8:6}

您想要使用的是:


有关调整领带处理方式的想法,请参阅及其答案。

我有一个仅使用香草Python的变体:

a = [2,5,3]
aSORT = list(a)
aSORT.sort()
for x in aSORT:
    a[a.index(x)] = aSORT.index(x)
print(a)

在我的测试中,这里发布的
numpy
版本花了0.1406秒对列表进行排序
[2,5,3,62,5,2,51000100,-1,-9]
,而我的方法只有0.0154秒。

这里是一个有效的解决方案,并与使用
索引的解决方案进行了比较(
索引
解决方案也不正确,添加了(编辑3)问题限制)

比较结果

>>> d = np.arange(1000)
>>> random.shuffle(d)
>>> %timeit rank1(d)
100 loops, best of 3: 1.97 ms per loop
>>> %timeit rank2(d)
1 loops, best of 3: 226 ms per loop

>>> d = np.arange(10000)
>>> random.shuffle(d)
>>> %timeit rank1(d)
10 loops, best of 3: 32 ms per loop
>>> %timeit rank2(d)
1 loops, best of 3: 24.4 s per loop

>>> d = np.arange(100000)
>>> random.shuffle(d)
>>> %timeit rank1(d)
1 loops, best of 3: 433 ms per loop

>>> d = np.arange(2000000)
>>> random.shuffle(d)
>>> %timeit rank1(d)
1 loops, best of 3: 11.2 s per loop

index
解决方案的问题是时间复杂度是O(n^2)。我的解决方案的时间复杂度是O(n lg n),即排序时间。

您看过
list.sort()
list.index()吗
?谢谢,np.argsort正是我所需要的!对不起,我还想补充一点,如果列表中重复了一个数字,它每次都需要具有相同的排名。请参阅我的解决方案,它在这些情况下也有效。实际上
np.argsort()
并没有执行OP真正要求的操作。它说它返回将对数组进行排序的索引,而不是数组元素的列组数组。这里的
[2,5,3]
示例工作原理相同,并返回
[0,2,1]
,但如果示例是
[5,2,3]
np.argsort()
将返回
[1,2,0]
,而不是列组数组
[2,0,1]
@StardustGogeta的答案在本例中是正确的。第3行不应该是
x=np.argsort(x)
?@StardustGogeta不是出于我的目的,不。
x.argsort()
np.argsort(x)相同
。我不想用排序后的参数替换
x
。我只想在屏幕上显示排序后的参数,以表明答案是正确的。我可以想象,这个答案的用户会希望执行类似
ranks=x.argsort()的操作
。好的,我明白你的意思。等等,rank1实际上只是返回原始列表?抱歉,这是复制代码时的一个输入错误。我已修复了它。我还想获得排名,以便一个排名的多个副本不会影响下一个排名。因此[2,3,3,4,1]将返回[1,2,2,3,0],而不是[1,2,2,4,0]就像这段代码一样。你知道我如何调整它使它返回[1,2,2,3,0]?编辑你的答案,举个例子,我会尝试更改代码。
import numpy as np

def rank1(x):
    # Sort values i = 0, 1, 2, .. using x[i] as key
    y = sorted(range(len(x)), key = lambda i: x[i])
    # Map each value of x to a rank. If a value is already associated with a
    # rank, the rank is updated. Iterate in reversed order so we get the
    # smallest rank for each value.
    rank = { x[y[i]]: i for i in xrange(len(y) -1, -1 , -1) }
    # Remove gaps in the ranks
    kv = sorted(rank.iteritems(), key = lambda p: p[1])
    for i in range(len(kv)):
        kv[i] = (kv[i][0], i)
    rank = { p[0]: p[1] for p in kv }
    # Pre allocate a array to fill with ranks
    r = np.zeros((len(x),), dtype=np.int)
    for i, v in enumerate(x):
        r[i] = rank[v]
    return r

def rank2(x):
    x_sorted = sorted(x)
    # creates a new list to preserve x
    rank = list(x)
    for v in x_sorted:
        rank[rank.index(v)] = x_sorted.index(v)
    return rank
>>> d = np.arange(1000)
>>> random.shuffle(d)
>>> %timeit rank1(d)
100 loops, best of 3: 1.97 ms per loop
>>> %timeit rank2(d)
1 loops, best of 3: 226 ms per loop

>>> d = np.arange(10000)
>>> random.shuffle(d)
>>> %timeit rank1(d)
10 loops, best of 3: 32 ms per loop
>>> %timeit rank2(d)
1 loops, best of 3: 24.4 s per loop

>>> d = np.arange(100000)
>>> random.shuffle(d)
>>> %timeit rank1(d)
1 loops, best of 3: 433 ms per loop

>>> d = np.arange(2000000)
>>> random.shuffle(d)
>>> %timeit rank1(d)
1 loops, best of 3: 11.2 s per loop