Numpy arange over numpy arrays - python

I have a function that basically returns generalized harmonic number.
def harmonic(limit, z):
return numpy.sum(1.0/numpy.arange(1, limit+1)**z)
Here is two examples for the current function definition:
>>> harmonic(1, 1)
1.0
>>> harmonic(2, 1)
1.5
As you might guess this works fine when limit is scalar, but how can I make this function work with 1D and 2D arrays as well?
The following demonstrates an example output of the function I want to achieve
>>> limit = np.array([[1, 2], [3, 4]])
>>> harmonic(limit, 1)
array([[1.0, 1.5], [1.833, 2.083]])

If you're only interested in vectorizing over limit and not z, as in the example you showed, then I think you can use np.vectorize:
>>> h = np.vectorize(harmonic)
>>> h(1, 1)
array(1.0)
>>> h(2, 1)
array(1.5)
>>> h([[1,2], [3,4]], 1)
array([[ 1. , 1.5 ],
[ 1.83333333, 2.08333333]])
>>> h([[1,2], [3,4]], 2)
array([[ 1. , 1.25 ],
[ 1.36111111, 1.42361111]])
Note that this will return 0-dimensional arrays for the scalar case.
Actually, on second thought, it should work for the z case too:
>>> h([[2,2], [2,2]], [[1,2],[3,4]])
array([[ 1.5 , 1.25 ],
[ 1.125 , 1.0625]])

arange generates evenly spaced 1D ndarray in range [1,limit+1] in your example.
Now say you want an multi-dim ndarray of evenly spaced arrays. Then you may use arange to generate each component of your 2D ndarray. You convert result of arange to a python list with list(), to make it the right format to be an argument of ndarray constructor.
It all depends on your purpose. As you deal with math. analysis, what you look for may be a grid:
>>> np.mgrid[0:5,0:5]
array([[[0, 0, 0, 0, 0],
[1, 1, 1, 1, 1],
[2, 2, 2, 2, 2],
[3, 3, 3, 3, 3],
[4, 4, 4, 4, 4]],
[[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4]]])
More here.
EDIT:
After you posted the code :
as DSM mentions, np.vectorize is a good way to do. From doc,
class numpy.vectorize(pyfunc, otypes='', doc=None, excluded=None,
cache=False)
Generalized function class.
Define a vectorized function which takes a nested sequence of objects
or numpy arrays as inputs and returns a numpy array as output. The
vectorized function evaluates pyfunc over successive tuples of the
input arrays like the python map function, except it uses the
broadcasting rules of numpy.

Related

Python - How to remove some terms of a numpy array in specific intervals

Suppose I have the following array:
import numpy as np
x = np.array([1,2,3,4,5,
1,2,3,4,5,
1,2,3,4,5])
How can I manipulate it to remove the term in equally spaced intervals and adapt the new length for it? For example, I'd like to have:
x = [1,2,3,4,
1,2,3,4,
1,2,3,4]
Where the terms from positions 4, 9, and 14 were excluded (so every 5 terms, one gets excluded). If possible, I'd like to have a code that I could use for an array with length N. Thank you in advance!
In your case, you can simply run code below after initializing the x array(as you did your question):
x.reshape(3,5)[:,:4]
Output
array([[1, 2, 3, 4],
[1, 2, 3, 4],
[1, 2, 3, 4]])
If you are interested in getting a vector and not a matrix(such as the output above), you can call the flatten function on the code above:
x.reshape(3,5)[:,:4].flatten()
Output
array([1, 2, 3, 4,
1, 2, 3, 4,
1, 2, 3, 4])
Explanation
Since x is a numpy array, we can use NumPy in-built functions such as reshape. This function, which has a self-explanatory name, shapes the array into the desired format. x was a vector of 15 elements. Therefore, running x.reshape(3,5) gives us a matrix with 3 rows and five columns. [:, :4] is to reselect the first four columns. flatten function changes a matrix into a vector.
IIUC, you can use a boolean mask generated with the modulo (%) operator:
N = 5
mask = np.arange(len(x))%N != N-1
x[mask]
output: array([1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4])
This works even if your array has not a size that is a multiple of N

Create numpy array within numpy array

I want to create a numpy array within a numpy array. If i do it with normal python its something like
a = [[1,2], [3,4]]
a[0][1] = [1,1,1]
print a
The result is [[1, [1, 1, 1]], [3, 4]]
How can I achieve the same using numpy arrays? The code I have is:
a = np.array([(1, 2, 3),(4, 5, 6)])
b = np.array([1,1,1])
a[0][1] = b
a as created is dtype int. Each element can only be another integer:
In [758]: a = np.array([(1, 2, 3),(4, 5, 6)])
...: b = np.array([1,1,1])
...:
In [759]: a
Out[759]:
array([[1, 2, 3],
[4, 5, 6]])
In [760]: b
Out[760]: array([1, 1, 1])
In [761]: a[0,1]=b
...
ValueError: setting an array element with a sequence.
You can make another dtype of array, one that holds pointers to objects, much as list does:
In [762]: aO = a.astype(object)
In [763]: aO
Out[763]:
array([[1, 2, 3],
[4, 5, 6]], dtype=object)
Now it is possible to replace one of those element pointers with a pointer to b array:
In [765]: aO[0,1]=b
In [766]: aO
Out[766]:
array([[1, array([1, 1, 1]), 3],
[4, 5, 6]], dtype=object)
But as asked in the comments - why do you want/need to do this? What are you going to do with such an array? It is possible to do some numpy math on such an array, but as shown in some recent SO questions, it is hit-or-miss. It is also slower.
As far as I know, you cannot do this. Numpy arrays cannot have entries of varying shape. Your request to make an array like [[1, [1, 1, 1]], [3, 4]] is impossible. However, you could make a numpy matrix of dimensions (3x2x3) to get
[
[
[1,0,0],
[1,1,1],
[0,0,0],
]
[
[3,0,0],
[4,0,0],
[0,0,0]
]
]
Your only option is to pad empty elements with some number (I used 0s above) or use another data structure.

