【问题标题】:is there any ceil() function based on abs value like trunc vs floor or round-away-from-zero function?是否有任何基于 abs 值的 ceil() 函数,例如 trunc vs floor 或从零舍入的函数?
【发布时间】:2018-03-16 07:26:13
【问题描述】:

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

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.])

ceil 输出是这样的:

np.ceil(a)
Out[124]: array([-1., -1., -0.,  1.,  2.,  2.,  2.])

但我想要一个输出: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 |

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

根据需要 numexpr >=2.6.4 的 @Divakar 进行更新。之前的任何版本都没有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 |

一点也不意外。 numexpr 版本将提供最佳速度和与 rawzero3 相同的内存占用。奇怪的是 rawzero3 的内存占用有点不稳定。理论上它应该只使用 2x 数组大小而不是 3x。

【问题讨论】:

  • 请注意,trunc 和 floor 都没有使用绝对值的概念。 trunc 向零舍入,而 floor 向负无穷舍入。 ceil 向正无穷大舍入,因此您正在寻找从零开始舍入 远离 的东西。我不知道有一个内置函数可以做到这一点。
  • 在我的帖子中添加了一种基于@Mitch 的签名想法的方法,该方法似乎比其他方法快得多。是否也将其添加到内存测试的基准测试设置中?
  • @Divakar 您使用的是哪个版本的 numexpr?我之前尝试使用 numexpr,但它不支持 ceil 功能。我很惊讶你可以让它工作。我正在使用 2.6.2
  • @Wang Yeah ceil 是最近添加的。我需要升级它。你能升级你的吗?在我的 linux 上,我做到了:sudo pip install numexpr --upgrade.
  • @Wang 我在2.6.4

标签: python numpy


【解决方案1】:

方法#1:使用np.where根据正面/负面在floorceil之间进行选择-

np.where(a<0, np.floor(a), np.ceil(a))

示例运行 -

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.])

方法 #2: 我们可以扩展 @Mitch's post 中使用的符号技巧,方法是使用与零的比较和缩放以获得等效的 sign,并利用 numexpr module 执行 @ 987654331@ abs 值。现在,我们应该记住,numexpr 在大型数据集上表现更好。因此,实现将是 -

import numexpr as ne

ne.evaluate('(2*(a>0)-1)*ceil(abs(a))')

运行时测试

所有方法 -

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))')

时间安排 -

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

【讨论】:

    【解决方案2】:

    你可以使用这个语法 [ np.ceil(x) if x&gt;0 else np.floor(x) for x in lst) ]

    手动完成。不确定功能。

    赞这个帖子One-line list comprehension: if-else variants

    【讨论】:

      【解决方案3】:

      另一个选项(虽然不是内置的)可能是采用绝对值的上限。

      np.sign(a) * np.ceil(np.abs(a))
      

      【讨论】:

      • 谢谢!我使用 copysign 来加快速度。
      猜你喜欢
      • 2019-05-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-26
      • 2017-07-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多