Sanity Checking Output of Python numpy eig() function - numpy

I have a question on numpy.linalg.eig().
Here's my covariance matrix after normalizing /standardizing the data.
lr_cov = np.cov(lr_norm, rowvar = False, ddof = 0)
lr_cov
array([[ 0.95454545, 0.88156287, 0.8601369 ],
[ 0.88156287, 0.95454545, 0.87367031],
[ 0.8601369 , 0.87367031, 0.95454545]])
I use the eig() function as below -- no problems here.
eig_val, eig_vec = np.linalg.eig(lr_cov)
eig_vec
array([[-0.57694452, -0.6184592 , 0.53351967],
[-0.57990975, -0.14982268, -0.80078577],
[-0.57518668, 0.77140222, 0.27221115]])
eig_val
array([ 2.69815538, 0.09525935, 0.07022164])
But when I proceed to sanity check that (Covariance Matrix)*(Eigen vector) = (Eigen Value)*(Eigen Vector), the LHS and RHS in this case don't match up.
lr_cov*eig_vec
array([[-0.55071977, -0.54521067, 0.45889996],
[-0.5112269 , -0.14301256, -0.69962276],
[-0.49473928, 0.67395122, 0.25983791]])
eig_val*eig_vec
array([[-1.55668595, -0.05891402, 0.03746463],
[-1.5646866 , -0.01427201, -0.05623249],
[-1.55194302, 0.07348327, 0.01911511]])
What I am doing incorrectly?

Two points:
* is element-wise multipication. Use the dot() method for matrix multiplication.
eig_val is a 1d array. Convert it to a 2d square diagonal array with np.diag(eig_val).
Example:
In [70]: cov
Out[70]:
array([[ 0.95454545, 0.88156287, 0.8601369 ],
[ 0.88156287, 0.95454545, 0.87367031],
[ 0.8601369 , 0.87367031, 0.95454545]])
In [71]: eig_val, eig_vec = np.linalg.eig(cov)
In [72]: cov.dot(eig_vec)
Out[72]:
array([[-1.55668595, -0.05891401, 0.03746463],
[-1.56468659, -0.01427202, -0.05623249],
[-1.55194302, 0.07348327, 0.01911511]])
In [73]: eig_vec.dot(np.diag(eig_val))
Out[73]:
array([[-1.55668595, -0.05891401, 0.03746463],
[-1.56468659, -0.01427202, -0.05623249],
[-1.55194302, 0.07348327, 0.01911511]])
In the last line, np.diag(eig_val) is on the right in order to multiply each column of eig_vec by the corresponding eigenvalue.
If you take advantage of numpy's broadcasting, you don't have to use np.diag(eig_val), and you can use element-wise multiplication (in either order, since element-wise multiplication is commutative):
In [75]: eig_vec * eig_val # element-wise multiplication with broadcasting
Out[75]:
array([[-1.55668595, -0.05891401, 0.03746463],
[-1.56468659, -0.01427202, -0.05623249],
[-1.55194302, 0.07348327, 0.01911511]])
In [76]: eig_val * eig_vec
Out[76]:
array([[-1.55668595, -0.05891401, 0.03746463],
[-1.56468659, -0.01427202, -0.05623249],
[-1.55194302, 0.07348327, 0.01911511]])

Related

Addressing polynomial multiplication and division "overflow" issue

