0

Is there a way to do an element-wise attribute extraction from a numpy array? For example, say I have:

import numpy as np

class foo():
    def __init__(self, value):
        self.bar = value

obj_array = np.empty((2, 2), dtype='object')
for i in range(obj_array.shape[0]):
    for j in range(obj_array.shape[1]):
        obj_array[i, j] = foo(i+j)

bar_array_hard_way = np.empty_like(obj_array)
for i in range(obj_array.shape[0]):
    for j in range(obj_array.shape[1]):
        bar_array_hard_way[i, j] = obj_array[i, j].bar

Here, I have an array of objects. Each object has some attribute. I'm hoping there is a slick built-in way of extracting those attributes as a new numpy array. Obviously this is a pretty trivial example, but larger arrays the element-wise copying is pretty annoying.

2
  • 4
    This is almost certainly not working code, since obj_array.size[0] is invalid ... you mean obj_array.shape Commented Jun 8, 2016 at 23:06
  • use a recarray perhaps? Commented Jun 8, 2016 at 23:24

2 Answers 2

1

I think the fastest way will be to combine Python's operator.attrgetter with numpy's np.frompyfunction - the first gives a fast, native code inlined, way to retrieve an object's attribute. The second, transforms an ordinary Python function into a Numpy's broadcast function, which can process an entire array in a single call -

so, your call is:

from operator import attrgetter
import numpy as np
# code to build obj_array
...
bar_array_easy_way = np.frompyfunc(attrgetter("bar"), 1, 1)(obj_array)

Quickly comparing it against using fromtiterator built a 1 million int array from my objects in half the time - besides, fromiterator can't build arrays with dtype=object - just fixed size elements.

Note that attrgetter itself is rather a "function factory" - it takes an attribute name, and returns a function that will take any object and return that attribute. That returned function we pass in turn, to frompyfunc - which takes other 2 arguments in order to allow numpy to make its broadcasting magic: the number of input arguments and the number of return results for our function.

Sign up to request clarification or add additional context in comments.

Comments

0

You can create your new array as:

bar_array = np.reshape(
    np.fromiter((x.bar for x in obj_array.flat), dtype=float),
    obj_array.shape)

Alter the dtype to whatever you'd please.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.