Numpy fill_diagonal return None - python

I want to generate symmetric zero diagonal matrices. My symmetric part work, but when I use fill_diagonal from numpy as the result I got "None". My code is below. Thank you for reading
import numpy as np
matrix_size = int(input("Size of the matrix \n"))
random_matrix = np.random.random_integers(-4,4,size=(matrix_size,matrix_size))
symmetric_matrix = (random_matrix + random_matrix.T)/2
print(symmetric_matrix)
zero_diogonal_matrix = np.fill_diagonal(symmetric_matrix,0)
print(zero_diogonal_matrix)

np.fill_diagonal(), like many other methods across python/numpy, works in-place. For example: Why does “return list.sort()” return None, not the list?. That is that it directly alters the object in memory and does not create a new object. The return value from such functions is None. Therefore, change:
zero_diogonal_matrix = np.fill_diagonal(symmetric_matrix,0)
To just:
np.fill_diagonal(symmetric_matrix,0)
You will then see the change reflected in symmetric_matrix.

It's probably overkill, but in case you want to preserve the tenet of minimising surprise, you could wrap this (and other functions like it) in a function that takes care of preserving the original array:
def fill_diagonal(source_array, diagonal):
copy = source_array.copy()
np.fill_diagonal(copy, diagonal)
return copy
But the question then becomes "who exactly is going to be least surprised by doing it this way?"

Related

Python function that acts on provided array

Some NumPy functions (e.g. argmax or cumsum) can take an array as an optional out parameter and store the result in that array. Please excuse my less than perfect grasp of the terminology here (which is what prevents me from googling for an answer), but it seems that these functions somehow act on variables that are beyond their scope.
How would I transform this simple function so that it can take an out parameter as the functions mentioned?
import numpy as np
def add_two(a):
return a + 2
a = np.arange(5)
a = add_two(a)
From my understanding, a rewritten version of add_two() would allow for the last line above to be replaced with
add_two(a, out=a)
In my opinion, the best and most explicit is to do as you're currently doing. Python passes the values, not the references as parameters in a function, so you can only modify mutable objects.
One way would be to do:
import numpy as np
def add_two(a, out):
out[:] = a+2
a = np.arange(5)
add_two(a, out=a)
a
Output:
array([2, 3, 4, 5, 6])
NB. Unlike your current solution, this requires that the object passed as parameter out exists and is an array
The naive solution would be to fill in the buffer of the output array with the result of your computation:
def add_two(a, out=None):
result = a + 2
if out is None:
out = result
else:
out[:] = result
return out
The problem (if you could call it that), is that you are still generating the intermediate array, and effectively bypassing the benefits of pre-allocating the result in the first place. A more nuanced approach would be to use the out parameters of the functions in your numpy pipeline:
def add_two(a, out=None):
return np.add(a, 2, out=out)
Unfortunately, as with general vectorization, this can only be done on a case-by-case basis depending on what the desired set of operations is.
As an aside, this has nothing to do with scope. Python objects are specifically available to all namespaces (though their names might not be). If a mutable argument is modified in a function, the changes will always be visible outside the function. See for example "Least Astonishment" and the Mutable Default Argument.

Manipulating copied numpy array without changing the original

I am trying to manipulate a numpy array that contains data stored in an other array. So far, when I change a value in my array, both of the arrays get values changed:
import numpy as np
from astropy.io import fits
image = fits.getdata("randomImage.fits")
fft = np.fft.fft2(image)
fftMod = np.copy(fft)
fftMod = fftMod*2
if fftMod.all()== fft.all():
print "shit same same same "
-- > shit same same same
Why is?
You misunderstood the usage of the .all() method.
It yields True if all elements of an array are not 0. This seems to be the case in both your arrays or in neither of them.
Since one is the double of the other, they definetly give the same result to the .all() method (both True or both False)
edit as requested in the comments:
To compare the content of the both arrays use element wise comparison first and check that all elements are True with .all:
(fftMod == fft).all()
Or maybe better for floats including a certain tolerance:
np.allclose(fftMod, fft)

list() function of Python modifies its argument?

