[英]Numpy: Check if float array contains whole numbers
在 Python 中,可以使用n.is_integer()
检查float
包含整数值,基于此 QA: 如何检查浮点值是否为整数。
numpy 是否有类似的操作可以应用于数组? 允许以下内容的东西:
>>> x = np.array([1.0 2.1 3.0 3.9])
>>> mask = np.is_integer(x)
>>> mask
array([True, False, True, False], dtype=bool)
可以做类似的事情
>>> mask = (x == np.floor(x))
或者
>>> mask = (x == np.round(x))
但它们涉及调用额外的方法并创建一堆可以避免的临时数组。
numpy 是否有一个矢量化函数,以类似于 Python 的float.is_integer
的方式检查浮点数的小数部分?
据我所知,没有这样的函数返回一个布尔数组,指示浮点数是否有小数部分。 我能找到的最接近的是np.modf
,它返回小数部分和整数部分,但这会创建两个浮点数组(至少是暂时的),所以它可能不是最好的内存。
如果您对就地工作感到满意,可以尝试以下操作:
>>> np.mod(x, 1, out=x)
>>> mask = (x == 0)
与使用 round 或 floor (您必须将x
保持在周围)相比,这应该可以节省内存,但当然您会丢失原始x
。
另一种选择是要求在 Numpy 中实现它,或者自己实现它。
由于稍微不同的原因,我需要这个问题的答案:检查何时可以将整个浮点数数组转换为整数而不会丢失数据。
Hunse 的回答几乎对我有用,只是我显然不能使用就地技巧,因为我需要能够撤消操作:
if np.all(np.mod(x, 1) == 0):
x = x.astype(int)
从那里,我想到了在许多情况下可能更快的以下选项:
x_int = x.astype(int)
if np.all((x - x_int) == 0):
x = x_int
原因是模运算比减法慢。 但是,现在我们预先对整数进行转换 - 相对而言,我不知道该操作有多快。 但是,如果您的大多数数组都是整数(在我的情况下是这样),则后一个版本几乎肯定会更快。
另一个好处是你可以用 np.isclose 之类的东西替换np.isclose
以检查在一定的容差范围内(当然你在这里应该小心,因为截断不是正确的舍入!)。
x_int = x.astype(int)
if np.all(np.isclose(x, x_int, 0.0001)):
x = x_int
编辑:较慢,但可能值得,具体取决于您的用例,如果存在,也会单独转换整数。
x_int = x.astype(int)
safe_conversion = (x - x_int) == 0
# if we can convert the whole array to integers, do that
if np.all(safe_conversion):
x = x_int.tolist()
else:
x = x.tolist()
# if there are _some_ integers, convert them
if np.any(safe_conversion):
for i in range(len(x)):
if safe_conversion[i]:
x[i] = int(x[i])
作为一个重要的例子:这对我有用,因为我有稀疏数据(这意味着大部分为零),然后我将其转换为 JSON,一次,然后在服务器上重用。 对于浮点数, ujson
将它们转换为[ ...,0.0,0.0,0.0,... ]
,对于导致[...,0,0,0,...]
整数,最多可节省一半字符串中的字符数。 这减少了服务器(较短的字符串)和客户端(较短的字符串,大概是 JSON 解析速度稍快)的开销。
您也可以在列表推导式中仅使用 Python 方法。
>>> x = np.array([1.0, 2.1, 3.0, 3.9])
>>> mask = np.array([val.is_integer() for val in x])
>>> mask
array([ True, False, True, False])
与使用 mod 1 的答案相比,对于具有 4 个值的给定示例(5.66 us vs 8.03 us),这稍微快一点,对于 1000 个值的数组,速度快了 3 倍以上。
受公认答案的启发,这是一个使用%
运算符的非就地版本:
modulus = x % 1
mask = modulus == 0
或更简洁地
mask = (x % 1) == 0
虽然(x % 1) == 0
的公认方法已经足够了,但让我感到困扰的是,在 numpy 中无法本地完成此操作,尤其是考虑到在 vanilla python 中存在float.is_integer
。
因此,我对 numpy 支持的浮点格式( float16
、 float32
、 float64
、 float128
(实际扩展精度))以及如何编写float128
进行了一些研究。
结果是,对于足够小的浮点数以适应相应的无符号整数类型(在普通机器上几乎所有高达float64
所有内容),您可以通过一些简单的位操作来进行检查。 例如,这里有一个 C99 函数,它可以非常快速地告诉您float32
包含整数值:
#include <stdint.h>
int isint_float(float n)
{
uint32_t k = ((union { float n; uint32_t k; }){n}).k;
// Zero when everything except sign bit is zero
if((k & 0x7FFFFFFF) == 0) return 1;
uint32_t exponent = k & 0x7F800000;
// NaN or Inf when the exponent bits are all ones
// Guaranteed fraction when exponent < 0
if(exponent == 0x7F800000 || exponent < 0x3F800000) return 0;
// Guaranteed integer when exponent >= FLT_MANT_DIG - 1
if(exponent >= 0x4B000000) return 1;
// Otherwise, check that the significand bits past the exponent are zeros
return (k & (0x7FFFFF >> ((exponent >> 23) - 0x7F))) == 0;
}
我继续将这个函数及其兄弟函数封装在一个 ufunc 中,可以在这里找到: https : //github.com/madphysicist/isint_ufunc 。 一个很好的特性是这个 ufunc 为所有整数类型返回True
而不是引发错误。 另一个是它的运行速度比(x % 1) == 0
快 5 到 15 倍。
根据链接的教程,您可以使用python setup.py {build_ext --inplace, build, install}
,具体取决于您想要的程度。 也许我应该看看 numpy 社区是否有兴趣包含这个 ufunc。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.