无法理解numpy argpartition输出

时间:2017-02-12 05:27:55

标签: python arrays numpy

我试图从numpy使用arpgpartition,但似乎出现了问题,我似乎无法弄明白。以下是发生的事情:

这些是排序数组[u'Location: New Delhi / Safdarjung', u'Current Time: Feb 12, 2017 at 10:29:52 am', u'Latest Report: Feb 12, 2017 at 8:30 am', u'Visibility: 1 km', u'Pressure: 102.12 kPa', u'Humidity: 95%', u'Dew Point: 10 \uc9f8C']

的前5个元素
norms

但是当我使用np.sort(norms)[:5] array([ 53.64759445, 54.91434479, 60.11617279, 64.09630585, 64.75318909], dtype=float32)

indices_sorted = np.argpartition(norms, 5)[:5]

当我认为我应该得到与排序数组相同的结果?

当我使用3作为参数norms[indices_sorted] array([ 60.11617279, 64.09630585, 53.64759445, 54.91434479, 64.75318909], dtype=float32)

时,它可以正常工作
indices_sorted = np.argpartition(norms, 3)[:3]

这对我来说没有多大意义,希望有人可以提供一些见解?

编辑:将这个问题改为argpartition是否保留k个分区元素的顺序更有意义。

3 个答案:

答案 0 :(得分:14)

我们需要使用按排序顺序保存的索引列表,而不是将第k个参数作为标量。因此,要保持第一个5元素的排序性质,而不是np.argpartition(a,5)[:5],只需执行 -

np.argpartition(a,range(5))[:5]

这是一个让事情变得清晰的示例 -

In [84]: a = np.random.rand(10)

In [85]: a
Out[85]: 
array([ 0.85017222,  0.19406266,  0.7879974 ,  0.40444978,  0.46057793,
        0.51428578,  0.03419694,  0.47708   ,  0.73924536,  0.14437159])

In [86]: a[np.argpartition(a,5)[:5]]
Out[86]: array([ 0.19406266,  0.14437159,  0.03419694,  0.40444978,  0.46057793])

In [87]: a[np.argpartition(a,range(5))[:5]]
Out[87]: array([ 0.03419694,  0.14437159,  0.19406266,  0.40444978,  0.46057793])

请注意argpartition在性能方面有意义,如果我们想要获得一小部分元素的排序索引,让我们说k元素的数量,这只是总数的一小部分元素数量。

让我们使用更大的数据集并尝试获取所有元素的排序索引,以使上述要点清晰明了 -

In [51]: a = np.random.rand(10000)*100

In [52]: %timeit np.argpartition(a,range(a.size-1))[:5]
10 loops, best of 3: 105 ms per loop

In [53]: %timeit a.argsort()
1000 loops, best of 3: 893 µs per loop

因此,要对所有元素进行排序,np.argpartition不是最佳选择。

现在,假设我希望只使用该大数据集获得前5个元素的排序索引,并保留其中的顺序 -

In [68]: a = np.random.rand(10000)*100

In [69]: np.argpartition(a,range(5))[:5]
Out[69]: array([1647,  942, 2167, 1371, 2571])

In [70]: a.argsort()[:5]
Out[70]: array([1647,  942, 2167, 1371, 2571])

In [71]: %timeit np.argpartition(a,range(5))[:5]
10000 loops, best of 3: 112 µs per loop

In [72]: %timeit a.argsort()[:5]
1000 loops, best of 3: 888 µs per loop

非常有用!

答案 1 :(得分:5)

鉴于直接排序子集的任务(顶部 k ,排序顺序中首先是最重要的意义),有两个内置解决方案:argsortargpartition cf. @Divakar的回答。

然而,如果表现是一个考虑因素,那么它可能(取决于数据的大小和感兴趣的子集)非常值得抵制单线"的诱惑,再投资一次并在argsort

的输出上应用argpartition
>>> def top_k_sort(a, k):
...     return np.argsort(a)[:k]
...
>>> def top_k_argp(a, k):
...     return np.argpartition(a, range(k))[:k]
...
>>> def top_k_hybrid(a, k):
...     b = np.argpartition(a, k)[:k]
...     return b[np.argsort(a[b])]

>>> k = 100
>>> timeit.timeit('f(a,k)', 'a=rng((100000,))', number = 1000, globals={'f': top_k_sort, 'rng': np.random.random, 'k': k})
8.348663672804832
>>> timeit.timeit('f(a,k)', 'a=rng((100000,))', number = 1000, globals={'f': top_k_argp, 'rng': np.random.random, 'k': k})
9.869098862167448
>>> timeit.timeit('f(a,k)', 'a=rng((100000,))', number = 1000, globals={'f': top_k_hybrid, 'rng': np.random.random, 'k': k})
1.2305558240041137

argsort是O(n log n),范围参数的argpartition似乎是O(nk)(?),argpartition + argsort是O( n + k log k)

因此,在一个有趣的制度 n >> k >> 1混合方法预计最快

答案 2 :(得分:5)

让我们以一种简化的方式来描述 partition 方法,该方法有助于大量了解 argpartition

enter image description here

下面的示例中,如果我们执行 C = numpy.argpartition(A,3),C将是获取B中每个元素相对于A数组的位置的结果数组。即:

Idx(z) = index of element z in array A

then C would be

C = [ Idx(B[0]), Idx(B[1]), Idx(B[2]), Idx(X), Idx(B[4]), ..... Idx(B[N]) ]

如前所述,该方法非常有用,当您有一个巨大的数组并且只对选定的一组有序元素感兴趣,而不对整个数组感兴趣时,该方法非常方便。

相关问题