Stack slices of numpy array from given indices - python

I'm struggling to perform the below operation on a numpy vector.
I want to take previous_n samples from vector finishing at indices.
It's like I want to perform a np.take with slicing of the previous_n samples.
Example:
import numpy as np
vector = np.array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14])
# number of previous samples
previous_n = 3
indices = np.array([ 5, 7, 12])
result
array([[ 3, 4, 5],
[ 5, 6, 7],
[10, 11, 12]])

Ok, this seems to do what I want. Found here
def stack_slices(arr, previous_n, indices):
all_idx = indices[:, None] + np.arange(previous_n) - (previous_n - 1)
return arr[all_idx]
>>> stack_slices(vector, 3, indices)
array([[ 3, 4, 5],
[ 5, 6, 7],
[10, 11, 12]])

Related

Get multiplication table generalized for n dimensions with numpy

Let a = np.arange(1, 4).
To get the 2 dimensional multiplication table for a, I do:
>>> a * a[:, None]
>>> array([[1, 2, 3],
[2, 4, 6],
[3, 6, 9]])
For 3 dimensions, I can do the following:
>>> a * a[:, None] * a[:, None, None]
>>> array([[[ 1, 2, 3],
[ 2, 4, 6],
[ 3, 6, 9]],
[[ 2, 4, 6],
[ 4, 8, 12],
[ 6, 12, 18]],
[[ 3, 6, 9],
[ 6, 12, 18],
[ 9, 18, 27]]])
How could I write a function that takes a numpy array a and a number of dimensions n as input and ouputs the n dimensional multiplication table for a?
This should do what you need:
import itertools
a = np.arange(1, 4)
n = 3
def f(x, y):
return np.expand_dims(x, len(x.shape))*y
l = list(itertools.accumulate(np.repeat(np.atleast_2d(a), n, axis=0), f))[-1]
Just change n to be whatever dimension you need
First we can use numpy.expand_dims() for dynamically promoting the array dimensions as needed in a list/generator comprehension and then use an iterable product tool such as math.prod on Python 3.8+. The implementation would then look like as demonstrated below:
from math import prod
def n_dim_multiplication(arr, num_dims):
gen_arr = (np.expand_dims(a, axis=tuple(range(1, idx+1))) for idx in range(num_dims))
return prod(gen_arr)
Sample run for the 3 dimensional case:
# input array
In [83]: a = np.arange(1, 4)
# desired number of dimensions
In [84]: num_dims = 3
In [85]: n_dim_multiplication(a, num_dims)
Out[85]:
array([[[ 1, 2, 3],
[ 2, 4, 6],
[ 3, 6, 9]],
[[ 2, 4, 6],
[ 4, 8, 12],
[ 6, 12, 18]],
[[ 3, 6, 9],
[ 6, 12, 18],
[ 9, 18, 27]]])

Change the format of a numpy array in python

