I am working on my first agent-based model (abm) in my life and I have to do operations on an array of arrays. Each agent of my model is an array with numbers that are added by the algorithm when certain conditions are met. Sometimes I have to divide or multiply all arrays by the same number. I saw in numpy array I can do this:
vector = np.array([1, 2.1, 3])
when I do
2 / vector
gives me, as expected, array([ 2. , 0.95238095, 0.66666667])
.
But if I want an array of arrays like for example
arrayofarrays = np.array([[1,2,3],[1.1,6],[1]])
it has by default dtype=object
and I guess it is this that doesn't allow me to do
2 / arrayofarrays
which gives
unsupported operand type(s) for /: 'int' and 'list'
Also
2 / arrayofarrays[0]
gives same error. Instead if you use a single array's value, as
2/arrayofarrays[0][1]
it works: 1.0
.
Can you help me? Thanks
Your ragged array - an array of lists:
In [31]: arr = np.array([[1,2,3],[1.1,6],[1]])
<ipython-input-31-4887f672b831>:1: VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify 'dtype=object' when creating the ndarray.
arr = np.array([[1,2,3],[1.1,6],[1]])
In [32]: arr
Out[32]: array([list([1, 2, 3]), list([1.1, 6]), list([1])], dtype=object)
Math on object dtype arrays is performed element by element (at list comprehension speeds). How it works depends on how the corresponding method works the elements:
In [33]: arr *2
Out[33]:
array([list([1, 2, 3, 1, 2, 3]), list([1.1, 6, 1.1, 6]), list([1, 1])],
dtype=object)
list*2
is replication operation, not multiplication.
In [34]: arr / 2
Traceback (most recent call last):
File "<ipython-input-34-855a165721c4>", line 1, in <module>
arr / 2
Divide is not defined for lists.
TypeError: unsupported operand type(s) for /: 'list' and 'int'
We can apply a simple function to each element with frompyfunc
:
In [38]: np.frompyfunc(lambda x: np.array(x)/2, 1,1)(arr)
Out[38]:
array([array([0.5, 1. , 1.5]), array([0.55, 3. ]), array([0.5])],
dtype=object)
This function takes care of the conversion to array as well as the division.
Equivalent list comprehension (just as fast):
In [40]: [np.array(x)/2 for x in arr]
Out[40]: [array([0.5, 1. , 1.5]), array([0.55, 3. ]), array([0.5])]
or the pure list version (may be faster)
In [41]: [[y/2 for y in x] for x in arr.tolist()]
Out[41]: [[0.5, 1.0, 1.5], [0.55, 3.0], [0.5]]