2

I am using trying to convert the following to a 2x2 numpy array of interval objects:

from interval import interval  # from the "pyinterval" package
import numpy as np

np.array([ 
    [interval([1.0, 2.0]), interval([1.0, 2.0])], 
    [interval([1.0, 2.0]), interval([1.0, 2.0])]
    ])

Unfortunately, this operation casts the intervals as numpy arrays, and gives me a 2x2x1x2 matrix. Is there any way I can prevent this from happening with numpy arrays or matrices?

I was able to get the desired result by populating an empty array first, where jac is a list of lists of intervals:

arr = np.empty(shape=(2,2), dtype=interval)

for i in range(len(arr)):
    for j in range(len(arr)):
        arr[i][j] = jac[i][j]

That being said, I suspect there's a more elegant way to achieve this. Is there a more "pythonic" way to do this?

4
  • 1
    What is interval? You can't call a module as if it were a function just like that. Commented May 1, 2017 at 15:54
  • Hi! Sorry about that, I was using pyinterval; I've corrected by question. Thanks! Commented May 1, 2017 at 16:07
  • Interval objects apparently look like lists. Commented May 1, 2017 at 16:10
  • Yes you have to use the allocate and fill. Sometimes the fill can be done as a whole or by slices. Commented May 1, 2017 at 16:19

3 Answers 3

2

It seems like numpy will coerce anything Sequence-like into a new dimension, even if np.array is called with dtype=object. You can work around this by directly making an empty array with dtype=object and then filling it manually.

interval_list = get_intervals()
interval_array = np.ndarray(len(interval_list), dtype=object)

for i, interv in enumerate(interval_list):
   interval_array[i] = interv
Sign up to request clarification or add additional context in comments.

Comments

0

You don't need the explicit loop when populating the empty array, you can just assign with [:]:

class interval(list):
    """I don't have any real interval but this should work."""
    def __repr__(self):
        return 'interval({})'.format(super().__repr__())

import numpy as np

>>> a = np.empty((2, 2), dtype=object)

>>> a[:] = [[interval([1.0, 2.0]), interval([1.0, 2.0])], 
...         [interval([1.0, 2.0]), interval([1.0, 2.0])]]

>>> a
array([[interval([1.0, 2.0]), interval([1.0, 2.0])],
       [interval([1.0, 2.0]), interval([1.0, 2.0])]], dtype=object)
>>> a.shape
(2, 2)
>>> a[0, 0]
interval([1.0, 2.0])

Unfortunatly there is no way to explicitly tell numpy.array which classes shouldn't be unpacked so you probably need to create the empty array first.


On a side note: There is not "interval" dtype for numpy arrays, if it's an unrecognized dtype it will use object. Using dtype=interval may be confusing for other readers because they might expect an efficient dtype.

Comments

0

With the assign and fill approach it is often possible to assign multiple items from a list. I have a vague memory that sometimes that doesn't work, but it does work for lists:

In [84]: jac = [[[1,2],[1,2]],[[1,2],[1,2]]]
In [85]: arr = np.empty((2,2),dtype=object)
In [86]: arr[...] = jac
In [87]: arr
Out[87]: 
array([[[1, 2], [1, 2]],
       [[1, 2], [1, 2]]], dtype=object)
In [88]: arr[1,0]
Out[88]: [1, 2]

p.s. it also works for jac = [[[[1,2]],[[1,2]]],[[[1,2]],[[1,2]]]], which would produce a (2,2,1,2) is used as np.array(jac).

1 Comment

"I have a vague memory that sometimes that doesn't work", only if some implicit broadcasting or unpacking is involved. I've never encountered a problem when the shapes were identical.

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.