I have a (2x2) numpy array which contains an (1x3) list, like this below:
[[ 1, 2, 3], [ 4, 5, 6]
[ 7, 8, 9], [10,11,12]]
and I want to break it to single elements like this (2x6) array (or matrix, I can't tell the difference):
[ 1, 2, 3, 4, 5, 6]
[ 7, 8, 9, 10, 11, 12]
I can create the second array by coping every single element of the first array and put it to the second one. Yet I wonder if there is a more easy way provided by the numpy library.
you can simply use resize function to do this
import numpy as np
a=[[ 1, 2, 3], [ 4, 5, 6],
[ 7, 8, 9], [10,11,12]]
a = numpy.array(a)
a.resize(2,6)
print(a)
OUTPUT
array([[ 1, 2, 3, 4, 5, 6],
[ 7, 8, 9, 10, 11, 12]])

Numpy operation to expand array into sequential slices of given length?

my_function must expand a 1D numpy array to a 2D numpy array, with the 2nd axis containing the slices of length starting from the first index until the end. Example:
import numpy as np
a = np.arange(10)
print (my_function(a, length=3))
Expected output
array([[0, 1, 2],
[1, 2, 3],
[2, 3, 4],
[3, 4, 5],
[4, 5, 6],
[5, 6, 7],
[6, 7, 8],
[7, 8, 9]])
I can achieve this using a for loop, but I was wondering if there is a numpy vectorization technique for this.
def my_function(a, length):
b = np.zeros((len(a)-(length-1), length))
for i in range(len(b)):
b[i] = a[i:i+length]
return b
If you're careful with the math and heed the warningin the docs, you can use np.lib.stride_tricks.as_strided(). You need to calculate the correct dimensions for your array so you don't overflow. Also note that as_strided() shares memory, so you will multiple references to the same memory in the final output. (You can of course, copy this to a new array).
>> import numpy as np
>> def my_function(a, length):
stride = a.strides[0]
l = len(a) - length + 1
return np.lib.stride_tricks.as_strided(a, (l, length), (stride,stride) )
>> np.array(my_function(np.arange(10), 3))
array([[0, 1, 2],
[1, 2, 3],
[2, 3, 4],
[3, 4, 5],
[4, 5, 6],
[5, 6, 7],
[6, 7, 8],
[7, 8, 9]])
>> np.array(my_function(np.arange(15), 7))
array([[ 0, 1, 2, 3, 4, 5, 6],
[ 1, 2, 3, 4, 5, 6, 7],
[ 2, 3, 4, 5, 6, 7, 8],
[ 3, 4, 5, 6, 7, 8, 9],
[ 4, 5, 6, 7, 8, 9, 10],
[ 5, 6, 7, 8, 9, 10, 11],
[ 6, 7, 8, 9, 10, 11, 12],
[ 7, 8, 9, 10, 11, 12, 13],
[ 8, 9, 10, 11, 12, 13, 14]])
How about this function?
import numpy as np
def my_function(a, length):
result = []
for i in range(length):
result.append(a + i)
return np.vstack(result).T[:len(a) - length + 1]
a = np.arange(10)
length = 3
my_function(a, length)

Creating history of data from 2d numpy arrays?

Suppose I have a 2-dimensional numpy array of shape n X m (where n is large number and m >=1 ). Each column represents one attribute. An example for n=5, m=3 is provided below:
[[1,2,3],
[4,5,6],
[7,8,9],
[10,11,12],
[13,14,15]]
I want to train my model on the history of attributes with history_steps = p(1< p <= n). For p=2, the output I expect (of shape (n-p+1 X m*p)) is
[[1,4,2,5,3,6],
[4,7,5,8,6,9],
[7,10,8,11,9,12],
[10,13,11,14,12,15]]
I tried to implement this in pandas by separating columns and then concatenating outputs.
def buff(s, n):
return (pd.concat([s.shift(-i) for i in range(n)], axis=1).dropna().astype(float))
But, for my purposes a numpy based approach will be better. Also, I would like to avoid splitting and concatenating.
How do I go about doing this?
Here's a NumPy based approach with focus on performance using np.lib.stride_tricks.as_strided -
def strided_axis0(a, L = 2):
# INPUTS :
# a : Input array
# L : Length along rows to be cut to create per subarray
# Store shape and strides info
m,n = a.shape
s0,s1 = a.strides
nrows = m - L + 1
strided = np.lib.stride_tricks.as_strided
# Finally use strides to get the 3D array view and then reshape
return strided(a, shape=(nrows,n,L), strides=(s0,s1,s0)).reshape(nrows,-1)
Sample run -
In [27]: a
Out[27]:
array([[ 1, 2, 3],
[ 4, 5, 6],
[ 7, 8, 9],
[10, 11, 12],
[13, 14, 15]])
In [28]: strided_axis0(a, L=2)
Out[28]:
array([[ 1, 4, 2, 5, 3, 6],
[ 4, 7, 5, 8, 6, 9],
[ 7, 10, 8, 11, 9, 12],
[10, 13, 11, 14, 12, 15]])
You can use dstack + reshape:
a = np.array([[1,2,3],
[4,5,6],
[7,8,9],
[10,11,12],
[13,14,15]])
# use `dstack` to stack the two arrays(one with last row removed, the other with first
# row removed), along the third axis, and then use reshape to flatten the second and third
# dimensions
np.dstack([a[:-1], a[1:]]).reshape(a.shape[0]-1, -1)
#array([[ 1, 4, 2, 5, 3, 6],
# [ 4, 7, 5, 8, 6, 9],
# [ 7, 10, 8, 11, 9, 12],
# [10, 13, 11, 14, 12, 15]])
To generalize to arbitrary p, use a list comprehension to generate a list of shifted arrays and then do stack+reshape:
n, m = a.shape
p = 3
np.dstack([a[i:(n-p+i+1)] for i in range(p)]).reshape(n-p+1, -1)
#array([[ 1, 4, 7, 2, 5, 8, 3, 6, 9],
# [ 4, 7, 10, 5, 8, 11, 6, 9, 12],
# [ 7, 10, 13, 8, 11, 14, 9, 12, 15]])

Reverse diagonal on numpy python

let's say I have this:
(numpy array)
a=
[0 1 2 3],
[4 5 6 7],
[8 9 10 11]
to get [1,1] which is 5 its diagonal is zero; according to numpy, a.diagonal(0)= [0,5,10]. How do I get the reverse or the right to left diagonal [2,5,8] for [1,1]? Is this possible?
My original problem is an 8 by 8 (0:7).. I hope that helps
Get a new array each row reversed.
>>> import numpy as np
>>> a = np.array([
... [0, 1, 2, 3],
... [4, 5, 6, 7],
... [8, 9, 10, 11]
... ])
>>> a[:, ::-1]
array([[ 3, 2, 1, 0],
[ 7, 6, 5, 4],
[11, 10, 9, 8]])
>>> a[:, ::-1].diagonal(1)
array([2, 5, 8])
or using numpy.fliplr:
>>> np.fliplr(a).diagonal(1)
array([2, 5, 8])
Flip the array upside-down and use the same:
np.flipud(a).diagonal(0)[::-1]
Another way to achieve this is to use np.rot90
import numpy as np
a = np.array([[0, 1, 2, 3],
[4, 5, 6, 7],
[8, 9, 10, 11]])
my_diag = np.rot90(a).diagonal(-1)
Result:
>>> my_diag
array([2, 5, 8])
A number of answers so far. #Akavall is closest as you need to rotate or filip and transpose (equivilant operations). I haven't seen a response from the OP regarding expected behavior on the "long" part of the rectangle.
Generalized solution for a square matrix:
a = array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19],
[20, 21, 22, 23, 24]])
>>> [(i, np.rot90(a).diagonal(2*i-a.shape[0]+1)) for i in range(a.shape[0])]
[(0, array([0])),
(1, array([ 2, 6, 10])),
(2, array([ 4, 8, 12, 16, 20])),
(3, array([14, 18, 22])),
(4, array([24]))]
As a function:
def reverse_diag(arr, n):
idx = 2*n - arr.shape[0]+1
return np.rot90(arr).diagonal(idx)
original matrix can be made square with a[:np.min(a.shape),:np.min(a.shape)]
EDIT: OP indicated the array is square.... Final Answer is the above

Categories

Resources