Duplicate after every row and column in numpy array - python

I have the following array:
first = array([[4, 5],
[7, 9]])
And I would like to duplicate every element i into every following i + 1 row and i + 1 column.
My output should look like this:
array([[4, 4, 5, 5],
[4, 4, 5, 5],
[7, 7, 9, 9],
[7, 7, 9, 9]])

Just repeat twice:
>>> first.repeat(2, axis=1).repeat(2, axis=0)
array([[4, 4, 5, 5],
[4, 4, 5, 5],
[7, 7, 9, 9],
[7, 7, 9, 9]])
Slightly more compact:
first.repeat(2,1).repeat(2,0)

You can use scipy.ndimage.zoom with the order set to 0 to keep replicating your array
>>> arr
array([[4, 5],
[7, 9]])
>>> scipy.ndimage.zoom(arr, 2, order=0)
array([[4, 4, 5, 5],
[4, 4, 5, 5],
[7, 7, 9, 9],
[7, 7, 9, 9]])
zoom also works with greater values and/or can approximate to floats (zooming in or out) and in different scales by-axis (including higher dimensions)
>>> scipy.ndimage.zoom(arr, 5, order=0)
array([[4, 4, 4, 4, 4, 5, 5, 5, 5, 5],
[4, 4, 4, 4, 4, 5, 5, 5, 5, 5],
[4, 4, 4, 4, 4, 5, 5, 5, 5, 5],
[4, 4, 4, 4, 4, 5, 5, 5, 5, 5],
[4, 4, 4, 4, 4, 5, 5, 5, 5, 5],
[7, 7, 7, 7, 7, 9, 9, 9, 9, 9],
[7, 7, 7, 7, 7, 9, 9, 9, 9, 9],
[7, 7, 7, 7, 7, 9, 9, 9, 9, 9],
[7, 7, 7, 7, 7, 9, 9, 9, 9, 9],
[7, 7, 7, 7, 7, 9, 9, 9, 9, 9]])
>>> scipy.ndimage.zoom(arr, 0.5, order=0)
array([[4]])
>>> scipy.ndimage.zoom(arr, (2,3), order=0)
array([[4, 4, 4, 5, 5, 5],
[4, 4, 4, 5, 5, 5],
[7, 7, 7, 9, 9, 9],
[7, 7, 7, 9, 9, 9]])

Related

Python: how to get random contiguous sets?

This is what I get by running train_test_split
In [1]:train_test_split([1,2,3,4,5,6,7,8,9,10],test_size = 0.2)
Out[1]: [[10, 3, 6, 5, 4, 2, 7, 9], [8, 1]]
However, what I want is a contiguous set, i.e.
[[1, 2, 3, 4, 5, 6, 7, 10], [8, 9]]
or
[[1, 2, 3, 4, 5, 8, 9, 10], [6, 7]]
or
[[1, 2, 5, 6, 7, 8, 9, 10], [3, 4]]
****** Please note that the following is also considered contiguous**
[[2, 3, 4, 5, 6, 7, 8, 9], [10, 1]]
How can I do this ?
Can you try the following:
import random
def custom_train_test_split(X, test_size=0.2):
temp = X.copy()
split_size = int(len(temp) * test_size)
start = random.randint(0, len(X) - split_size)
end = start + split_size
test = temp[start:end]
del temp[start:end]
return [temp, test]
X = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(custom_train_test_split(X, test_size=0.2))
print(custom_train_test_split(X, test_size=0.2))
print(custom_train_test_split(X, test_size=0.2))
Output:
[[1, 2, 5, 6, 7, 8, 9, 10], [3, 4]]
[[1, 2, 3, 4, 5, 8, 9, 10], [6, 7]]
[[3, 4, 5, 6, 7, 8, 9, 10], [1, 2]]

Update a position in list of list Python

