Changing the structure of np.array in Python - python

I have the following array structure.
array([[ 0.3, 0.1, 0. , 1. , 0. , 0. , 2.7],
[ 0.5, 0.5, 0. , 0. , 1. , 0. , 6. ],
[ 0.6, 0.4, -1. , 0. , 0. , 1. , 6. ]])
How can I change to the following structure?
array([[ 0.3, 0.1, 0. , 1. , 2.7],
[ 0.5, 0.5, 0. , 0. , 6. ],
[ 0.6, 0.4, -1. , 0. , 6. ]])

Assuming array is stored in a variable arr use indexing:
arr[:,[0, 1, 2, 3, 6]]

Related

How to add rows to a matrix with pad?

I have a matrix like this:
profile=np.array([[0,0,0.5,0.1],
[0.3,0,0,0],
[0,0,0.1,0.9],
[0,0,0,0.1],
[0,0.5,0,0]])
And I want to add a row before and after filled with zeros. How can I do that?
I thought of using np.pad but not sure how.
Output should be:
np.array([[0,0,0,0],
[0,0,0.5,0.1],
[0.3,0,0,0],
[0,0,0.1,0.9],
[0,0,0,0.1],
[0,0.5,0,0]
[0,0,0,0]])
The np.pad function allows you to specify the axes you want to pad:
In [3]: np.pad(profile, ((1, 1), (0, 0)))
Out[3]:
array([[0. , 0. , 0. , 0. ],
[0. , 0. , 0.5, 0.1],
[0.3, 0. , 0. , 0. ],
[0. , 0. , 0.1, 0.9],
[0. , 0. , 0. , 0.1],
[0. , 0.5, 0. , 0. ],
[0. , 0. , 0. , 0. ]])
The nested tuple can be read as: pad 1 array "above", and 1 array "below" axis 0, and pad 0 arrays "above" and 0 arrays "below" axis 1.
Another example, which pads five columns "after" on axis 1:
In [4]: np.pad(profile, ((0, 0), (0, 5)))
Out[4]:
array([[0. , 0. , 0.5, 0.1, 0. , 0. , 0. , 0. , 0. ],
[0.3, 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. ],
[0. , 0. , 0.1, 0.9, 0. , 0. , 0. , 0. , 0. ],
[0. , 0. , 0. , 0.1, 0. , 0. , 0. , 0. , 0. ],
[0. , 0.5, 0. , 0. , 0. , 0. , 0. , 0. , 0. ]])
You can use np.pad:
out = np.pad(profile, 1)[:, 1:-1]
Output:
>>> out
array([[0. , 0. , 0. , 0. ],
[0. , 0. , 0.5, 0.1],
[0.3, 0. , 0. , 0. ],
[0. , 0. , 0.1, 0.9],
[0. , 0. , 0. , 0.1],
[0. , 0.5, 0. , 0. ],
[0. , 0. , 0. , 0. ]])
Because np.pad pads it on all sides (left and right, in addition to top and bottom), [:, 1:-1] slices off the first and last columns.

Keep First Non-Zero Element, Set All Others to 0

I have a 2-d NumPy array that looks like this:
array([[0. , 0. , 0.2, 0.2],
[0.3, 0. , 0.3, 0. ]])
I'd like to modify it so that each row consists of all 0's, except for the first non-zero entry. If it's all 0s to start with, we don't change anything.
I could do this:
example = np.array([[0,0, 0.2, 0.2], [0.3, 0, 0.3, 0]])
my_copy = np.zeros_like(example)
for i, row in enumerate(example):
for j, elem in enumerate(row):
if elem > 0:
my_copy[i, j] = elem
break
But that's ugly and not vectorized. Any suggestions for how to vectorize this?
Thanks!
Here's a vectorised solution. The trick is to calculate your first non-zero entries via bool conversion and argmax.
import numpy as np
A = np.array([[0. , 0. , 0.2, 0.2],
[0.3, 0. , 0.3, 0. ],
[0. , 0. , 0. , 0. ]])
res = np.zeros(A.shape)
idx = np.arange(res.shape[0])
args = A.astype(bool).argmax(1)
res[idx, args] = A[idx, args]
print(res)
array([[ 0. , 0. , 0.2, 0. ],
[ 0.3, 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. ]])
Simply
e =np.zeros(example.shape)
rows = np.arange(example.shape[0])
cols = np.argmax(example != 0, 1)
e[rows, cols] = example[rows, cols]
Setup
x = np.array([[0. , 0. , 0.2, 0.2],
[0.3, 0. , 0.3, 0. ],
[0. , 0. , 0. , 0. ]])
Using logical_and with np.eye:
m = (x!=0).argmax(1)
x[~np.logical_and(x, np.eye(x.shape[1])[m])] = 0
Output:
array([[0. , 0. , 0.2, 0. ],
[0.3, 0. , 0. , 0. ],
[0. , 0. , 0. , 0. ]])
Using this method will be slightly slower than the other two suggested.

