我有一个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}}
这似乎是一个简单而常见的操作,我希望将解决方案构建到numpy库中,但我找不到一个。
答案 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))