使用Python/NumPy排列数组中的项目
我有一个数组数组,我想创建另一个数组,代表第一个数组中的每个项目的排名。我正在使用Python和NumPy。使用Python/NumPy排列数组中的项目
例如:
array = [4,2,7,1]
ranks = [2,1,3,0]
下面是我想出的最好方法:
array = numpy.array([4,2,7,1])
temp = array.argsort()
ranks = numpy.arange(len(array))[temp.argsort()]
是否有更好的/更快的方法是避免排序阵列的两倍?在最后一步的左侧
使用切片:
array = numpy.array([4,2,7,1])
temp = array.argsort()
ranks = numpy.empty_like(temp)
ranks[temp] = numpy.arange(len(array))
这样就避免了在最后一步颠倒排列排序的两倍。
使用argsort两次,第一次,以获得阵列的顺序,然后获得排名:
array = numpy.array([4,2,7,1])
order = array.argsort()
ranks = order.argsort()
当与2D(或更高维)阵列处理,一定要传递一个轴参数argsort到顺序在正确的轴上。
请注意,如果数字在您的输入数组中重复(例如'[4,2,7,1,1]'),输出将根据它们的数组位置('[3,2,4,0, 1]') – rcoup 2011-06-08 01:53:34
很好的回答!非常pythonic。 – 2014-04-14 19:00:41
排序两次效率不高。 @Sven Marnach的回答显示了如何通过一次调用'argsort'完成排名。 – 2015-07-13 15:13:12
我试图扩展超过一个维度的数组A的解决方案,假设您逐行处理数组(axis = 1)。
我用循环在行上扩展了第一个代码;大概可以提高
temp = A.argsort(axis=1)
rank = np.empty_like(temp)
rangeA = np.arange(temp.shape[1])
for iRow in xrange(temp.shape[0]):
rank[iRow, temp[iRow,:]] = rangeA
,第二个,以下k.rooijers建议,变为:
temp = A.argsort(axis=1)
rank = temp.argsort(axis=1)
我随机生成400个阵列具有形状(1000,100);第一个代码大约7.5,第二个3.8。
我试过上面的方法,但因为我有很多zeores而失败。是的,即使有浮标,重复项目也可能很重要。
所以我加入了领带检查步骤写了修改1D方案:
def ranks (v):
import numpy as np
t = np.argsort(v)
r = np.empty(len(v),int)
r[t] = np.arange(len(v))
for i in xrange(1, len(r)):
if v[t[i]] <= v[t[i-1]]: r[t[i]] = r[t[i-1]]
return r
# test it
print sorted(zip(ranks(v), v))
我相信这是有效率,因为它可以。
我喜欢k.rooijers的方法,但正如rcoup写的,重复的数字按照数组的位置排列。这对我来说没有好处,所以我修改的版本进行后处理队伍,任何重复的数字合并成一个综合平均等级:
import numpy as np
a = np.array([4,2,7,2,1])
r = np.array(a.argsort().argsort(), dtype=float)
f = a==a
for i in xrange(len(a)):
if not f[i]: continue
s = a == a[i]
ls = np.sum(s)
if ls > 1:
tr = np.sum(r[s])
r[s] = float(tr)/ls
f[s] = False
print r # array([ 3. , 1.5, 4. , 1.5, 0. ])
我希望这可以帮助别人也一样,我试图找到anothers解决这个,但找不到任何...
对于平均排名的矢量化版本,请参见下文。我喜欢np.unique,它真的扩大了代码可以或不可能有效矢量化的范围。除了避免python for循环外,这种方法还可以避免隐含的'a'双循环。
import numpy as np
a = np.array([4,1,6,8,4,1,6])
a = np.array([4,2,7,2,1])
rank = a.argsort().argsort()
unique, inverse = np.unique(a, return_inverse = True)
unique_rank_sum = np.zeros_like(unique)
np.add.at(unique_rank_sum, inverse, rank)
unique_count = np.zeros_like(unique)
np.add.at(unique_count, inverse, 1)
unique_rank_mean = unique_rank_sum.astype(np.float)/unique_count
rank_mean = unique_rank_mean[inverse]
print rank_mean
;我让这个代码产生与其他平均等级代码相同的输出,但是我可以想象一组重复数的最小等级也是一样的。 >>> unique,index,inverse = np.unique(a,True,True) >>> rank_min = rank [index] [inverse] – 2014-01-06 20:47:21
我收到以下错误消息解决方案(numpy 1.7.1): AttributeError:'numpy。' – Fear 2017-07-14 09:33:18
ufunc'对象没有属性'这需要更新版本的numpy;你的是很古老的 – 2017-07-14 10:08:38
使用argsort()两次将做到这一点:
>>> array = [4,2,7,1]
>>> ranks = numpy.array(array).argsort().argsort()
>>> ranks
array([2, 1, 3, 0])
这是[已经提到](http://*.com/a/6266510/786559)之前,你提出了你的答案 – 2017-04-09 16:26:45
这个问题是几年的历史,并接受的答案是伟大的,但我认为下面还是值得一提。如果你不介意scipy
的依赖,你可以使用scipy.stats.rankdata
:
In [22]: from scipy.stats import rankdata
In [23]: a = [4, 2, 7, 1]
In [24]: rankdata(a)
Out[24]: array([ 3., 2., 4., 1.])
In [25]: (rankdata(a) - 1).astype(int)
Out[25]: array([2, 1, 3, 0])
的rankdata
一个很好的功能是,method
参数提供用于处理关系的几个选项。例如,有三个事件20的和两次出现的40 b
:
In [26]: b = [40, 20, 70, 10, 20, 50, 30, 40, 20]
默认的平均等级分配给并列值:
In [27]: rankdata(b)
Out[27]: array([ 6.5, 3. , 9. , 1. , 3. , 8. , 5. , 6.5, 3. ])
method='ordinal'
分配连续的行列:
In [28]: rankdata(b, method='ordinal')
Out[28]: array([ 6., 2., 9., 1., 3., 8., 5., 7., 4.])
method='min'
将绑定值的最小等级分配给所有绑定值:
In [29]: rankdata(b, method='min')
Out[29]: array([ 6., 2., 9., 1., 2., 8., 5., 6., 2.])
请参阅文档字符串了解更多选项。
您的最后一行等同于'ranks = temp.argsort()'。 – 2011-03-12 19:03:58