efficiently generate "shifted" gaussian kernel in python

I have a (very large) number of data points, each consisting of an x and y coordinate and a sigma-uncertainty (sigma is the same in both x and y directions; all three variables are floats). For each data-point I want to generate a 2d array on a standard grid, with probabilities that the the actual value is in that location.
For instance if x=5.0, y=5.0, sigma=1.0, on a (0,0)->(9,9) grid, I expect to generate:
[ 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. , 0.01, 0.02, 0.01, 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0.01, 0.06, 0.1 , 0.06, 0.01, 0. , 0. ],
[ 0. , 0. , 0. , 0.02, 0.1 , 0.16, 0.1 , 0.02, 0. , 0. ],
[ 0. , 0. , 0. , 0.01, 0.06, 0.1 , 0.06, 0.01, 0. , 0. ],
[ 0. , 0. , 0. , 0. , 0.01, 0.02, 0.01, 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. ]]
Above was generated by creating a numpy array with zeroes, and [5,5] = 1, and then applying ndimage.filters.gaussian_filter with a sigma of 1. I feel that I can deal with non-integer x and y by distributing over nearby integer values and get a good approximation.
It feels however to be extreme overkill to get my resulting array this way, since scipy will have to take all values into account, not just the 1 in location [5, 5], even though they are all 0. It only takes 300us for a 64x64 grid, but still, I would likt to know if there is no more efficient way to get a X*Y numpy array with a gaussian kernel with arbitrary x, y and sigma.
A reasonably fast approach is to note that the Gaussian is separable, so you can calculate the 1D gaussian for x and y and then take the outer product:
import numpy as np
import matplotlib.pyplot as plt
x0, y0, sigma = 5.5, 4.2, 1.4
x, y = np.arange(9), np.arange(9)
gx = np.exp(-(x-x0)**2/(2*sigma**2))
gy = np.exp(-(y-y0)**2/(2*sigma**2))
g = np.outer(gx, gy)
g /= np.sum(g) # normalize, if you want that
plt.imshow(g, interpolation="nearest", origin="lower")
plt.show()
#tom10's outer product answer is probably the best for this particular case. If you want to make a kernal out of an arbitrary function in two (or more) dimensions, you may want to look at np.indices or np.meshgrid.
For example:
def gaussian(x, mu=0, sigma=1):
n = np.prod(sigma)*np.sqrt(2*np.pi)**len(x)
return np.exp(-0.5*(((x-mu)/sigma)**2).sum(0))/n
gaussian(np.indices((10,10)), mu=5, sigma=1)
Which yields:
array([[ 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. , 0.001, 0.002, 0.001, 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0.003, 0.013, 0.022, 0.013, 0.003, 0. , 0. ],
[ 0. , 0. , 0.001, 0.013, 0.059, 0.097, 0.059, 0.013, 0.001, 0. ],
[ 0. , 0. , 0.002, 0.022, 0.097, 0.159, 0.097, 0.022, 0.002, 0. ],
[ 0. , 0. , 0.001, 0.013, 0.059, 0.097, 0.059, 0.013, 0.001, 0. ],
[ 0. , 0. , 0. , 0.003, 0.013, 0.022, 0.013, 0.003, 0. , 0. ],
[ 0. , 0. , 0. , 0. , 0.001, 0.002, 0.001, 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. ]])
For more flexibility, you can use np.meshgrid to control what the scale and scope of your domain is:
kern = gaussian(np.meshgrid(np.linspace(-10, 5), np.linspace(-2, 2)))
For this, kern.shape will be (50, 50) because 50 is the default length of np.linspace, and meshgrid is defining the x and y axes by the arrays passed to it. An equivalent way of doing this is np.mgrid[-10:5:50j, -2:2:50j]