I have a list:
[[6, 8, 5, 1, 3, 2, 9, 4, 7],
[7, 3, 4, 5, 9, 8, 2, 1, 6],
[2, 1, 9, 7, 6, 4, 8, 5, 3],
[9, 2, 6, 8, 7, 1, 5, 3, 4],
[8, 5, 1, 3, 4, 9, 6, 7, 2],
[4, 7, 3, 2, 5, 6, 1, 8, 9],
[5, 6, 8, 4, 2, 7, 3, 9, 1],
[3, 4, 2, 9, 1, 5, 7, 6, 8],
[1, 9, 7, 6, 8, 3, 4, 2, 5]]
I want to update a position in this list
for example:
update_list(position: tuple[int, int], value: Optional[int])
where value is the element that is going to replace the original element in the list
Thus update_list((1, 1), 5) should replace 3 with 5
What is the best way to code for this?
You can directly index into the inner list!
>>> content = [[6, 8, 5, 1, 3, 2, 9, 4, 7],
... [7, 3, 4, 5, 9, 8, 2, 1, 6],
... [2, 1, 9, 7, 6, 4, 8, 5, 3],
... [9, 2, 6, 8, 7, 1, 5, 3, 4],
... [8, 5, 1, 3, 4, 9, 6, 7, 2],
... [4, 7, 3, 2, 5, 6, 1, 8, 9],
... [5, 6, 8, 4, 2, 7, 3, 9, 1],
... [3, 4, 2, 9, 1, 5, 7, 6, 8],
... [1, 9, 7, 6, 8, 3, 4, 2, 5]]
>>> content[1][1]
3
>>> content[1][1] = 5
>>> content[1][1]
5
>>> content
[[6, 8, 5, 1, 3, 2, 9, 4, 7], [7, 5, 4, 5, 9, 8, 2, 1, 6], [2, 1, 9, 7, 6, 4, 8, 5, 3], [9, 2, 6, 8, 7, 1, 5, 3, 4], [8, 5, 1, 3, 4, 9, 6, 7, 2], [4, 7, 3, 2, 5, 6, 1, 8, 9], [5, 6, 8, 4, 2, 7, 3, 9, 1], [3, 4, 2, 9, 1, 5, 7, 6, 8], [1, 9, 7, 6, 8, 3, 4, 2, 5]]
This one works for me:
content = [[6, 8, 5],[1, 2, 3]]
def update_list(a, b):
content[a[0]][a[1]] = b
update_list((0,0),25) #It replace the first element by 25
The Output of content:
[[25, 8, 5], [1, 2, 3]]

Insert a string at a specified index in 2D array

I would like to insert a string at a specified index in a row of an array by 2 steps. From a matrix:
A=[[1, 2, 3, 4, 5],
[6, 7, 8, 9, 10],
[1, 1, 2, 2, 3],
[2, 3, 4, 5, 6],
[4, 5, 6, 7, 7],
[5, 7, 6, 8, 9]]
I would like to receive:
A=[[**x**, 2, 3, 4, 5],
[6, 7, 8, 9, 10],
[**x**, 1, 2, 2, 3],
[2, 3, 4, 5, 6],
[**x**, 5, 6, 7, 7],
[5, 7, 6, 8, 9]]
or:
A=[[1, 2, 3, 4, 5],
[**x**, 7, 8, 9, 10],
[1, 1, 2, 2, 3],
[**x**, 3, 4, 5, 6],
[4, 5, 6, 7, 7],
[**x**, 7, 6, 8, 9]]
or:
A=[[1, 2, **x**, 4, 5],
[6, 7, 8, 9, 10],
[1, 1, **x**, 2, 3],
[2, 3, 4, 5, 6],
[4, 5, **x**, 7, 7],
[5, 7, 6, 8, 9]]
and so on. I hope you understand my question (I used bold letters in order to distinguish strings). If I try:
def r(l):
for i in l[::2]:
i.insert(0, 'x')
return l
it returns:
'int' object has no attribute 'insert'
but I suppose it isn't my very valuable comment, if I end up with no clue how I can complete the task...
You can use simple indexing instead of insert:
def r(l, idx=0):
for i in l[::2]:
i[idx] = 'x'
return l
>>> print(r(A))
[['x', 2, 3, 4, 5], [6, 7, 8, 9, 10], ['x', 1, 2, 2, 3], [2, 3, 4, 5, 6], ['x', 5, 6, 7, 7], [5, 7, 6, 8, 9]]
The idx argument gives you the index where you want to change the entry. For example, if you wanted to change the 3rd element to x, then use:
>>> print(r(A, idx=2))
[[1, 2, 'x', 4, 5], [6, 7, 8, 9, 10], [1, 1, 'x', 2, 3], [2, 3, 4, 5, 6], [4, 5, 'x', 7, 7], [5, 7, 6, 8, 9]]

Copying 2D Array into 3D w/ one less row n times

