numpy数组的元素智能测试是数字

时间:2016-06-23 15:55:19

标签: python arrays numpy

我有一个如下数组:

In [1]: x = array(['1.2', '2.3', '1.2.3'])

我想测试数组中的每个元素是否可以转换为数值。也就是说,函数:is_numeric(x)将返回一个True / False数组,如下所示:

In [2]: is_numeric(x)
Out[2]: array([True, True, False])

怎么做?

5 个答案:

答案 0 :(得分:1)

import numpy as np

def is_float(val):
        try:
            float(val)
        except ValueError:
            return False
        else:
            return True

a = np.array(['1.2', '2.3', '1.2.3'])

is_numeric_1 = lambda x: map(is_float, x)              # return python list
is_numeric_2 = lambda x: np.array(map(is_float, x))    # return numpy array
is_numeric_3 = np.vectorize(is_float, otypes = [bool]) # return numpy array

取决于 a 数组的大小和返回值的类型,这些函数的速度不同。

In [26]: %timeit is_numeric_1(a)
100000 loops, best of 3: 2.34 µs per loop

In [27]: %timeit is_numeric_2(a)
100000 loops, best of 3: 3.13 µs per loop

In [28]: %timeit is_numeric_3(a)
100000 loops, best of 3: 6.7 µs per loop

In [29]: a = np.array(['1.2', '2.3', '1.2.3']*1000)

In [30]: %timeit is_numeric_1(a)
1000 loops, best of 3: 1.53 ms per loop

In [31]: %timeit is_numeric_2(a)
1000 loops, best of 3: 1.6 ms per loop

In [32]: %timeit is_numeric_3(a)
1000 loops, best of 3: 1.58 ms per loop

如果list没问题,请使用is_numeric_1

如果您想要numpy array 的尺寸很小,请使用is_numeric_2

否则,请使用is_numeric_3

答案 1 :(得分:1)

In [23]: x = np.array(['1.2', '2.3', '1.2.3', '1.2', 'foo'])

尝试将整个数组转换为float,如果无法转换一个或多个字符串,则会导致错误:

In [24]: x.astype(float)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-24-a68fda2cafea> in <module>()
----> 1 x.astype(float)

ValueError: could not convert string to float: '1.2.3'

In [25]: x[:2].astype(float)
Out[25]: array([ 1.2,  2.3])

但是为了找到哪些可以转换,哪些不可以,我们可能必须对每个元素应用测试。这需要某种迭代,以及某种测试。

这些答案中的大多数已将float包裹在try/except块中。但请看How do I check if a string is a number (float) in Python? 替代品。一个答案发现浮动包装对于有效输入是快速的,但对于无效输入(https://stackoverflow.com/a/25299619/901925),正则表达式测试更快。

In [30]: def isnumeric(s):
    try:
        float(s)
        return True
    except ValueError:
        return False

In [31]: [isnumeric(s) for s in x]
Out[31]: [True, True, False, True, False]

In [32]: np.array([isnumeric(s) for s in x])  # for array
Out[32]: array([ True,  True, False,  True, False], dtype=bool)

我喜欢列表理解,因为它很常见且清晰(在Py3中更受欢迎)。为了速度,我发现frompyfunc比其他迭代器(并处理多维数组)具有适度的优势:

In [34]: np.frompyfunc(isnumeric, 1,1)(x)
Out[34]: array([True, True, False, True, False], dtype=object)

In [35]: np.frompyfunc(isnumeric, 1,1)(x).astype(bool)
Out[35]: array([ True,  True, False,  True, False], dtype=bool)

它需要比vectorize更多的样板,但通常更快。但是如果数组或列表很小,列表理解通常会更快(避免开销不足)。

======================

(已编辑)np.char具有一组将字符串方法应用于数组元素的函数。但最接近的函数是np.char.isnumeric,它只测试数字字符,而不是完整的浮动转换。

答案 2 :(得分:0)

# method to check whether a string is a float
def is_numeric(s):
    try:
        float(s)
        return True
    except ValueError:
        return False

# method to return an array of booleans that dictate whether a string can be parsed into a number
def is_numeric_array(arr):
    return_array = []
    for val in numpy.ndenumerate(arr):
        return_array.append(is_numeric(val))
    return return_array

答案 3 :(得分:0)

这也依赖于获取每元素结果的try-except方法,但使用fromiter预分配布尔结果数组:

def is_numeric(x):

    def try_float(xx):
        try:
            float(xx)
        except ValueError:
            return False
        else:
            return True

    return fromiter((try_float(xx) for xx in x.flat),
                    dtype=bool, count=x.size)

x = array(['1.2', '2.3', '1.2.3'])
print is_numeric(x)

给出:

[ True  True False]

答案 4 :(得分:0)

我发现以下内容适用于我的目的。

首先,将isNumeric函数从https://rosettacode.org/wiki/Determine_if_a_string_is_numeric#C保存在名为ctest.h的文件中,然后按如下方式创建.pyx文件:

from numpy cimport ndarray, uint8_t
import numpy as np
cimport numpy as np

cdef extern from "ctest.h":
     int isNumeric(const char * s)

def is_numeric_elementwise(ndarray x):
    cdef Py_ssize_t i
    cdef ndarray[uint8_t, mode='c', cast=True] y = np.empty_like(x, dtype=np.uint8)

    for i in range(x.size):
        y[i] = isNumeric(x[i])

    return y > 0

上面的Cython函数运行得非常快。

In [4]: is_numeric_elementwise(array(['1.2', '2.3', '1.2.3']))
Out[4]: array([ True,  True, False], dtype=bool)

In [5]: %timeit is_numeric_elementwise(array(['1.2', '2.3', '1.2.3'] * 1000000))
1 loops, best of 3: 695 ms per loop

https://stackoverflow.com/a/37997673/4909242中的is_numeric_3方法进行比较,速度提高约5倍。

In [6]: %timeit is_numeric_3(array(['1.2', '2.3', '1.2.3'] * 1000000))
1 loops, best of 3: 3.45 s per loop

我猜可能还有一些空间需要改进。