Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/280.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 具有可能重复项的numpy数组的排序_Python_Sorting_Numpy_Scipy - Fatal编程技术网

Python 具有可能重复项的numpy数组的排序

Python 具有可能重复项的numpy数组的排序,python,sorting,numpy,scipy,Python,Sorting,Numpy,Scipy,我有一个浮点/整数的numpy数组,并希望将其元素映射到它们的行列中 如果数组没有重复项,则可以通过以下代码解决此问题 In [49]: a1 Out[49]: array([ 0.1, 5.1, 2.1, 3.1, 4.1, 1.1, 6.1, 8.1, 7.1, 9.1]) In [50]: a1.argsort().argsort() Out[50]: array([0, 5, 2, 3, 4, 1, 6, 8, 7, 9]) 现在我想将此方法扩展到可能存在重复项的数

我有一个浮点/整数的numpy数组,并希望将其元素映射到它们的行列中

如果数组没有重复项,则可以通过以下代码解决此问题

In [49]: a1
Out[49]: array([ 0.1,  5.1,  2.1,  3.1,  4.1,  1.1,  6.1,  8.1,  7.1,  9.1])

In [50]: a1.argsort().argsort()
Out[50]: array([0, 5, 2, 3, 4, 1, 6, 8, 7, 9])
现在我想将此方法扩展到可能存在重复项的数组,以便将重复项映射到相同的值。例如,我想要一个数组

a2 = np.array([0.1, 1.1, 2.1, 3.1, 4.1, 1.1, 6.1, 7.1, 7.1, 1.1])
要映射到

0 1 4 5 6 1 7 8 8 1

0 2 4 5 6 2 7 8.5 8.5 2
在第一种/第二种情况下,如果只应用a2.argsort().argsort(),我们将重复项映射到它们之间的最小/最大秩。 第三个病例只是前两个病例的平均数

有什么建议吗

编辑(效率要求)

在最初的描述中,我忘了提到时间要求。我正在寻找numpy/scipy函数方面的解决方案,这将避免“纯粹的python开销”。为了弄清楚,考虑李察提出的解决方案实际上解决了问题,但速度很慢:

def argsortdup(a1):
  sorted = np.sort(a1)
  ranked = []
  for item in a1:
    ranked.append(sorted.searchsorted(item))
  return np.array(ranked)

In [86]: a2 = np.array([ 0.1,  1.1,  2.1,  3.1,  4.1,  1.1,  6.1,  7.1,  7.1,  1.1])

In [87]: %timeit a2.argsort().argsort()
1000000 loops, best of 3: 1.55 us per loop

In [88]: %timeit argsortdup(a2)
10000 loops, best of 3: 25.6 us per loop

In [89]: a = np.arange(0.1, 1000.1)

In [90]: %timeit a.argsort().argsort()
10000 loops, best of 3: 24.5 us per loop

In [91]: %timeit argsortdup(a)
1000 loops, best of 3: 1.14 ms per loop

In [92]: a = np.arange(0.1, 10000.1)

In [93]: %timeit a.argsort().argsort()
1000 loops, best of 3: 303 us per loop

In [94]: %timeit argsortdup(a)
100 loops, best of 3: 11.9 ms per loop

从上面的分析可以清楚地看出,argsortdup比a.argsort().argsort()慢30-50倍。主要原因是使用python循环和列表。

这里有一个函数,可以返回您想要的输出(在第一种情况下)

基本上,您可以对它进行排序,然后搜索该项所在的索引。假设重复,则应返回第一个实例索引。我用你的a2例子进行了测试

a3 = argsortdup(a2)
屈服

array([0, 1, 4, 5, 6, 1, 7, 8, 8, 1])
“a2测试”:


按照@WarrenWeckesser在评论中的建议升级到最新版本的
scipy
后,
scipy.stats.rankdata
似乎比
scipy.stats.mstats.rankdata
np.searchsorted
都要快,这是在大型阵列上实现这一功能的最快方法

