Numpy:获取数组X的最低N个元素,仅考虑其索引不是另一个数组Y

时间:2017-03-10 09:24:13

标签: python arrays numpy

要获得数组X的最低10个值,我会执行以下操作:

lowest10 = np.argsort(X)[:10]

什么是最有效的方法,避免循环,过滤结果,以便我得到其索引不是另一个数组Y的元素的最低10个值?

例如,如果数组Y是:

[2,20,51]

X [2],X [20]和X [51]不应该被考虑计算最低的10。

3 个答案:

答案 0 :(得分:2)

经过一些基准测试后,我的建议很简单:

交换似乎或多或少总是比屏蔽更快(即使禁止99%的X.)所以使用

的内容。
swap = X[Y]
X[Y] = np.inf

排序很昂贵,因此请使用argpartition并仅排序必要的内容。像

lowest10 = np.argpartition(Xfiltered, 10)[:10]
lowest10 = lowest10[np.argsort(Xfiltered[lowest10])]

以下是一些基准:

import numpy as np
from timeit import timeit

def swap_out():
    global sol

    swap = X[Y]
    X[Y] = np.inf

    sol = np.argpartition(X, K)[:K]
    sol = sol[np.argsort(X[sol])]

    X[Y] = swap

def app1():
    sidx = X.argsort()
    return sidx[~np.in1d(sidx, Y)][:K]

def app2():
    sidx = np.argpartition(X,range(K+Y.size))
    return sidx[~np.in1d(sidx, Y)][:K]

def app3():
    sidx = np.argpartition(X,K+Y.size)
    return sidx[~np.in1d(sidx, Y)][:K]


K = 10    # number of small elements wanted
N = 10000 # size of X
M = 10    # size of Y
S = 10    # number of repeats in benchmark

X = np.random.random((N,))
Y = np.random.choice(N, (M,))

so = timeit(swap_out, number=S)
print(sol)
print(X[sol])
d1 = timeit(app1, number=S)
print(sol)
print(X[sol])
d2 = timeit(app2, number=S)
print(sol)
print(X[sol])
d3 = timeit(app3, number=S)
print(sol)
print(X[sol])

print('pp', f'{so:8.5f}', '  d1(um)', f'{d1:8.5f}', '  d2', f'{d2:8.5f}', '  d3', f'{d3:8.5f}')
# pp  0.00053   d1(um)  0.00731   d2  0.00313   d3  0.00149

答案 1 :(得分:1)

您可以使用numpy.delete();

处理原始数组的子集
lowest10 = np.argsort(np.delete(X, Y))[:10]

由于删除的工作原理是将原始数组切片以保留索引,因此复杂性应该是不变的。

警告:此解决方案使用原始 X 数组的子集(X没有在Y中索引的元素),因此最终结果将是该子集中最低的10个。

答案 2 :(得分:1)

这是一种方法 -

class Box(models.Model):
name = models.CharField(max_length=120, unique=True)

def __str__(self):
    return self.name

class Things(models.Model):
    box = models.ForeignKey(Box)
    name = models.CharField(max_length=120)
    thing_number = models.PositiveIntegerField(default=1)

    def __str__(self):
        return self.name

示例运行 -

sidx = X.argsort()
idx_out = sidx[~np.in1d(sidx, Y)][:10]

或者,为了提高性能,我们可能希望使用# Setup inputs In [141]: X = np.random.choice(range(60), 60) In [142]: Y = np.array([2,20,51]) # For testing, let's set the Y positions as 0s and # we want to see them skipped in o/p In [143]: X[Y] = 0 # Use proposed approach In [144]: sidx = X.argsort() In [145]: X[sidx[~np.in1d(sidx, Y)][:10]] Out[145]: array([ 0, 2, 4, 5, 5, 9, 9, 10, 12, 14]) # Print the first 13 numbers and skip three 0s and # that should match up with the output from proposed approach In [146]: np.sort(X)[:13] Out[146]: array([ 0, 0, 0, 0, 2, 4, 5, 5, 9, 9, 10, 12, 14]) ,就像这样 -

np.argpartition

如果sidx = np.argpartition(X,range(10+Y.size)) idx_out = X[sidx[~np.in1d(sidx, Y)][:10]] 的长度比X大得多,那么这将非常有用。

如果你不关心10索引列表中元素的顺序,为了进一步提升,我们可以简单地将标量长度而不是10数组传递给{{1} }:range

我们可以使用np.argpartition优化np.argpartition(X,10+Y.size),以便再采用一种方法(下一步列出)。

在下面列出了本文所讨论的所有方法 -

np.in1d