What does "wrap" in np.pad actually do? - python

When I am padding a numpy 2d array with mode='wrap', the return from it make me confuse:
import numpy as np
a = np.arange(9, dtype=float).reshape(3, 3)
print(np.pad(a, [(2, 4), (1, 1)], mode='wrap'))
it return:
[[5. 3. 4. 5. 3.]
[8. 6. 7. 8. 6.]
[2. 0. 1. 2. 0.]
[5. 3. 4. 5. 3.]
[8. 6. 7. 8. 6.]
[2. 0. 1. 2. 0.]
[5. 3. 4. 5. 3.]
[8. 6. 7. 8. 6.]
[5. 3. 4. 5. 3.]]
the last row is[[5. 3. 4. 5. 3.]], but I think(expect) it should be [[2. 0. 1. 2. 0.]], that is it will repeat the given array again and again.
The fowolling code is I expect wrap should do:
def pad(array, pad_width, mode='wrap'):
"""pad_width definition is same as np.pad()"""
size = array.shape[0] + pad_width[0][0] + pad_width[0][1], array.shape[1] + pad_width[1][0] + pad_width[1][1]
if mode=='wrap':
arr = np.empty(size, dtype=array.dtype)
for i in range(size[0]):
for j in range(size[1]):
arr[i, j] = array[(i-pad_width[0][0])%array.shape[0], (j-pad_width[1][0])%array.shape[0]]
else:
print('Not define')
return
return arr
a = np.arange(9, dtype=float).reshape(3, 3)
print(pad(a, [(2, 4), (1, 1)], mode='wrap'))
return:
[[5. 3. 4. 5. 3.]
[8. 6. 7. 8. 6.]
[2. 0. 1. 2. 0.]
[5. 3. 4. 5. 3.]
[8. 6. 7. 8. 6.]
[2. 0. 1. 2. 0.]
[5. 3. 4. 5. 3.]
[8. 6. 7. 8. 6.]
[2. 0. 1. 2. 0.]]
Can someone explain what is "wrap" actually doing, thank you!
Edited(2nd):
Now, I have some feeling about what wrap did, it uses the definition of "wrap" and done by recursive to pad the array, but I still wonder what is usefulness of wrap padding?(I didn't make sense of this strange algorithm.)

Here's the definition of wrap mode :
'wrap'
Pads with the wrap of the vector along the axis.
The first values are used to pad the end and the
end values are used to pad the beginning.
And here's the code in pad method :
#array_function_dispatch(_pad_dispatcher, module='numpy')
def pad(array, pad_width, mode='constant', **kwargs):
array = np.asarray(array)
pad_width = np.asarray(pad_width)
if not pad_width.dtype.kind == 'i':
raise TypeError('`pad_width` must be of integral type.')
# Broadcast to shape (array.ndim, 2)
pad_width = _as_pairs(pad_width, array.ndim, as_index=True)
if callable(mode):
# Old behavior: Use user-supplied function with np.apply_along_axis
function = mode
# Create a new zero padded array
padded, _ = _pad_simple(array, pad_width, fill_value=0)
# And apply along each axis
for axis in range(padded.ndim):
# Iterate using ndindex as in apply_along_axis, but assuming that
# function operates inplace on the padded array.
# view with the iteration axis at the end
view = np.moveaxis(padded, axis, -1)
# compute indices for the iteration axes, and append a trailing
# ellipsis to prevent 0d arrays decaying to scalars (gh-8642)
inds = ndindex(view.shape[:-1])
inds = (ind + (Ellipsis,) for ind in inds)
for ind in inds:
function(view[ind], pad_width[axis], axis, kwargs)
return padded
# Make sure that no unsupported keywords were passed for the current mode
allowed_kwargs = {
'empty': [], 'edge': [], 'wrap': [],
'constant': ['constant_values'],
'linear_ramp': ['end_values'],
'maximum': ['stat_length'],
'mean': ['stat_length'],
'median': ['stat_length'],
'minimum': ['stat_length'],
'reflect': ['reflect_type'],
'symmetric': ['reflect_type'],
}
try:
unsupported_kwargs = set(kwargs) - set(allowed_kwargs[mode])
except KeyError:
raise ValueError("mode '{}' is not supported".format(mode)) from None
if unsupported_kwargs:
raise ValueError("unsupported keyword arguments for mode '{}': {}"
.format(mode, unsupported_kwargs))
stat_functions = {"maximum": np.amax, "minimum": np.amin,
"mean": np.mean, "median": np.median}
# Create array with final shape and original values
# (padded area is undefined)
padded, original_area_slice = _pad_simple(array, pad_width)
# And prepare iteration over all dimensions
# (zipping may be more readable than using enumerate)
axes = range(padded.ndim)
#All the other modes...
elif mode == "wrap":
for axis, (left_index, right_index) in zip(axes, pad_width):
roi = _view_roi(padded, original_area_slice, axis)
while left_index > 0 or right_index > 0:
# Iteratively pad until dimension is filled with wrapped
# values. This is necessary if the pad area is larger than
# the length of the original values in the current dimension.
left_index, right_index = _set_wrap_both(
roi, axis, (left_index, right_index))
return padded
Now you can see the difference with what you assume it was doing and what it's really doing
You can find those information in the Numpy GitHub. The code for pad is in the file arraypad.py located at numpy/numpy/lib/arraypad.py

Related

Replace column by 0 based on probability

How to replace column in the numpy array be certain number based on probability, if it is (1,X,X) shape.
I found code to replace rows, but cannot figure out how to modify it, so it is applicable for columns replacement.
grid_example = np.random.rand(1,5,5)
probs = np.random.random((1,5))
grid_example[probs < 0.25] = 0
grid_example
Thanks!
Use:
import numpy as np
rng = np.random.default_rng(42)
grid_example = rng.random((1, 5, 5))
probs = rng.random((1, 5))
grid_example[..., (probs < 0.25).flatten()] = 0
print(grid_example)
Output
[[[0. 0.43887844 0. 0. 0.09417735]
[0. 0.7611397 0. 0. 0.45038594]
[0. 0.92676499 0. 0. 0.4434142 ]
[0. 0.55458479 0. 0. 0.6316644 ]
[0. 0.35452597 0. 0. 0.7783835 ]]]
The notation [..., (probs < 0.25).flatten()] applies the boolean indexing to the last index. More on the documentation.

Create Jordan matrix from eigenvalues using NumPy

I have ndarray of eigenvalues and their multiplicities (for instance, np.array([(2.2, 2), (3, 3), (5, 1)])). I need to compute Jordan matrix for this eigenvalues without using Python cycles and iterables (list comprehensions, for loops etc.), only by using NumPy's functions.
I decided to build the matrix by this steps:
Create this blocks using np.vectorize and np.eye with np.fill_diagonal:
Combine blocks into one matrix using hstack and vstack.
But I've got two problems:
Here's snippet of my block creating code:
def eye(t):
eye = np.eye(t[1].astype(int),k=1)
return eye
def jordan_matrix(X: np.ndarray) -> np.ndarray:
dim = np.sum(X[:,1].astype(int))
eyes = np.vectorize(eye, signature='(x)->(n,m)')(X)
return eyes
And I'm getting error ValueError: could not broadcast input array from shape (3,3) into shape (2,2)
I need to create extra zero matrices to fill space which is not used by created blocks, but their sizes are variable and I can't figure out how to create them without using Python's for and its equivalents.
Am I on the right way? How can I get out of this problems?
np.vectorize would basically loop under the hoods. We could use NumPy funcs for actual vectorization at Python level. Here's one such way -
def blockwise_jordan(a):
r = a[:,1].astype(int)
v = np.repeat(a[:,0],r)
out = np.diag(v)
n = out.shape[1]
fillvals = np.ones(n, dtype=out.dtype)
fillvals[r[:-1].cumsum()-1] = 0
out.flat[1::out.shape[1]+1] = fillvals
return out
Sample run -
In [52]: X = np.array([(2.2, 2), (3, 3), (5, 1)])
In [53]: blockwise_jordan(X)
Out[53]:
array([[2.2, 1. , 0. , 0. , 0. , 0. ],
[0. , 2.2, 0. , 0. , 0. , 0. ],
[0. , 0. , 3. , 1. , 0. , 0. ],
[0. , 0. , 0. , 3. , 1. , 0. ],
[0. , 0. , 0. , 0. , 3. , 0. ],
[0. , 0. , 0. , 0. , 0. , 5. ]])
Optimization #1
We can replace the final three steps to perform the conditional assignment of 1s and 0s, like so -
out.flat[1::n+1] = 1
c = r[:-1].cumsum()-1
out[c,c+1] = 0
Here's my solution:
def jordan(a):
e = a[:,0] # eigenvalues
m = a[:,1].astype('int') # multiplicities
d = np.repeat(e, m) # main diagonal
ones = np.ones(d.size - 1)
ones[np.cumsum(m)[:-1] -1] = 0
j = np.diag(d) + np.diag(ones, k=1)
return j
Edit: just realized that my solution is almost the same as Divakar's.

Raise diagonal matrix to the negative power 1/2

I am trying to compute the matrix which has the following equation.
S = (D^−1/2) * W * (D^−1/2)
where D is a diagonal matrix of this form:
array([[ 0.59484625, 0. , 0. , 0. ],
[ 0. , 0.58563893, 0. , 0. ],
[ 0. , 0. , 0.58280472, 0. ],
[ 0. , 0. , 0. , 0.58216725]])
and W:
array([[ 0. , 0.92311635, 0.94700586, 0.95599748],
[ 0.92311635, 0. , 0.997553 , 0.99501248],
[ 0.94700586, 0.997553 , 0. , 0.9995501 ],
[ 0.95599748, 0.99501248, 0.9995501 , 0. ]])
I tried to compute D^-1/2 by using numpy function linalg.matrix_power(D,-1/2) and numpy.power(D,-1/2) and matrix_power function raises TypeError: exponent must be an integer and numpy.power function raises RuntimeWarning: divide by zero encountered in power.
How to compute negative power -1/2 for diagonal matrix. Please help.
If you can update D(like in your own answer) then simply update the items at its diagonal indices and then call np.dot:
>>> D[np.diag_indices(4)] = 1/ (D.diagonal()**0.5)
>>> np.dot(D, W).dot(D)
array([[ 0. , 0.32158153, 0.32830723, 0.33106193],
[ 0.32158153, 0. , 0.34047794, 0.33923936],
[ 0.32830723, 0.34047794, 0. , 0.33913717],
[ 0.33106193, 0.33923936, 0.33913717, 0. ]])
Or create a new zeros array and then fill its diagonal elements with 1/ (D.diagonal()**0.5):
>>> arr = np.zeros(D.shape)
>>> np.fill_diagonal(arr, 1/ (D.diagonal()**0.5))
>>> np.dot(arr, W).dot(arr)
array([[ 0. , 0.32158153, 0.32830723, 0.33106193],
[ 0.32158153, 0. , 0.34047794, 0.33923936],
[ 0.32830723, 0.34047794, 0. , 0.33913717],
[ 0.33106193, 0.33923936, 0.33913717, 0. ]])
I got the answer by computing thro' mathematical terms but would love to see any straight forward one liners :)
def compute_diagonal_to_negative_power():
for i in range(4):
for j in range(4):
if i == j:
element = D[i][j]
numerator = 1
denominator = math.sqrt(element)
D[i][j] = numerator / denominator
return D
diagonal_matrix = compute_diagonal_to_negative_power()
S = np.dot(diagonal_matrix, W).dot(diagonal_matrix)
print(S)
"""
[[ 0. 0.32158153 0.32830723 0.33106193]
[ 0.32158153 0. 0.34047794 0.33923936]
[ 0.32830723 0.34047794 0. 0.33913718]
[ 0.33106193 0.33923936 0.33913718 0. ]]
"""
Source: https://math.stackexchange.com/questions/340321/raising-a-square-matrix-to-a-negative-half-power
You can do the following:
numpy.power(D,-1/2, where=(D!=0))
And then you will avoid getting the warning:
RuntimeWarning: divide by zero encountered in power
numpy will divide every value on the matrix element-wise by it's own square root, which is not zero, so basically you won't try to divide by zero anymore.

Making a matrix square and padding it with desired value in numpy

In general we could have matrices of arbitrary sizes. For my application it is necessary to have square matrix. Also the dummy entries should have a specified value. I am wondering if there is anything built in numpy?
Or the easiest way of doing it
EDIT :
The matrix X is already there and it is not squared. We want to pad the value to make it square. Pad it with the dummy given value. All the original values will stay the same.
Thanks a lot
Building upon the answer by LucasB here is a function which will pad an arbitrary matrix M with a given value val so that it becomes square:
def squarify(M,val):
(a,b)=M.shape
if a>b:
padding=((0,0),(0,a-b))
else:
padding=((0,b-a),(0,0))
return numpy.pad(M,padding,mode='constant',constant_values=val)
Since Numpy 1.7, there's the numpy.pad function. Here's an example:
>>> x = np.random.rand(2,3)
>>> np.pad(x, ((0,1), (0,0)), mode='constant', constant_values=42)
array([[ 0.20687158, 0.21241617, 0.91913572],
[ 0.35815412, 0.08503839, 0.51852029],
[ 42. , 42. , 42. ]])
For a 2D numpy array m it’s straightforward to do this by creating a max(m.shape) x max(m.shape) array of ones p and multiplying this by the desired padding value, before setting the slice of p corresponding to m (i.e. p[0:m.shape[0], 0:m.shape[1]]) to be equal to m.
This leads to the following function, where the first line deals with the possibility that the input has only one dimension (i.e. is an array rather than a matrix):
import numpy as np
def pad_to_square(a, pad_value=0):
m = a.reshape((a.shape[0], -1))
padded = pad_value * np.ones(2 * [max(m.shape)], dtype=m.dtype)
padded[0:m.shape[0], 0:m.shape[1]] = m
return padded
So, for example:
>>> r1 = np.random.rand(3, 5)
>>> r1
array([[ 0.85950957, 0.92468279, 0.93643261, 0.82723889, 0.54501699],
[ 0.05921614, 0.94946809, 0.26500925, 0.02287463, 0.04511802],
[ 0.99647148, 0.6926722 , 0.70148198, 0.39861487, 0.86772468]])
>>> pad_to_square(r1, 3)
array([[ 0.85950957, 0.92468279, 0.93643261, 0.82723889, 0.54501699],
[ 0.05921614, 0.94946809, 0.26500925, 0.02287463, 0.04511802],
[ 0.99647148, 0.6926722 , 0.70148198, 0.39861487, 0.86772468],
[ 3. , 3. , 3. , 3. , 3. ],
[ 3. , 3. , 3. , 3. , 3. ]])
or
>>> r2=np.random.rand(4)
>>> r2
array([ 0.10307689, 0.83912888, 0.13105124, 0.09897586])
>>> pad_to_square(r2, 0)
array([[ 0.10307689, 0. , 0. , 0. ],
[ 0.83912888, 0. , 0. , 0. ],
[ 0.13105124, 0. , 0. , 0. ],
[ 0.09897586, 0. , 0. , 0. ]])
etc.

Calculate Matrix Determinants of minors!

i want to caluculate Matrix determinants of minors in Python, maybe using scipy or some other package.
any suggestions?
Numpy/SciPy will do all this.
Form sub-matrices by removing rows and columns.
Calculate determinants with linalg.det().
To create the minor matrix you could use the function
def minor(M, i, j):
M = np.delete(M, i, 0)
M = np.delete(M, j, 1)
return M
With this output
np.linalg.det(M)
To create the principal minor determinants of a matrix and make the calculus for each one determinant, you would want to do this:
import numpy as np
# procedure for creating principal minor determinants
def minor(M, size):
# size can be 2x2, 3x3, 4x4 etc.
theMinor = []
for i in range(size):
clearList = []
for j in range(size):
clearList.append(M[i][j])
theMinor.append(clearList)
return theMinor
# procedure to handle the principal minor
def handleMinorPrincipals(A, n):
# A is a square Matrix
# n is number or rows and cols for A
if n == 0:
return None
if n == 1:
return A[0][0]
# size 1x1 is calculated
# we now look for other minors
for i in range(1, n):
# get the minor determinant
minDet = minor(A, i + 1)
# check if determinant is greater than 0
if np.linalg.det(minDet) > 0:
# do smth
else:
# smth else
return
Example:
[[8. 8. 0. 0. 0.]
[6. 6. 3. 0. 0.]
[0. 4. 4. 4. 0.]
[0. 0. 2. 2. 2.]
[0. 0. 0. 2. 2.]]
size = 1 -> Minor is
[8]
size = 2 -> Minor is
[[8. 8.]
[6. 6.]]
size = 3 -> Minor is
[[8. 8. 0.]
[6. 6. 3.]
[0. 4. 4]]

Categories

Resources