numpy的argsort能给出相同等级的相同元素吗?

时间:2016-08-20 22:46:45

标签: python sorting numpy

我想获得每个元素的排名,因此我在argsort中使用numpy

np.argsort(np.array((1,1,1,2,2,3,3,3,3)))
array([0, 1, 2, 3, 4, 5, 6, 7, 8])

它给不同等级的相同元素,我可以得到相同的等级:

array([0, 0, 0, 3, 3, 5, 5, 5, 5])

5 个答案:

答案 0 :(得分:11)

如果您不介意依赖scipy,可以method='min'使用In [14]: a Out[14]: array([1, 1, 1, 2, 2, 3, 3, 3, 3]) In [15]: from scipy.stats import rankdata In [16]: rankdata(a, method='min') Out[16]: array([1, 1, 1, 4, 4, 6, 6, 6, 6])

rankdata

请注意In [17]: rankdata(a, method='min') - 1 Out[17]: array([0, 0, 0, 3, 3, 5, 5, 5, 5]) 将等级开始为1.要从0开始,从结果中减去1:

rankdata(x, method='min') - 1

如果您不想要scipy依赖项,可以使用scipy.stats.rankdata来计算排名。这是一个计算与import numpy as np def rankmin(x): u, inv, counts = np.unique(x, return_inverse=True, return_counts=True) csum = np.zeros_like(counts) csum[1:] = counts[:-1].cumsum() return csum[inv] 相同结果的函数:

In [137]: x = np.array([60, 10, 0, 30, 20, 40, 50])

In [138]: rankdata(x, method='min') - 1
Out[138]: array([6, 1, 0, 3, 2, 4, 5])

In [139]: rankmin(x)
Out[139]: array([6, 1, 0, 3, 2, 4, 5])

In [140]: a = np.array([1,1,1,2,2,3,3,3,3])

In [141]: rankdata(a, method='min') - 1
Out[141]: array([0, 0, 0, 3, 3, 5, 5, 5, 5])

In [142]: rankmin(a)
Out[142]: array([0, 0, 0, 3, 3, 5, 5, 5, 5])

例如,

argsort()

顺便说一句,对argsort()的一次调用不会给出排名。您可以在问题numpy.unique中找到各种排名方法,包括如何使用#Force non-www: RewriteEngine on RewriteCond %{HTTP_HOST} ^www\.YOURDOMAIN\.com [NC] RewriteRule ^(.*)$ http://YOURDOMAIN.com/$1 [L,R=301] 进行排名。

答案 1 :(得分:3)

或者,pandas系列有一个rank方法,可以使用min方法完成您所需的工作:

import pandas as pd
pd.Series((1,1,1,2,2,3,3,3,3)).rank(method="min")

# 0    1
# 1    1
# 2    1
# 3    4
# 4    4
# 5    6
# 6    6
# 7    6
# 8    6
# dtype: float64

答案 2 :(得分:3)

关注绩效,这是一种方法 -

def rank_repeat_based(arr):
    idx = np.concatenate(([0],np.flatnonzero(np.diff(arr))+1,[arr.size]))
    return np.repeat(idx[:-1],np.diff(idx))

对于输入数组中的元素尚未排序的一般情况,我们需要使用argsort()来跟踪位置。所以,我们会有一个修改版本,如此 -

def rank_repeat_based_generic(arr):    
    sidx = np.argsort(arr,kind='mergesort')
    idx = np.concatenate(([0],np.flatnonzero(np.diff(arr[sidx]))+1,[arr.size]))
    return np.repeat(idx[:-1],np.diff(idx))[sidx.argsort()]

运行时测试

测试到目前为止列出的所有方法,以解决大型数据集上的问题。

排序数组案例:

In [96]: arr = np.sort(np.random.randint(1,100,(10000)))

In [97]: %timeit rankdata(arr, method='min') - 1
1000 loops, best of 3: 635 µs per loop

In [98]: %timeit rankmin(arr)
1000 loops, best of 3: 495 µs per loop

In [99]: %timeit (pd.Series(arr).rank(method="min")-1).values
1000 loops, best of 3: 826 µs per loop

In [100]: %timeit rank_repeat_based(arr)
10000 loops, best of 3: 200 µs per loop

未分类的案例:

In [106]: arr = np.random.randint(1,100,(10000))

In [107]: %timeit rankdata(arr, method='min') - 1
1000 loops, best of 3: 963 µs per loop

In [108]: %timeit rankmin(arr)
1000 loops, best of 3: 869 µs per loop

In [109]: %timeit (pd.Series(arr).rank(method="min")-1).values
1000 loops, best of 3: 1.17 ms per loop

In [110]: %timeit rank_repeat_based_generic(arr)
1000 loops, best of 3: 1.76 ms per loop

答案 3 :(得分:0)

我出于相同的目的编写了一个函数。它仅使用纯python和numpy。请看一看。我也发表了评论。

def my_argsort(array):
    # this type conversion let us work with python lists and pandas series
    array = np.array(array)
    # create mapping for unique values
    # it's a dictionary where keys are values from the array and
    # values are desired indices 
    unique_values = list(set(array))
    mapping = dict(zip(unique_values, np.argsort(unique_values)))
    # apply mapping to our array
    # np.vectorize works similar map(), and can work with dictionaries
    array = np.vectorize(mapping.get)(array)
    return array

希望有帮助。

答案 4 :(得分:0)

对于这个问题不需要复杂的解决方案。

> ary = np.sort([1, 1, 1, 2, 2, 3, 3, 3, 3])  # or anything; must be sorted.
> a = np.diff().cumsum(); a
array([0, 0, 1, 1, 2, 2, 2, 2])
> b = np.r_[0, a]; b  # ties get first open rank
array([0, 0, 0, 1, 1, 2, 2, 2, 2]) 
> c = np.flatnonzero(ary[1:] != ary[:-1])
> np.r_[0, 1 + c][b]  # ties get last open rank
array([0, 0, 0, 3, 3, 5, 5, 5])