I have a 2D array, and I need to make it into a 3D array - with the next layer starting with the second row of the first layer.
This is my best attempt to visually show what I want to do, with four 'layers':
# original array
dat = np.array([[0, 0, 0, 0, 9]
[1, 1, 1, 1, 9],
[2, 2, 2, 2, 9],
[3, 3, 3, 3, 9],
[4, 4, 4, 4, 9],
[5, 5, 5, 5, 9],
[6, 6, 6, 6, 9],
[7, 7, 7, 7, 9],
[8, 8, 8, 8, 9]], np.int32
)
#dat.shape
#(8, 5)
layers = 4
# new 3d array
# first 'layer'
[0, 0, 0, 0, 9],
[1, 1, 1, 1, 9],
[2, 2, 2, 2, 9],
[3, 3, 3, 3, 9],
[4, 4, 4, 4, 9],
[5, 5, 5, 5, 9]
# second 'layer'
[1, 1, 1, 1, 9],
[2, 2, 2, 2, 9],
[3, 3, 3, 3, 9],
[4, 4, 4, 4, 9],
[5, 5, 5, 5, 9],
[6, 6, 6, 6, 9]
# third 'layer'
[2, 2, 2, 2, 9],
[3, 3, 3, 3, 9],
[4, 4, 4, 4, 9],
[5, 5, 5, 5, 9],
[6, 6, 6, 6, 9],
[7, 7, 7, 7, 9]
# fourth 'layer'
[3, 3, 3, 3, 9],
[4, 4, 4, 4, 9],
[5, 5, 5, 5, 9],
[6, 6, 6, 6, 9],
[7, 7, 7, 7, 9],
[8, 8, 8, 8, 9]
# new shape: (rows, layers, columns)
#dat.shape
#(6, 4, 5)
I realize my visual representation of the layers might not be the way I say it is at the end, but that is the shape that I'm trying to get it in.
Solutions that I've tried include a variation of np.repeat(dat[:, :, np.newaxis], steps, axis=2) but for some reason I struggle once it's more than two dimensions.
Appreciate any help!
Approach #1: Here's one approach using broadcasting -
layers = 4
L = dat.shape[0]-layers+1
out = dat[np.arange(L) + np.arange(layers)[:,None]]
If you actually need a (6,4,5) shaped array, we would need slight modification :
out = dat[np.arange(L)[:,None] + np.arange(layers)]
Approach #2: Here's another with NumPy strides -
strided = np.lib.stride_tricks.as_strided
m,n = dat.strides
N = dat.shape[1]
out = strided(dat, shape = (layers,L,N), strides= (m,N*n,n))
For (6,4,5) shaped output array,
out = strided(dat, shape = (L,layers,N), strides= (N*n,m,n))
Note that this second method would create a view into input array dat and is very efficient to be created. If you need a copy instead, append .copy() at the end : out.copy().
Sample output for (6,4,5) output -
In [267]: out[:,0,:]
Out[267]:
array([[0, 0, 0, 0, 9],
[1, 1, 1, 1, 9],
[2, 2, 2, 2, 9],
[3, 3, 3, 3, 9],
[4, 4, 4, 4, 9],
[5, 5, 5, 5, 9]])
In [268]: out[:,1,:]
Out[268]:
array([[1, 1, 1, 1, 9],
[2, 2, 2, 2, 9],
[3, 3, 3, 3, 9],
[4, 4, 4, 4, 9],
[5, 5, 5, 5, 9],
[6, 6, 6, 6, 9]])
In [269]: out[:,2,:]
Out[269]:
array([[2, 2, 2, 2, 9],
[3, 3, 3, 3, 9],
[4, 4, 4, 4, 9],
[5, 5, 5, 5, 9],
[6, 6, 6, 6, 9],
[7, 7, 7, 7, 9]])
In [270]: out[:,3,:]
Out[270]:
array([[3, 3, 3, 3, 9],
[4, 4, 4, 4, 9],
[5, 5, 5, 5, 9],
[6, 6, 6, 6, 9],
[7, 7, 7, 7, 9],
[8, 8, 8, 8, 9]])

How to use numpy to add any two elements in an array and produce a matrix?

The native python codes are like this:
>>> a=[1,2,3,4,5,6]
>>> [[i+j for i in a] for j in a]
[[2, 3, 4, 5, 6, 7],
[3, 4, 5, 6, 7, 8],
[4, 5, 6, 7, 8, 9],
[5, 6, 7, 8, 9, 10],
[6, 7, 8, 9, 10, 11],
[7, 8, 9, 10, 11, 12]]
However, I have to use numpy to do this job as the array is very large.
Does anyone have ideas about how to do the same work in numpy?
Many NumPy binary operators have an outer method which can be used to form the equivalent of a multiplication (or in this case, addition) table:
In [260]: import numpy as np
In [255]: a = np.arange(1,7)
In [256]: a
Out[256]: array([1, 2, 3, 4, 5, 6])
In [259]: np.add.outer(a,a)
Out[259]:
array([[ 2, 3, 4, 5, 6, 7],
[ 3, 4, 5, 6, 7, 8],
[ 4, 5, 6, 7, 8, 9],
[ 5, 6, 7, 8, 9, 10],
[ 6, 7, 8, 9, 10, 11],
[ 7, 8, 9, 10, 11, 12]])

Categories