How to create or fill an numpy array with another array?

How to create an numpy array with shape [2, 2, 3], where the elements at axis 2 is another array, for example [1, 2, 3]?
So I would like to do something like this invalid code:
a = np.arange(1, 4)
b = np.full((3, 3), a)
Resulting in an array like:
[[[ 1. 2. 3.]
[ 1. 2. 3.]]
[[ 1. 2. 3.]
[ 1. 2. 3.]]]
Could of course make the loop for filling like, but thought there may be a shortcut:
for y in range(b.shape[0]):
for x in range(b.shape[1]):
b[y, x, :] = a
There are multiple ways to achieve this. One is to use np.full in np.full((2,2,3), a) as pointed out by Divakar in the comments. Alternatively, you can use np.tile for this, which allows you to construct an array by repeating an input array a given number of times. To construct your example you could do:
import numpy as np
np.tile(np.arange(1, 4), [2, 2, 1])
If your numpy version is >= 1.10 you can use broadcast_to
a = np.arange(1,4)
a.shape = (1,1,3)
b = np.broadcast_to(a,(2,2,3))
This produces a view rather than copying so will be quicker for large arrays.
EDIT this looks to be the result you're asking for with your demo.
Based on Divakar comment, an answer can also be:
import numpy as np
np.full([2, 2, 3], np.arange(1, 4))
Yet another possibility is:
import numpy as np
b = np.empty([2, 2, 3])
b[:] = np.arange(1, 4)
Also using np.concatenate or it's wrapper np.vstack
In [26]: a = np.arange(1,4)
In [27]: np.vstack([a[np.newaxis, :]]*4).reshape(2,2, 3)
Out[27]:
array([[[1, 2, 3],
[1, 2, 3]],
[[1, 2, 3],
[1, 2, 3]]])
In [28]: np.concatenate([a[np.newaxis, :]]*4, axis=0).reshape(2,2, 3)
Out[28]:
array([[[1, 2, 3],
[1, 2, 3]],
[[1, 2, 3],
[1, 2, 3]]])

Create numpy array of arrays [duplicate]

How to create an numpy array with shape [2, 2, 3], where the elements at axis 2 is another array, for example [1, 2, 3]?
So I would like to do something like this invalid code:
a = np.arange(1, 4)
b = np.full((3, 3), a)
Resulting in an array like:
[[[ 1. 2. 3.]
[ 1. 2. 3.]]
[[ 1. 2. 3.]
[ 1. 2. 3.]]]
Could of course make the loop for filling like, but thought there may be a shortcut:
for y in range(b.shape[0]):
for x in range(b.shape[1]):
b[y, x, :] = a
There are multiple ways to achieve this. One is to use np.full in np.full((2,2,3), a) as pointed out by Divakar in the comments. Alternatively, you can use np.tile for this, which allows you to construct an array by repeating an input array a given number of times. To construct your example you could do:
import numpy as np
np.tile(np.arange(1, 4), [2, 2, 1])
If your numpy version is >= 1.10 you can use broadcast_to
a = np.arange(1,4)
a.shape = (1,1,3)
b = np.broadcast_to(a,(2,2,3))
This produces a view rather than copying so will be quicker for large arrays.
EDIT this looks to be the result you're asking for with your demo.
Based on Divakar comment, an answer can also be:
import numpy as np
np.full([2, 2, 3], np.arange(1, 4))
Yet another possibility is:
import numpy as np
b = np.empty([2, 2, 3])
b[:] = np.arange(1, 4)
Also using np.concatenate or it's wrapper np.vstack
In [26]: a = np.arange(1,4)
In [27]: np.vstack([a[np.newaxis, :]]*4).reshape(2,2, 3)
Out[27]:
array([[[1, 2, 3],
[1, 2, 3]],
[[1, 2, 3],
[1, 2, 3]]])
In [28]: np.concatenate([a[np.newaxis, :]]*4, axis=0).reshape(2,2, 3)
Out[28]:
array([[[1, 2, 3],
[1, 2, 3]],
[[1, 2, 3],
[1, 2, 3]]])

Python - construct a matrix by matrix of index

Suppose I have an array, I want to have a matrix from that array by a matrix of index.
import numpy as np
arr = np.array([1,5])
mtxidx = np.array([[0,1,0],[0,1,1],[0,0,0]])
How can I get a matrix [[1,5,1],[1,5,5],[1,1,1]] ?
An initial thought is simply say
arr(mtxidx)
however it doesn't work
Is there any function/method that do this elegantly?
"Fancy" indexing works for me (NB in your question you are trying to call the array object (round brackets) but NumPy "ndarray" objects are not callable):
In [61]: arr[mtxidx]
Out[61]:
array([[1, 5, 1],
[1, 5, 5],
[1, 1, 1]])
Your initial thought was pretty close, simply replacing the parenthesis with [] would make it work.
arr[mtxidx]
A list comprehension would work as well.
>>> np.array([arr[row] for row in mtxidx])
array([[1, 5, 1],
[1, 5, 5],
[1, 1, 1]])
I upvote the fancy indexing proposed by #xnx but if you would have done something in same range but involving an operation (or ..anything else) you can also try this :
arr = np.array([1,5])
mtxidx = np.array([[0,1,0],[0,1,1],[0,0,0]])
def func(v):
return arr[v]
vfunc = np.vectorize(func)
vfunc(mtxidx)
# array([[1, 5, 1],
# [1, 5, 5],
# [1, 1, 1]])

Categories

Resources