(I am quite a newbie in Python, so lots of things puzzle me even after reading the tutorial...)
Initially, I had the code like the following:
strings = ['>abc', 'qwertyu', '>def', 'zxcvbnm']
matrix = zip(*strings)
for member in matrix:
print("".join(member)) # characters are printed as expected
-- which did what I expected. But then for some reason I wanted to determine the number of members in matrix; as len(matrix) gave an error, I decided to copy it with converting to the list: mtxlist = list(matrix). Surprisingly, after this line the content of matrix seems to be changed - or at least I cannot use it the same way as above:
strings = ['>abc', 'qwertyu', '>def', 'zxcvbnm']
matrix = zip(*strings)
mtxlist = list(matrix) # this assignment empties (?) the matrix
for member in matrix:
print("".join(member)) # nothing printed
Can anybody explain what is going on there?
You're using Python 3, correct?
zip returns a generator that can only be iterated once. If you want to use it more than once, then your options are:
Write zip(*strings) each time you need it.
matrix = tuple(zip(*strings))
(iterate matrix as many times as you like. This is the easy option. The downside is that if zip(*strings) is big then it uses a lot of memory that the generator doesn't.)
matrix1, matrix2 = itertools.tee(zip(*strings))
(iterate each of matrix1 and matrix2 once. This is worse than the tuple in your usage, but it's useful if you want to partially consume matrix1, then use some of matrix2, more of matrix1, etc)
def matrix():
return zip(*strings)
# or
matrix = lambda: zip(*strings)
(iterate but using matrix(), not matrix, as many times as you like. Doesn't use extra memory for a copy of the result like the tuple solution, but the syntax for using it is a bit annoying)
class ReusableIterable:
def __init__(self, func):
self.func = func
def __iter__(self):
return iter(self.func())
matrix = ReusableIterable(lambda: zip(*strings))
(iterate using matrix as many times as you like. Deals with the syntax annoyance, although you still have to beware that if you modify strings between iterations over matrix then you'll get different results.)

numpy ravel versus flat in slice assignment

According to the documentation, ndarray.flat is an iterator over the array while ndarray.ravel returns a flattened array (when possible). So my question is, when should we use one or the other?
Which one would be preferred as the rvalue in an assignment like the one in the code below?
import numpy as np
x = np.arange(2).reshape((2,1,1))
y = np.arange(3).reshape((1,3,1))
z = np.arange(5).reshape((1,1,5))
mask = np.random.choice([True, False], size=(2,3,5))
# netCDF4 module wants this kind of boolean indexing:
nc4slice = tuple(mask.any(axis=axis) for axis in ((1,2),(2,0),(0,1)))
indices = np.ix_(*nc4slice)
ncrds = 3
npnts = (np.broadcast(*indices)).size
points = np.empty((npnts, ncrds))
for i,crd in enumerate(np.broadcast_arrays(x,y,z)):
# Should we use ndarray.flat ...
points[:,i] = crd[indices].flat
# ... or ndarray.ravel():
points[:,i] = crd[indices].ravel()
You don't need either. crd[mask] is already 1-d. If you did, numpy always calls np.asarray(rhs) first, so it is the same if no copy is needed for ravel. When the copy is needed, I would guess that ravel may be faster currently (I did not time it).
If you knew that a copy might be needed, and here you know that nothing is needed, reshaping points could actually be the fastest. Since you usually don't need the fastest, I would say it is more a matter of taste, and would personally probably use ravel.

Transform filter function to Python code

I'm trying to understand how to transform a filter, in this case a Notch(stopband) filter, to Python but I don't know how.
x(n)=-2*x(n)/(-0.9*x(n) -0.9*x(n-1))
Can anyone help me please?
Thanks in advance.
If you're using numpy arrays, this should work:
x[1:]=-2*x[1:]/(-0.9*x[1:]-0.9*x[:-1])
this changes your array in place, but you could just as easily assign it to a new array.
y=-2*x[1:]/(-0.9*x[1:]-0.9*x[:-1])
Note that your algorithm isn't really well defined for the 0th element, so my translation leaves x[0] unchanged.
EDIT
To change an iterable to a numpy array:
import numpy as np
x=np.array(iterable) #pretty easy :) although there could be more efficient ways depending on where "iterable" comes from.
result = []
#prime your result, that is, add the initial values to handle indexing
lower_bound = #
upper_bound = #
for n in range(lower_bound,upper_bound):
result.append( 2*result[n]/(-0.9*result[n] -0.9*result[n-1]) )

Categories

Resources