In [1]: import numpy as np

In [2]: from scipy.stats import rankdata as rd
   ...: from scipy.stats.mstats import rankdata as rd2
   ...: 

In [3]: array = np.arange(0.1, 1000000.1)

In [4]: %timeit np.searchsorted(np.sort(array), array)
1 loops, best of 3: 385 ms per loop

In [5]: %timeit rd(array)
10 loops, best of 3: 109 ms per loop

In [6]: %timeit rd2(array)
1 loops, best of 3: 205 ms per loop

使用
unique
bincount
可以做得相当好:

>>> u, v = np.unique(a2, return_inverse=True)
>>> (np.cumsum(np.bincount(v)) - 1)[v]
array([0, 3, 4, 5, 6, 3, 7, 9, 9, 3])
或者,对于最低等级:

>>> (np.cumsum(np.concatenate(([0], np.bincount(v)))))[v]
array([0, 1, 4, 5, 6, 1, 7, 8, 8, 1])
通过提供
bincount
要提供的箱子数量,可以稍微加快速度:

(np.cumsum(np.bincount(v, minlength=u.size)) - 1)[v]

理查德,谢谢你的快速回答。您的函数解决了这个问题,但是我正在寻找执行时间方面更有效的解决方案。我忘了在最初的描述中提到这一点——这是我的错,我很抱歉。有关更多详细信息,请参阅更新的说明。再次感谢您的回复!正确的方法,但如果使用
numpy
更好,您可以做得更好。该函数只是:
np.searchsorted(np.sort(a1),a1)
为什么要与
a.argsort().argsort()进行比较?这并没有给你答案。正确,这并没有给我答案,因为有重复的。但是,我想强调使用numpy函数与使用numpy+纯python循环时的性能差异。差别是巨大的。就我所知,解决方案比Richard提供的更快,我使用“a.argsort().argsort()”:)Richard的答案是正确的,但需要更多的矢量化。见我对他的回答的评论。这将在相当合理的时间内给出答案。请查看
scipy.stats.rankdata
。另外,请查看
pandas
包()中的排名函数。谢谢,您的答案很有用。然而,据我所知,它在内部用纯python实现了逻辑(与Richard提出的非常相似,但处理关系的逻辑要多一点)。因此,它甚至比Richard的解决方案还要慢。但是无论如何,有一个现成的解决方案是好的。@MikhailShevelev——速度取决于数组的大小,尝试一些大的东西,它会比其他两个都好。你可以使用
scipy.stats.rankdata
,它比
scipy.stats.mstats.rankdata
@WarrenWeckesser快——我实际上已经检查过了,但在大型阵列上,它似乎(明显)做得更糟,这有点令人困惑…@root:您使用的是什么版本的scipy?在scipy的最新版本中,
stats.rankdata
是用cython重写的,因此它将比旧的python+numpy版本快得多。非常漂亮的解决方案,在大型阵列上可以正确且非常快速地工作。多谢各位!对@Merlin有什么想法吗?当然,使用
scipy.stats.rankdata
它只是“序数”-“min”。如果出于某种原因不能使用scipy,我的代码也可以工作。回答您的问题。@ecatmur我如何使用您的代码回答我的问题?scipy可以工作,通过查看您的来了解一些东西。@Merlin当然,只需使用我的(第二个)解决方案来替换
rankdata(…,“min”)
argsort().argsort()
技术来替换
rankdata(…,“ordinal”)
。更新了我的答案。
>>> u, v = np.unique(a2, return_inverse=True)
>>> (np.cumsum(np.bincount(v)) - 1)[v]
array([0, 3, 4, 5, 6, 3, 7, 9, 9, 3])
>>> (np.cumsum(np.concatenate(([0], np.bincount(v)))))[v]
array([0, 1, 4, 5, 6, 1, 7, 8, 8, 1])
(np.cumsum(np.bincount(v, minlength=u.size)) - 1)[v]