I have a list of the coefficient to degree 1 polynomials, with a[i][0]*x^1 + a[i][1]
a = np.array([[ 1. , 77.48514702],
[ 1. , 0. ],
[ 1. , 2.4239275 ],
[ 1. , 1.21848739],
[ 1. , 0. ],
[ 1. , 1.18181818],
[ 1. , 1.375 ],
[ 1. , 2. ],
[ 1. , 2. ],
[ 1. , 2. ]])
And running into issues with the following operation,
np.polydiv(reduce(np.polymul, a), a[0])[0] != reduce(np.polymul, a[1:])
where
In [185]: reduce(np.polymul, a[1:])
Out[185]:
array([ 1. , 12.19923307, 63.08691612, 179.21045388,
301.91486027, 301.5756213 , 165.35814595, 38.39582615,
0. , 0. ])
and
In [186]: np.polydiv(reduce(np.polymul, a), a[0])[0]
Out[186]:
array([ 1.00000000e+00, 1.21992331e+01, 6.30869161e+01, 1.79210454e+02,
3.01914860e+02, 3.01575621e+02, 1.65358169e+02, 3.83940472e+01,
1.37845155e-01, -1.06809521e+01])
First of all the remainder of np.polydiv(reduce(np.polymul, a), a[0]) is way bigger than 0, 827.61514239 to be exact, and secondly, the last two terms to quotient should be 0, but way larger from 0. 1.37845155e-01, -1.06809521e+01.
I'm wondering what are my options to improve the accuracy?
There is a slightly complicated way to keep the product first and then divide structure.
By first employ n points and evaluate on a.
xs = np.linspace(0, 1., 10)
ys = np.array([np.prod(list(map(lambda r: np.polyval(r, x), a))) for x in xs])
then do the division on ys instead of coefficients.
ys = ys/np.array([np.polyval(a[0], x) for x in xs])
finally recover the coefficient using polynomial interpolation with xs and ys
from scipy.interpolate import lagrange
lagrange(xs, ys)

How to use tf.cond for batch processing

I want to use tf.cond(pred, fn1, fn2, name=None) for conditional branching. Let say I have two tensors: x, y. Each tensor is a batch of 0/1 and I want to use this tensors compression x < y as the source for
tf.cond pred argument:
pred: A scalar determining whether to return the result of fn1 or fn2.
But if I am working with batches then it looks like I need to iterate over the source tensor inside the graph and make slices for every item in batch and apply tf.cond for every item. Looks suspiciously as for me. Why tf.cond not accept batch and only scalar? Can you advise what is the right way to use it with batch?
tf.where sounds like what you want: a vectorized selection between Tensors.
tf.cond is a control flow modifier: it determines which ops are executed, and so it's difficult to think of useful batch semantics.
We can also put together a mixture of these operations: an operation which slices based on a condition and passes those slices to two branches.
import tensorflow as tf
from tensorflow.python.util import nest
def slicing_where(condition, full_input, true_branch, false_branch):
"""Split `full_input` between `true_branch` and `false_branch` on `condition`.
Args:
condition: A boolean Tensor with shape [B_1, ..., B_N].
full_input: A Tensor or nested tuple of Tensors of any dtype, each with
shape [B_1, ..., B_N, ...], to be split between `true_branch` and
`false_branch` based on `condition`.
true_branch: A function taking a single argument, that argument having the
same structure and number of batch dimensions as `full_input`. Receives
slices of `full_input` corresponding to the True entries of
`condition`. Returns a Tensor or nested tuple of Tensors, each with batch
dimensions matching its inputs.
false_branch: Like `true_branch`, but receives inputs corresponding to the
false elements of `condition`. Returns a Tensor or nested tuple of Tensors
(with the same structure as the return value of `true_branch`), but with
batch dimensions matching its inputs.
Returns:
Interleaved outputs from `true_branch` and `false_branch`, each Tensor
having shape [B_1, ..., B_N, ...].
"""
full_input_flat = nest.flatten(full_input)
true_indices = tf.where(condition)
false_indices = tf.where(tf.logical_not(condition))
true_branch_inputs = nest.pack_sequence_as(
structure=full_input,
flat_sequence=[tf.gather_nd(params=input_tensor, indices=true_indices)
for input_tensor in full_input_flat])
false_branch_inputs = nest.pack_sequence_as(
structure=full_input,
flat_sequence=[tf.gather_nd(params=input_tensor, indices=false_indices)
for input_tensor in full_input_flat])
true_outputs = true_branch(true_branch_inputs)
false_outputs = false_branch(false_branch_inputs)
nest.assert_same_structure(true_outputs, false_outputs)
def scatter_outputs(true_output, false_output):
batch_shape = tf.shape(condition)
scattered_shape = tf.concat(
[batch_shape, tf.shape(true_output)[tf.rank(batch_shape):]],
0)
true_scatter = tf.scatter_nd(
indices=tf.cast(true_indices, tf.int32),
updates=true_output,
shape=scattered_shape)
false_scatter = tf.scatter_nd(
indices=tf.cast(false_indices, tf.int32),
updates=false_output,
shape=scattered_shape)
return true_scatter + false_scatter
result = nest.pack_sequence_as(
structure=true_outputs,
flat_sequence=[
scatter_outputs(true_single_output, false_single_output)
for true_single_output, false_single_output
in zip(nest.flatten(true_outputs), nest.flatten(false_outputs))])
return result
Some examples:
vector_test = slicing_where(
condition=tf.equal(tf.range(10) % 2, 0),
full_input=tf.range(10, dtype=tf.float32),
true_branch=lambda x: 0.2 + x,
false_branch=lambda x: 0.1 + x)
cross_range = (tf.range(10, dtype=tf.float32)[:, None]
* tf.range(10, dtype=tf.float32)[None, :])
matrix_test = slicing_where(
condition=tf.equal(tf.range(10) % 3, 0),
full_input=cross_range,
true_branch=lambda x: -x,
false_branch=lambda x: x + 0.1)
with tf.Session():
print(vector_test.eval())
print(matrix_test.eval())
Prints:
[ 0.2 1.10000002 2.20000005 3.0999999 4.19999981 5.0999999
6.19999981 7.0999999 8.19999981 9.10000038]
[[ 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. ]
[ 0.1 1.10000002 2.0999999 3.0999999 4.0999999
5.0999999 6.0999999 7.0999999 8.10000038 9.10000038]
[ 0.1 2.0999999 4.0999999 6.0999999 8.10000038
10.10000038 12.10000038 14.10000038 16.10000038 18.10000038]
[ 0. -3. -6. -9. -12. -15.
-18. -21. -24. -27. ]
[ 0.1 4.0999999 8.10000038 12.10000038 16.10000038
20.10000038 24.10000038 28.10000038 32.09999847 36.09999847]
[ 0.1 5.0999999 10.10000038 15.10000038 20.10000038
25.10000038 30.10000038 35.09999847 40.09999847 45.09999847]
[ 0. -6. -12. -18. -24. -30.
-36. -42. -48. -54. ]
[ 0.1 7.0999999 14.10000038 21.10000038 28.10000038
35.09999847 42.09999847 49.09999847 56.09999847 63.09999847]
[ 0.1 8.10000038 16.10000038 24.10000038 32.09999847
40.09999847 48.09999847 56.09999847 64.09999847 72.09999847]
[ 0. -9. -18. -27. -36. -45.
-54. -63. -72. -81. ]]

bad result from numpy corrcoef and minimum spanning tree

I have this code:
mm = np.array([[1, 4, 7, 8], [2, 2, 8, 4], [1, 13, 1, 5]])
mm = np.column_stack(mm)
mmCov = np.cov(mm, rowvar=0)
print("covariance\n", mmCov)
# my code to get correlations
mmResCor = np.zeros(shape=(3, 3))
for i in range(len(mmCov)):
for j in range(len(mmCov[i])):
mmResCor[i][j] = mmCov[i][j] / (math.sqrt(mmCov[i][i] * mmCov[j] [j]))
print("correlaciones a mano\n", mmResCor)
mmCor = np.corrcoef(mmCov, rowvar=0)
print("correlations\n", mmCor)
X = csr_matrix(mmCor)
XX = minimum_spanning_tree(X)
print("minimun spanning tree\n", XX)
first: each column represents a variable, with observations in the rows
numpy corrcoef use this relation with covariance matrix:
R_{ij} = \frac{ C_{ij} } { \sqrt{ C_{ii} * C_{jj} } }
when I use numpy corrcoef I get this matrix
correlations
[[ 1. 0.8660254 -0.82603319]
[ 0.8660254 1. -0.99717646]
[-0.82603319 -0.99717646 1. ]]
but when I apply "my code" to get the same result...
mmResCor = np.zeros(shape=(3, 3))
for i in range(len(mmCov)):
for j in range(len(mmCov[i])):
mmResCor[i][j] = mmCov[i][j] / (math.sqrt(mmCov[i][i] * mmCov[j][j]))
I get this matrix
correlaciones a mano
[[ 1. 0.67082039 0. ]
[ 0.67082039 1. -0.5 ]
[ 0. -0.5 1. ]]
why do I get differents results if its suppose I am doing the same?
One more question:
When I apply minimun_spanning_tree I get this:
minimun spanning tree
(0, 2) -0.826033187631
(1, 2) -0.997176464953
Is there any way to represent these or can I save this result in some variables?
The np.corrcoef should take the data as the input. You're passing the covariance matrix as input. If you pass the data, you get the same result as your manual computation:
>>> np.corrcoef(mm, rowvar=0)
array([[ 1. , 0.67082039, 0. ],
[ 0.67082039, 1. , -0.5 ],
[ 0. , -0.5 , 1. ]])
Regarding the minimum spanning tree, I'm not sure what your question is, but the output XX is a sparse matrix which stores a matrix representation of the tree.

How to efficiently prepare matrices (2-d array) for multiple arguments?

If you want to evaluate a 1-d array for multiple arguments efficiently i.e. without for-loop, you can do this:
x = array([1, 2, 3])
def gen_1d_arr(x):
arr = array([2 + x, 2 - x,])
return arr
gen_1d_arr(x).T
and you get:
array([[ 3, 1],
[ 4, 0],
[ 5, -1]])
Okay, but how do you do this for 2-d array like below:
def gen_2d_arr(x):
arr = array([[2 + x, 2 - x,],
[2 * x, 2 / x]])
return arr
and obtain this?:
array([[[ 3. , 1. ],
[ 2. , 2. ]],
[[ 4. , 0. ],
[ 4. , 1. ]],
[[ 5. , -1. ],
[ 6. , 0.66666667]]])
Also, is this generally possible for n-d arrays?
Look at what you get with your function
In [274]: arr = np.array([[2 + x, 2 - x,],
[2 * x, 2 / x]])
In [275]: arr
Out[275]:
array([[[ 3. , 4. , 5. ],
[ 1. , 0. , -1. ]],
[[ 2. , 4. , 6. ],
[ 2. , 1. , 0.66666667]]])
In [276]: arr.shape
Out[276]: (2, 2, 3)
The 3 comes from x. The middle 2 comes from [2+x, 2-x] pairs, and the 1st 2 from the outer list.
Looks like what you want is a (3,2,2) array. One option is to apply a transpose or axis swap to arr.
arr.transpose([2,0,1])
The basic operation of np.array([arr1,arr2]) is to construct a new array with a new dimension in front, i.e. with shape (2, *arr1(shape)).
There are other operations that combine arrays. np.concatenate and its variants hstack, vstack, dstack, column_stack, join arrays. .reshape() and [None,...], atleast_nd etc add dimensions. Look at the code of the stack functions to get some ideas on how to combine arrays using these tools.
On the question of efficiency, my time tests show that concatenate operations are generally faster than np.array. Often np.array converts its inputs to lists, and reparses the values. This gives it more power in cooercing arrays to specific dtypes, but at the expense of time. But I'd only worry about this with large arrays where construction time is significant.

fft of numpy and octave different on transpose

First of i know there is an identical question with answer in SO here: FFT in Matlab and numpy / scipy give different results
but the answer given there does not work on the test i did:
when i do an fft from numpy.fft i get following result:
In [30]: numpy.fft.fft(numpy.array([1+0.5j, 3+0j, 2+0j, 8+3j]))
Out[30]: array([ 14.+3.5j, -4.+5.5j, -8.-2.5j, 2.-4.5j])
which is identical to the output of in my case octave)
octave:39> fft([1+0.5j,3+0j,2+0j,8+3j])
ans =
Columns 1 through 3:
14.0000 + 3.5000i -4.0000 + 5.5000i -8.0000 - 2.5000i
Column 4:
2.0000 - 4.5000i
but if i transpose the list in octave and python i get:
In [9]: numpy.fft.fft(numpy.array([1+0.5j, 3+0j, 2+0j, 8+3j]).transpose())
Out[9]: array([ 14.+3.5j, -4.+5.5j, -8.-2.5j, 2.-4.5j])
and for octave:
octave:40> fft([1+0.5j,3+0j,2+0j,8+3j]')
ans =
14.0000 - 3.5000i
2.0000 + 4.5000i
-8.0000 + 2.5000i
-4.0000 - 5.5000i
I also tried to reshape in python but this results in:
In [33]: numpy.fft.fft(numpy.reshape(numpy.array([1+0.5j,3+0j,2+0j,8+3j]), (4,1)))
Out[33]:
array([[ 1.+0.5j],
[ 3.+0.j ],
[ 2.+0.j ],
[ 8.+3.j ]])
how do i get the same result in python as in octave?
+ i don't have matlab to test, otherwise i would check if it returns the same as octave just to be sure.
Why NumPy and octave gave different results:
The inputs were different. The ' in octave is returning the complex conjugate transpose, not the transpose, .':
octave:6> [1+0.5j,3+0j,2+0j,8+3j]'
ans =
1.0000 - 0.5000i
3.0000 - 0.0000i
2.0000 - 0.0000i
8.0000 - 3.0000i
So to make NumPy's result match octave's:
In [115]: np.fft.fft(np.array([1+0.5j, 3+0j, 2+0j, 8+3j]).conj()).reshape(-1, 1)
Out[115]:
array([[ 14.-3.5j],
[ 2.+4.5j],
[ -8.+2.5j],
[ -4.-5.5j]])
octave:7> fft([1+0.5j,3+0j,2+0j,8+3j]')
ans =
14.0000 - 3.5000i
2.0000 + 4.5000i
-8.0000 + 2.5000i
-4.0000 - 5.5000i
In NumPy, the transpose of a 1D array is the same 1D array.
That's why fft(np.array([1+0.5j, 3+0j, 2+0j, 8+3j]).transpose()) returns a 1D array.
Reshaping after taking the FFT of a 1D array:
You could take the FFT first, and then reshape. To make a 1D array 2-dimensional you could use reshape to obtain a column-like array of shape (4,1), or use np.atleast_2d followed by transpose:
In [115]: np.fft.fft(np.array([1+0.5j, 3+0j, 2+0j, 8+3j]).conj()).reshape(-1, 1)
Out[115]:
array([[ 14.-3.5j],
[ 2.+4.5j],
[ -8.+2.5j],
[ -4.-5.5j]])
or
In [116]: np.atleast_2d(np.fft.fft(np.array([1+0.5j, 3+0j, 2+0j, 8+3j]).conj())).T
Out[116]:
array([[ 14.-3.5j],
[ 2.+4.5j],
[ -8.+2.5j],
[ -4.-5.5j]])
Taking the FFT of a 2D array:
np.fft.fft takes the FFT over the last axis by default.
This is why reshaping to shape (4, 1) did not work. Instead, reshape the array to (1, 4):
In [117]: np.fft.fft(np.reshape(np.array([1+0.5j,3+0j,2+0j,8+3j]), (1,4)).conj()).T
Out[117]:
array([[ 14.-3.5j],
[ 2.+4.5j],
[ -8.+2.5j],
[ -4.-5.5j]])
Or you could use np.matrix to
make a 2D matrix of shape (1, 4).
Again the FFT is taken over the last axis, returns an array of shape (1, 4), which you can then transpose to get the desired result:
In [121]: np.fft.fft(np.matrix([1+0.5j, 3+0j, 2+0j, 8+3j]).conj()).T
Out[121]:
array([[ 14.-3.5j],
[ 2.+4.5j],
[ -8.+2.5j],
[ -4.-5.5j]])
This, perhaps, gives you the neatest syntax. But be aware that this passes a np.matrix as input but returns a np.ndarray as output.
As Warren Weckesser pointed out, if you already have a 2D NumPy array, and wish to take the FFT of its columns, then you could pass axis=0 to the call to np.fft.fft.
Also, The matrix class (unlike the ndarray class) has a H property which returns the complex conjugate transpose. Thus
In [114]: np.fft.fft(np.matrix([1+0.5j, 3+0j, 2+0j, 8+3j]).H, axis=0)
Out[114]:
array([[ 14.-3.5j],
[ 2.+4.5j],
[ -8.+2.5j],
[ -4.-5.5j]])