繁体   English   中英

Numpy:检查浮点数组是否包含整数

[英]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 支持的浮点格式( float16float32float64float128 (实际扩展精度))以及如何编写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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM