是否存在基于abs值的ceil()函数,如trunc vs floor或round-away-from-zero函数?

Wan*_*ang 0 python numpy

numpy.trunc 是一个基于abs值的floor函数:

a = np.array([-1.7, -1.5, -0.2, 0.2, 1.5, 1.7, 2.0])
np.floor(a)
Out[122]: array([-2., -2., -1.,  0.,  1.,  1.,  2.])
np.trunc(a)
Out[123]: array([-1., -1., -0.,  0.,  1.,  1.,  2.])
Run Code Online (Sandbox Code Playgroud)

ceil输出是这样的:

np.ceil(a)
Out[124]: array([-1., -1., -0.,  1.,  2.,  2.,  2.])
Run Code Online (Sandbox Code Playgroud)

但我想要一个输出:array([ - 2., - 2.,-1.,1.,2.,2.,2.])这个numpy函数是什么?

编辑:不幸的是,零函数没有内置圆.基于@Mitch和@Divakar的答案,我做了一些测试,并尝试优化速度和内存使用.

def rawzero1(a): #@Mitch
    return np.sign(a)*np.ceil(np.abs(a))


def rawzero2(a): #@Divakar
    return np.where(a<0, np.floor(a), np.ceil(a))


def rawzero3(a):
    _a = np.abs(a)
    np.ceil(_a, _a) # inplace
    np.copysign(_a, a, out = _a)
    return _a


def rawzero4(a):
    _a = np.ceil(np.abs(a))
    np.copysign(_a, a, out = _a)
    return _a

array size: 762.94 MB

| func     |   t per call (ms) |   max mem use (MB) |   mem to array size (MB) |
|:---------|------------------:|-------------------:|-------------------------:|
| rawzero1 |           1071.34 |            3082.51 |                     4.04 |
| rawzero2 |           1237.74 |            3183.39 |                     4.17 |
| rawzero3 |            543.71 |            1576.41 |                     2.07 |
| rawzero4 |            583.83 |            2328.77 |                     3.05 |
Run Code Online (Sandbox Code Playgroud)

所以最好的是rawzero3,它使用inplace操作来减少内存使用,并使copysign加速.

根据@Divakar更新,需要numexpr> = 2.6.4.之前的任何版本都没有ceil().

rawzero1(a) == rawzero2(a)
rawzero1(a) == rawzero3(a)
rawzero1(a) == rawzero4(a)
rawzero1(a) == numexpr_1(a)
array size: 762.94 MB
| func      |   t per call (ms) |   max mem use (MB) |   mem to array size (MB) |
|:----------|------------------:|-------------------:|-------------------------:|
| rawzero1  |           1108.68 |            3828.35 |                     5.02 |
| rawzero2  |           1226.78 |            3940.69 |                     5.17 |
| rawzero3  |            531.54 |            2323.55 |                     3.05 |
| rawzero4  |            579.55 |            3082.49 |                     4.04 |
| numexpr_1 |            228.00 |            2323.57 |                     3.05 |
Run Code Online (Sandbox Code Playgroud)

毫无疑问.numexpr版本将提供与rawzero3相同的最佳速度和相同的内存占用.奇怪的部分是rawzero3的内存占用有点不稳定.从理论上讲,它应该只使用2x数组大小而不是3x.

mir*_*ulo 6

另一种选择(虽然不是内置的)可以取绝对值的上限.

np.sign(a) * np.ceil(np.abs(a))
Run Code Online (Sandbox Code Playgroud)


Div*_*kar 5

方法1:使用np.where做之间的选择floorceil基于的积极/消极-

np.where(a<0, np.floor(a), np.ceil(a))
Run Code Online (Sandbox Code Playgroud)

样品运行 -

In [61]: a
Out[61]: array([-1.7, -1.5, -0.2,  0.2,  1.5,  1.7,  2. ])

In [62]: np.where(a<0, np.floor(a), np.ceil(a))
Out[62]: array([-2., -2., -1.,  1.,  2.,  2.,  2.])
Run Code Online (Sandbox Code Playgroud)

方法#2:我们可以@Mitch's post通过使用与零和缩放的比较来扩展所使用的符号技巧以获得sign等效,并且还利用numexpr模块来执行ceilon abs值.现在,我们应该记住,numexpr使用大型数据集可以更好地执行.因此,实施将是 -

import numexpr as ne

ne.evaluate('(2*(a>0)-1)*ceil(abs(a))')
Run Code Online (Sandbox Code Playgroud)

运行时测试

所有方法 -

def rawzero1(a):
    return np.sign(a)*np.ceil(np.abs(a))

def rawzero2(a):
    return np.where(a<0, np.floor(a), np.ceil(a))

def rawzero3(a):
    _a = np.abs(a)
    np.ceil(_a, _a) # inplace
    np.copysign(_a, a, out = _a)
    return _a

def rawzero4(a):
    _a = np.ceil(np.abs(a))
    np.copysign(_a, a, out = _a)
    return _a

def numexpr_1(a):
    return ne.evaluate('(2*(a>0)-1)*ceil(abs(a))')
Run Code Online (Sandbox Code Playgroud)

计时 -

In [52]: a = np.random.randn(1000000)

In [53]: %timeit rawzero1(a)
    ...: %timeit rawzero2(a)
    ...: %timeit rawzero3(a)
    ...: %timeit rawzero4(a)
    ...: %timeit numexpr_1(a)
    ...: 
100 loops, best of 3: 11.6 ms per loop
100 loops, best of 3: 13.2 ms per loop
100 loops, best of 3: 4.9 ms per loop
100 loops, best of 3: 6.54 ms per loop
1000 loops, best of 3: 1.65 ms per loop

In [54]: np.allclose(numexpr_1(a), rawzero1(a))
Out[54]: True
Run Code Online (Sandbox Code Playgroud)