将numpy数组的组名映射到索引的最快方法是什么?

将numpy数组的组名映射到索引的最快方法是什么?,第1张

将numpy数组的组名映射到索引的最快方法是什么? 每组不变的索引数方法1

我们可以执行

dimensionality-reduction
简化
cubes
为一维数组。这是基于将给定的多维数据集数据映射到n维网格上以计算线性索引等效项的方法,该方法将详细讨论here。然后,基于这些线性索引的唯一性,我们可以分离唯一组及其对应的索引。因此,按照这些策略,我们将有一个解决方案,像这样-

N = 4 # number of indices per groupc1D = np.ravel_multi_index(cubes.T, cubes.max(0)+1)sidx = c1D.argsort()indices = sidx.reshape(-1,N)unq_groups = cubes[indices[:,0]]# If you need in a zipped dictionary formatout = dict(zip(map(tuple,unq_groups), indices))

备选方案1: 如果in

cubes
中的整数太大,则可能要这样做
dimensionality-reduction
,以选择范围较小的尺寸作为主轴。因此,对于这些情况,我们可以将缩减步骤修改为get
c1D
,如下所示:

s1,s2 = cubes[:,:2].max(0)+1s = np.r_[s2,1,s1*s2]c1D = cubes.dot(s)
方法#2

接下来,我们可以使用

Cython-powered kd-tree
快速最近邻查找来获取最近邻索引,从而像这样解决我们的情况-

from scipy.spatial import cKDTreeidx = cKDTree(cubes).query(cubes, k=N)[1] # N = 4 as discussed earlierI = idx[:,0].argsort().reshape(-1,N)[:,0]unq_groups,indices = cubes[I],idx[I]

一般情况:每组索引数量可变

我们将对基于argsort的方法进行一些扩展以得到所需的输出,如下所示:

c1D = np.ravel_multi_index(cubes.T, cubes.max(0)+1)sidx = c1D.argsort()c1Ds = c1D[sidx]split_idx = np.flatnonzero(np.r_[True,c1Ds[:-1]!=c1Ds[1:],True])grps = cubes[sidx[split_idx[:-1]]]indices = [sidx[i:j] for (i,j) in zip(split_idx[:-1],split_idx[1:])]# If needed as dict o/pout = dict(zip(map(tuple,grps), indices))

使用1D版本的组

cubes
作为键

我们将使用

cubes
as键组扩展先前列出的方法,以简化字典创建过程并使其高效使用,例如-

def numpy1(cubes):    c1D = np.ravel_multi_index(cubes.T, cubes.max(0)+1) sidx = c1D.argsort()    c1Ds = c1D[sidx]    mask = np.r_[True,c1Ds[:-1]!=c1Ds[1:],True]    split_idx = np.flatnonzero(mask)    indices = [sidx[i:j] for (i,j) in zip(split_idx[:-1],split_idx[1:])]    out = dict(zip(c1Ds[mask[:-1]],indices))    return out

接下来,我们将使用

numba
package进行迭代并获得最终的可哈希字典输出。随之而来的是,有两种解决方案-
一种使用键和值分别获取,
numba
主调用将压缩并转换为dict,而另一种将创建
numba-supported
dict类型,因此主调用函数不需要额外的工作。

因此,我们将有第一个

numba
解决方案:

from numba import  njit@njitdef _numba1(sidx, c1D):    out = []    n = len(sidx)    start = 0    grpID = []    for i in range(1,n):        if c1D[sidx[i]]!=c1D[sidx[i-1]]: out.append(sidx[start:i]) grpID.append(c1D[sidx[start]]) start = i    out.append(sidx[start:])    grpID.append(c1D[sidx[start]])    return grpID,outdef numba1(cubes):    c1D = np.ravel_multi_index(cubes.T, cubes.max(0)+1)    sidx = c1D.argsort()    out = dict(zip(*_numba1(sidx, c1D)))    return out

第二种

numba
解决方案是:

from numba import typesfrom numba.typed import Dictint_array = types.int64[:]@njitdef _numba2(sidx, c1D):    n = len(sidx)    start = 0    outt = Dict.empty(        key_type=types.int64,        value_type=int_array,    )    for i in range(1,n):        if c1D[sidx[i]]!=c1D[sidx[i-1]]: outt[c1D[sidx[start]]] = sidx[start:i] start = i    outt[c1D[sidx[start]]] = sidx[start:]    return outtdef numba2(cubes):    c1D = np.ravel_multi_index(cubes.T, cubes.max(0)+1)        sidx = c1D.argsort()    out = _numba2(sidx, c1D)    return out

cubes.npz
数据计时-

In [4]: cubes = np.load('cubes.npz')['array']In [5]: %timeit numpy1(cubes)   ...: %timeit numba1(cubes)   ...: %timeit numba2(cubes)2.38 s ± 14.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)2.13 s ± 25.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)1.8 s ± 5.95 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

选择#1: 我们可以通过

numexpr
大型数组来实现进一步的加速
c1D
,例如-

import numexpr as nes0,s1 = cubes[:,0].max()+1,cubes[:,1].max()+1d = {'s0':s0,'s1':s1,'c0':cubes[:,0],'c1':cubes[:,1],'c2':cubes[:,2]}c1D = ne.evaluate('c0+c1*s0+c2*s0*s1',d)

这将适用于所有需要的地方

c1D



欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5667255.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-16
下一篇 2022-12-16

发表评论

登录后才能评论

评论列表(0条)

保存