问题
numpy.trunc
is a floor function based on abs value:
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.])
The ceil output is this:
np.ceil(a)
Out[124]: array([-1., -1., -0., 1., 2., 2., 2.])
But I want an output: array([-2., -2., -1., 1., 2., 2., 2.]) What is the numpy function for this?
edit: Unfortunately there is no build-in round away from zero function. Based on @Mitch and @Divakar answers I did some test and try to optimize the speed and memory usage.
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 |
so the best is rawzero3, which use inplace operations to reduce memory usage and copysign to speed up.
update according to @Divakar which requires numexpr >=2.6.4. Any version before that does not have 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 |
There is no surprise at all. numexpr version will give the best speed and same memory footprint as rawzero3. The weird part is rawzero3's memory footprint is kind of unstable. Theoretically it should only use 2x array size instead of 3x.
回答1:
Another option (though not a built-in) could be taking the ceiling of the absolute values.
np.sign(a) * np.ceil(np.abs(a))
回答2:
Approach #1 : Use np.where
to do the choosing between floor
and ceil
based on the positivity/negativity -
np.where(a<0, np.floor(a), np.ceil(a))
Sample run -
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.])
Approach #2 : We could extend the sign trick used in @Mitch's post by using a comparison against zero and scaling to get the sign
equivalent and also leverages numexpr module to perform the ceil
on abs
values. Now, we should keep in mind that numexpr
performs better with large datasets. Thus, the implementation would be -
import numexpr as ne
ne.evaluate('(2*(a>0)-1)*ceil(abs(a))')
Runtime test
All approaches -
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))')
Timings -
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
回答3:
You can use this syntax
[ np.ceil(x) if x>0 else np.floor(x) for x in lst) ]
to do it manually. Not sure about the function.
Like this post One-line list comprehension: if-else variants
来源:https://stackoverflow.com/questions/46572699/is-there-any-ceil-function-based-on-abs-value-like-trunc-vs-floor-or-round-awa