numpy merge upper and lower triangular

I essentially would like to do the opposite of this question. I have two matrixes that have been split with np.tril or np.triu and I want to recombine them into a single matrix.
A = array([[ 0. , 0. , 0. ],
[ 0.1, 0. , 0. ],
[ 0.6, 0.5, 0. ]])
B = array([[ 0. , 0.4, 0.8],
[ 0. , 0. , 0.3],
[ 0. , 0. , 0. ]])
And what I want it to look like is
array([[ 0. , 0.4, 0.8],
[ 0.1, 0. , 0.3],
[ 0.6, 0.5, 0. ]])
Is there an inbuilt numpy function to do this?
You mean A+B ?
import numpy
A = numpy.array([[ 0. , 0. , 0. ],
[ 0.1, 0. , 0. ],
[ 0.6, 0.5, 0. ]])
B = numpy.array([[ 0. , 0.4, 0.8],
[ 0. , 0. , 0.3],
[ 0. , 0. , 0. ]])
print A+B
returns
array([[ 0. , 0.4, 0.8],
[ 0.1, 0. , 0.3],
[ 0.6, 0.5, 0. ]])
If the values are strings, then this works as long as B is the upper triangle.
A = np.array([[ 0. , 0. , 0. ],
[ '0.1**', 0. , 0. ],
[ 0.6, '0.5**', 0. ]])
B = np.array([[ 0. , 0.4, '0.8***'],
[ 0. , 0. , 0.3],
[ 0. , 0. , 0. ]])
for i in range(0,len(A)):
for j in range(0,i):
B[i,j]=A[i,j]
B
Returns
array([['0.0', '0.4', '0.8***'],
['0.1**', '0.0', '0.3'],
['0.6', '0.5**', '0.0']], dtype='<U32')

numpy only perform function on nonzero parts while preserving structure of array

In numpy:
Foo =
array([[ 3.5, 0. , 2.5, 2. , 0. , 1. , 0. ],
[ 0. , 3. , 2.5, 2. , 0. , 0. , 0.5],
[ 3.5, 0. , 0. , 0. , 1.5, 0. , 0.5]])
I want to perform a function on Foo such that only the nonzero elements are changed, i.e. for f(x) = x(nonzero)+5:
array([[ 8.5, 0. , 7.5, 7. , 0. , 6. , 0. ],
[ 0. , 8. , 8.5, 7. , 0. , 0. , 5.5],
[ 8.5, 0. , 0. , 0. , 6.5, 0. , 5.5]])
Also I want the shape/structure of the array to stay the same, so I don't think Foo[np.nonzero(Foo)] is going to work...
How do I do this in numpy?
thanks!
In [138]: foo = np.array([[ 3.5, 0. , 2.5, 2. , 0. , 1. , 0. ],
[ 0. , 3. , 2.5, 2. , 0. , 0. , 0.5],
[ 3.5, 0. , 0. , 0. , 1.5, 0. , 0.5]])
In [141]: mask = foo != 0
In [142]: foo[mask] = foo[mask]+5
In [143]: foo
Out[143]:
array([[ 8.5, 0. , 7.5, 7. , 0. , 6. , 0. ],
[ 0. , 8. , 7.5, 7. , 0. , 0. , 5.5],
[ 8.5, 0. , 0. , 0. , 6.5, 0. , 5.5]])
you can also do it in place as follows
>>> import numpy as np
>>> foo = np.array([[ 3.5, 0. , 2.5, 2. , 0. , 1. , 0. ],
... [ 0. , 3. , 2.5, 2. , 0. , 0. , 0.5],
... [ 3.5, 0. , 0. , 0. , 1.5, 0. , 0.5]])
>>> foo[foo!=0] += 5
>>> foo
array([[ 8.5, 0. , 7.5, 7. , 0. , 6. , 0. ],
[ 0. , 8. , 7.5, 7. , 0. , 0. , 5.5],
[ 8.5, 0. , 0. , 0. , 6.5, 0. , 5.5]])
>>>

Categories