I have an array a
, and want to create a new matrix A
for which A[i,j] = a[i+j]
. Example:
import numpy as np
a = np.random.rand(3)
A = np.zeros((2,2));
for i in range(2):
for j in range(2):
A[i,j] = a[i+j]
Is there a way of doing this without a for loop? (with numpy)
stride_tricks.as_strided
This would be a perfect use case for stride_tricks
:
from np.lib.stride_tricks import as_strided
Set the strides as (8, 8)
(i.e. (1, 1)
in terms of slots). This way we essentially map the resulting array A
as i, j -> k = i + j
. A more detailed description would be: we map every i, j
pair to a natural number k
defined by the strides as k = i*s_i + j*s_j
, where s_i
and s_j
are the strides set to 1
s, i.e. k = i + j
. Thus ending up with the desired result: A[i, j] = a[k] = a[i + j]
.
>>> a
array([0.53954179, 0.51789927, 0.33982179])
>>> A = as_strided(a, shape=(2,2), strides=(8,8))
array([[0.53954179, 0.51789927],
[0.51789927, 0.33982179]])
A more general solution would be to get the shapes as well as the strides from a
's metadata.
The shape of A
is given by (len(a)//2+1,)*2
.
As noted by @Daniel F, the memory slot size does not always equal to 8
, this indeed depends on the dtype of your array. It would be better to define strides
from a
's strides instead: a.strides*2
.
This comes down to:
>>> A = as_strided(a, shape=(len(a)//2+1,)*2, strides=a.strides*2)
Alternatively, you can construct a grid of coordinates (you can do so using itertools.product
) then copy the appropriate values from a
to A
:
i, j = np.array(list(product(range(2), range(2)))).T
Then initialize A
and copy
:
>>> A = np.zeros((2,2))
>>> A[i, j] = a[i + j]
This will however double the memory usage, compared to the as_strided
method.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With