在numpy数组中查找类型转换失败的索引

时间:2018-04-26 17:43:49

标签: python arrays numpy

我有一个1D numpy字符串数组,我需要将其转换为新的dtype。 新类型可以是int,float或datetime类型。某些字符串对于该类型可能无效且无法转换,这会导致错误,例如:

from timeit import timeit
import numpy as np

strings = np.array(list(map(str, range(10000000))))


def python_parse(arr):
    result = []
    for i, x in enumerate(arr):
        try:
            result.append(int(x))
        except ValueError:
            raise Exception(f'Failed at: {i}')


print(timeit(lambda: np.array(strings, dtype=int), number=10))  # 35 seconds
print(timeit(lambda: python_parse(strings), number=10))         # 52 seconds

我想找到该无效值的索引,在本例中为2.目前我只能想到两个解决方案,两者都不是很好:

  1. 使用正则表达式解析异常消息以查找无效值,然后在原始数组中查找该值的索引。这看起来很混乱,容易出错。
  2. 在Python中解析循环中的值。这可能会比numpy版本慢得多。例如,这是我做过的一个实验:
  3. {{1}}

    这似乎是一个简单而常见的操作,我希望将解决方案构建到numpy库中,但我找不到一个。

3 个答案:

答案 0 :(得分:3)

您可以使用np.core.defchararray.isdigit()查找数字的索引,然后使用逻辑非操作数来获取纳米数字的索引。之后您可以使用np.where()来获取相应的索引:

In [20]: arr = np.array(['10', '20', 'a', '4', '%'])

In [24]: np.where(~np.core.defchararray.isdigit(arr))
Out[24]: (array([2, 4]),)

如果要检查浮动等多种类型,可以使用自定义函数,然后使用np.vectorize将函数应用于数组。对于约会来说这有点棘手但如果你想要一般的方法,你可能想要使用dateutils.parser()

您可以使用以下功能:

# from dateutils import parser
In [33]: def check_type(item):
    ...:     try:
    ...:         float(item)
    ...:     except:
    ...:         try:         
    ...:             parser.parse(item)
    ...:         except:     
    ...:             return True
    ...:         else:      
    ...:             return False
    ...:     else:          
    ...:         return False

然后:

vector_func = np.vectorize(check_type)
np.where(vector_func(arr))

演示:

In [45]: arr = np.array(['10.34', '-20', 'a', '4', '%', '2018-5-01'])

In [46]: vector_func = np.vectorize(check_type)
    ...: np.where(vector_func(arr))
    ...: 
Out[46]: (array([2, 4]),)

答案 1 :(得分:1)

事实证明,我高估了Python和numpy之间的区别,虽然我在问题中提到的Python代码非常慢,但使用预分配的数组可以更快地实现它:

def python_parse(arr):
    result = np.empty(shape=(len(arr),), dtype=int)
    for i, x in enumerate(arr):
        try:
            result[i] = x
        except ValueError:
            raise Exception(f'Failed at: {i}')
    return result

这会正确地产生错误,并且几乎与简单np.array(strings, dtype=int)一样快(这让我感到非常惊讶)。

答案 2 :(得分:0)

我会做类似的事情:

custom_type=int
i = 0
l = ['10', '20', 'a']
acc = np.array([], dtype=custom_type)
for elem in l:
    try:
       acc = np.concatenate((acc, np.array([elem], dtype=custom_type)))
       i += 1
    except:
       print("Failed to convert the type of the element in position {}".format(i))