`numpy.nanpercentile` 非常慢

Posted

技术标签:

【中文标题】`numpy.nanpercentile` 非常慢【英文标题】:`numpy.nanpercentile` is extremely slow 【发布时间】:2020-02-01 08:31:53 【问题描述】:

numpy.nanpercentile 非常慢。 所以,我想用cupy.nanpercentile;但是还没有实现cupy.nanpercentile。 有人有解决办法吗?

【问题讨论】:

这个问题需要更多信息才能很好地回答。你的数据是什么样的?你能过滤掉空值吗?慢具体是什么意思?等等。 @NickBecker 我的数据是二维数组。我必须跨列轴计算 nanpercentile。 nan 值随机分布在数组中,大约 10% 是 nan。慢意味着运行时间需要几天而不是几个小时。 谢谢。您能否发布一个小示例数组来捕获数据的关键属性/性质? 【参考方案1】:

我的数据集也遇到了 np.nanpercentile 非常慢的问题。我找到了一个可以让你使用标准 np.percentile 的 wokraround。它还可以应用于许多其他库。

这个应该可以解决您的问题。而且它的运行速度也比 np.nanpercentile 快很多:

arr = np.array([[np.nan,2,3,1,2,3],
                [np.nan,np.nan,1,3,2,1],
                [4,5,6,7,np.nan,9]])

mask = (arr >= np.nanmin(arr)).astype(int)

count = mask.sum(axis=1)
groups = np.unique(count)
groups = groups[groups > 0]

p90 = np.zeros((arr.shape[0]))
for g in range(len(groups)):
    pos = np.where (count == groups[g])
    values = arr[pos]
    values = np.nan_to_num (values, nan=(np.nanmin(arr)-1))
    values = np.sort (values, axis=1)
    values = values[:,-groups[g]:]
    p90[pos] = np.percentile (values, 90, axis=1)

因此,它不是使用 nans 获取百分位数,而是根据有效数据的数量对行进行排序,并将这些行的百分位数分开。然后将所有内容重新组合在一起。这也适用于 3D 数组,只需添加 y_pos 和 x_pos 而不是 pos。并注意您计算的是哪个轴。

【讨论】:

【参考方案2】:
def testset_gen(num):
    init=[]
    for i in range (num):
        a=random.randint(65,122) # Dummy name
        b=random.randint(1,100) # Dummy value: 11~100 and 10% of nan
        if b<11:
            b=np.nan # 10% = nan
        init.append([a,b])
    return np.array(init)

np_testset=testset_gen(30000000) # 468,751KB

def f1_np (arr, num):
    return np.percentile (arr[:,1], num)
# 55.0, 0.523902416229248 sec

打印 (f1_np(np_testset[:,1], 50))

def cupy_nanpercentile (arr, num):
    return len(cp.where(arr > num)[0]) / (len(arr) - cp.sum(cp.isnan(arr))) * 100
    # 55.548758317136446, 0.3640251159667969 sec
    # 43% faster
    # If You need same result, use int(). But You lose saved time.

打印 (cupy_nanpercentile(cp_testset[:,1], 50))

我无法想象测试结果需要几天时间。用我的电脑,似乎有 1 万亿行数据或更多。因此,由于资源不足,我无法重现相同的问题。

【讨论】:

【参考方案3】:

这是一个使用 numba 的实现。编译后它比 numpy 版本快 7 倍以上。

现在它设置为沿第一个轴取百分位数,但可以轻松更改。

@numba.jit(nopython=True, cache=True)
def nan_percentile_axis0(arr, percentiles):
    """Faster implementation of np.nanpercentile
    
    This implementation always takes the percentile along axis 0.
    Uses numba to speed up the calculation by more than 7x.

    Function is equivalent to np.nanpercentile(arr, <percentiles>, axis=0)

    Params:
        arr (np.array): Array to calculate percentiles for
        percentiles (np.array): 1D array of percentiles to calculate

    Returns:
        (np.array) Array with first dimension corresponding to
            values as passed in percentiles

    """
    shape = arr.shape
    arr = arr.reshape((arr.shape[0], -1))
    out = np.empty((len(percentiles), arr.shape[1]))
    for i in range(arr.shape[1]):
        out[:,i] = np.nanpercentile(arr[:,i], percentiles)
    shape = (out.shape[0], *shape[1:])
    return out.reshape(shape)

【讨论】:

以上是关于`numpy.nanpercentile` 非常慢的主要内容,如果未能解决你的问题,请参考以下文章

由于通知轮询,页面加载速度非常慢

为啥使用 Dataflow 写入 Bigquery 非常慢?

BrowserSync 非常慢

为啥 Spark Mllib KMeans 算法非常慢?

非常非常慢的 Excel 宏

wxGraphicsContext 在 Windows 上非常慢