假设我有以下numpy数组:
arr = np.array(["a", "b", "c"], dtype=object)
现在我想对每个元素执行任意函数或调用任意方法。例如,假设我想获得所有这些元素的大写。 “逻辑上”说,我想做这样的事情:
upp_arr = arr.upper()
或
upp_arr = str.upper(arr)
简短版本:我可以完成以上任何一种吗?
长版:
这显然不会起作用,考虑到数组没有upper
方法(即使各个元素都有),str
内置也不知道如何处理numpy数组。我不想构建一个知道如何处理数组的str.upper
自定义版本,因为这需要我事先知道我的数组用户可能想要使用哪些函数。
我可以做类似
的事情upp_arr = np.array([x.upper() for x in arr])
我不喜欢这样:现在我需要向我的代码的用户公开arr
实际上是一个numpy数组。我希望得到类似上述两种非工作解决方案的东西。
我试图通过对np.ndarray
进行子类化来覆盖__getattr__(self, name)
方法以返回名称name
的元素属性数组,如果name
不是np.ndarray
的属性,而是覆盖其__call__
方法以返回元素数组 调用`结果:
import numpy as np
class MyArr(np.ndarray):
def __getattr__(self, name):
if hasattr(np.ndarray, name):
return getattr(np.ndarray, name)
arr = MyArr(self.shape, dtype=object)
arr[:] = [getattr(elem, name) for elem in self]
return arr
def __call__(self):
arr = MyArr(self.shape, dtype=self.dtype)
arr[:] = [elem() for elem in self]
return arr
arr = MyArr((3,), dtype=object)
arr[:] = ["a", "b", "c"]
arr.upper()
这有两个问题:构造数组是一个痛苦(必须首先实例化它,然后用值填充它),我必须假设函数调用的结果与dtype相同原始数组(dtype=self.dtype
部分)。如果我坚持使用object
类型的数组,那么后者不是问题,但通常会这样。
如何解决?
答案 0 :(得分:-1)
有一个函数库可以将str
操作应用于字符串数组的元素,例如
In [199]: np.char.upper(np.array(['a','b','c']))
Out[199]:
array(['A', 'B', 'C'],
dtype='|S1')
但它不适用于dtype对象的数组:
In [200]: np.char.upper(np.array(['a','b','c'],dtype=object))
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-200-17a9e3cc581f> in <module>()
----> 1 np.char.upper(np.array(['a','b','c'],dtype=object))
...\numpy\core\defchararray.pyc in upper(a)
1571 """
1572 a_arr = numpy.asarray(a)
-> 1573 return _vec_string(a_arr, a_arr.dtype, 'upper')
TypeError: string operation on non-string array
但是这个char
函数并不比相应的列表理解快。它仍然必须在每个元素上调用str操作。但是如果数组是n-d将会更方便。
In [209]: timeit np.char.upper(x1) # large x1
1000 loops, best of 3: 277 µs per loop
In [210]: timeit np.array([i.upper() for i in x1])
1000 loops, best of 3: 278 µs per loop
关于这个问题的一些新想法。
np.frompyfunc
将一个函数应用于数组的所有元素,返回一个新对象dtype数组。
In [49]: vupper = np.frompyfunc(lambda astr: astr.upper(), 1, 1)
In [50]: vupper(np.array(['a','b','c']))
Out[50]: array(['A', 'B', 'C'], dtype=object)
In [51]: vupper(np.array(['a','b','c'], dtype=object))
Out[51]: array(['A', 'B', 'C'], dtype=object)
np.vectorize
使用np.frompyfunc
,但添加了一些dtype
次转化。在我的测试np.frompyfunc
中有点快;在某些情况下,比同等的列表理解版本快2倍。
查看numpy/core/records.py
,了解np.recarray
如何让我们将结构化数组字段作为属性进行访问。它包裹__getattribute__
。
Masked数组是具有大量自定义方法的数组子类的一个很好的例子。 /numpy/ma/__init__.py