Python:将使用对象数组的函数调用向量化

时间:2018-08-06 05:59:02

标签: python arrays python-3.x numpy vectorization

我有一个对象数组。我还有一个函数,一次需要两个对象的信息。我想对函数的调用进行矢量化处理,以便它一次计算所有调用,而不是使用循环来遍历必要的对象对。

如果我改用必要的数据创建一个数组,我就可以使用它。但是,这部分地破坏了使用对象的目的。

这是代码。它当前使用数组方法工作,并且在功能中只需注释/取消注释即可切换到不起作用的“对象”模式,但我非常希望这样做。

我得到的错误是:TypeError:只有具有一个元素的整数数组才能转换为索引

import numpy as np
import time as time

class ExampleObject():

    def __init__(self, r):
        self.r       = r

def ExampleFunction(x):
    """ WHAT I REALLY WANT """
#    answer = exampleList[x].r - exampleList[indexArray].r 
    """WHAT I AM STUCK WITH """
    answer = coords[x] - exampleList[indexArray].r
    return answer

indexArray = 5   #arbitrary choice of array index
sizeArray = 1000    

exampleList = []
for i in range(sizeArray):
    r = np.random.rand()
    exampleList.append( ExampleObject( r ) )

index_list = np.arange(0,sizeArray,1)
index_list = np.delete(index_list,indexArray)

coords = np.array([h.r for h in exampleList])

answerArray = ExampleFunction(index_list)

问题在于,当我向函数传递一个整数数组时,当我使用对象数组(实际上是列表)时,它不返回答案数组(我想要的矢量化)。如果我使用数组(没有对象,每个元素中只有数据),它确实可以工作。但是正如我已经说过的那样,这在我的脑海中是无法实现的,它的目的是要在对象上存储信息。我真的还需要在数组中存储相同的信息吗?

2 个答案:

答案 0 :(得分:3)

我无法发表评论,对您滥用答案部分表示抱歉...

如果numpy数组的数据类型是python对象,则numpy数组的内存不连续。操作的向量化可能不会大大提高性能。也许您可能想尝试使用numpy结构化数组。

假设对象具有属性a和b,并且它们是双精度浮点数,则...

import numpy as np

numberOfObjects = 6

myStructuredArray = np.zeros(
    (numberOfObjects,),
    [("a", "f8"), ("b", "f8")],
)

您可以像这样初始化对象0的各个属性

myStructuredArray["a"][0] = 1.0

或者您可以为所有对象初始化单个属性

myStructuredArray["a"] = [1,2,3,4,5,6]

print(myStructuredArray)

[(1., 0.) (2., 0.) (3., 0.) (4., 0.) (5., 0.) (6., 0.)]

答案 1 :(得分:2)

numpy.ufunc,在给定对象dtype数组时,对其进行迭代,然后尝试对每个元素应用对应的方法。

例如np.abs尝试应用__abs__方法。让我们将这样的方法添加到您的类中:

In [31]: class ExampleObject():
    ...: 
    ...:     def __init__(self, r):
    ...:         self.r       = r
    ...:     def __abs__(self):
    ...:         return self.r
    ...:     

现在创建数组:

In [32]: indexArray = 5   #arbitrary choice of array index
    ...: sizeArray = 10  
    ...: 
    ...: exampleList = []
    ...: for i in range(sizeArray):
    ...:     r = np.random.rand()
    ...:     exampleList.append( ExampleObject( r ) )
    ...: 
    ...: index_list = np.arange(0,sizeArray,1)
    ...: index_list = np.delete(index_list,indexArray)
    ...: 
    ...: coords = np.array([h.r for h in exampleList])

并从列表中创建对象dtype数组:

In [33]: exampleArr = np.array(exampleList)

In [34]: exampleArr
Out[34]: 
array([<__main__.ExampleObject object at 0x7fbb541eb9b0>,
       <__main__.ExampleObject object at 0x7fbb541eba90>,
       <__main__.ExampleObject object at 0x7fbb541eb3c8>,
       <__main__.ExampleObject object at 0x7fbb541eb978>,
       <__main__.ExampleObject object at 0x7fbb541eb208>,
       <__main__.ExampleObject object at 0x7fbb541eb128>,
       <__main__.ExampleObject object at 0x7fbb541eb198>,
       <__main__.ExampleObject object at 0x7fbb541eb358>,
       <__main__.ExampleObject object at 0x7fbb541eb4e0>,
       <__main__.ExampleObject object at 0x7fbb541eb048>], dtype=object)

现在,我们可以通过调用r函数来获取np.abs值的数组:

In [35]: np.abs(exampleArr)
Out[35]: 
array([0.28411876298913485, 0.5807617042932764, 0.30566195995294954,
       0.39564156171554554, 0.28951905026871105, 0.5500945908978057,
       0.40908712567465855, 0.6469497088949425, 0.7480045751535003,
       0.710425181488751], dtype=object)

它也适用于数组的索引元素:

In [36]: np.abs(exampleArr[:3])
Out[36]: 
array([0.28411876298913485, 0.5807617042932764, 0.30566195995294954],
      dtype=object)

这很方便,但是我不能保证速度。在其他测试中,我发现对象dtype的迭代比数字数组元素的迭代快(在Python中),但比列表迭代慢。

In [37]: timeit np.abs(exampleArr)
3.61 µs ± 131 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

In [38]: timeit [h.r for h in exampleList]
985 ns ± 31.5 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
In [39]: timeit np.array([h.r for h in exampleList])
3.55 µs ± 88.6 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)