NumPy matrix to SciPy sparse matrix: What is the safest way to add a scalar? - numpy

First off, I'm no mathmatician. I admit that. Yet I still need to understand how ScyPy's sparse matrices work arithmetically in order to switch from a dense NumPy matrix to a SciPy sparse matrix in an application I have to work on. The issue is memory usage. A large dense matrix will consume tons of memory.
The formula portion at issue is where a matrix is added to a scalar.
A = V + x
Where V is a square matrix (its large, say 60,000 x 60,000) and sparsely populated. x is a float.
The operation with NumPy will (if I'm not mistaken) add x to each field in V. Please let me know if I'm completely off base, and x will only be added to non-zero values in V.
With a SciPy, not all sparse matrices support the same features, like scalar addition. dok_matrix (Dictionary of Keys) supports scalar addition, but it looks like (in practice) that it's allocating each matrix entry, effectively rendering my sparse dok_matrix as a dense matrix with more overhead. (not good)
The other matrix types (CSR, CSC, LIL) don't support scalar addition.
I could try constructing a full matrix with the scalar value x, then adding that to V. I would have no problems with matrix types as they all seem to support matrix addition. However I would have to eat up a lot of memory to construct x as a matrix, and the result of the addition could end up being fully populated matrix as well.
There must be an alternative way to do this that doesn't require allocating 100% of a sparse matrix.
I'm will to accept that large amounts of memory are needed, but I thought I would seek some advice first. Thanks.

Admittedly sparse matrices aren't really in my wheelhouse, but ISTM the best way forward depends on the matrix type. If you're DOK:
>>> S = dok_matrix((5,5))
>>> S[2,3] = 10; S[4,1] = 20
>>> S.todense()
matrix([[ 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0.],
[ 0., 0., 0., 10., 0.],
[ 0., 0., 0., 0., 0.],
[ 0., 20., 0., 0., 0.]])
Then you could update:
>>> S.update(zip(S.keys(), np.array(S.values()) + 99))
>>> S
<5x5 sparse matrix of type '<type 'numpy.float64'>'
with 2 stored elements in Dictionary Of Keys format>
>>> S.todense()
matrix([[ 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0.],
[ 0., 0., 0., 109., 0.],
[ 0., 0., 0., 0., 0.],
[ 0., 119., 0., 0., 0.]])
Not particularly performant, but is O(nonzero).
OTOH, if you have something like COO, CSC, or CSR, you can modify the data attribute directly:
>>> C = S.tocoo()
>>> C
<5x5 sparse matrix of type '<type 'numpy.float64'>'
with 2 stored elements in COOrdinate format>
>>> C.data
array([ 119., 109.])
>>> C.data += 1000
>>> C
<5x5 sparse matrix of type '<type 'numpy.float64'>'
with 2 stored elements in COOrdinate format>
>>> C.todense()
matrix([[ 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0.],
[ 0., 0., 0., 1109., 0.],
[ 0., 0., 0., 0., 0.],
[ 0., 1119., 0., 0., 0.]])
Note that you're probably going to want to add an additional
>>> C.eliminate_zeros()
to handle the possibility that you've added a negative number and so there's now a 0 which is actually being recorded. By itself, that should work fine, but the next time you did the C.data += some_number trick, it would add somenumber to that zero you introduced.

Related

How to create Numpy matrix of row index where a certain condition is met?

How do I convert a numpy matrix of values to numpy matrix of row indexes where a certain condition is met?
Let's say
A = array([[ 0., 5., 0.],[ 0., 0., 3.],[ 0., 0., 0.]])
If there is a condition that I want to use here -- if an element is greater than 0 then replace it by row index+1, how would I do it?
So output should be,
B = array([[0., 1., 0.],[0., 0., 2.],[0., 0., 0.]])
Not sure if I am using np.where correctly. Thanks.
Using numpy.where
np.where(A>0, np.arange(1, A.shape[0]+1)[:, None], A)
array([[0., 1., 0.],
[0., 0., 2.],
[0., 0., 0.]])
Or you can use arithmetic (won't work if you have values less than 0):
(A > 0) * np.arange(1, A.shape[0]+1)[:, None]

Multiplying numpy array stack with hermitian transpose of itself without loop

I want to completely get rid of for loops in my code.
I have a complex numpy array stack1 of dimension OxMxN This is a stack of MxN arrays stacked in the 1st dimension. For each MxN array that we call A I want to compute the matrix multiplication:
for k in range(stack1.shape[0]):
A=stack1[k,:,:]
newstack[k,:,:]=A.dot( numpy.conj(numpy.transpose(A)) )
I tried
newstack = stack1 # np.conj(stack1.T)
but I run in an issue because the dimensions won't match
We can use einsum -
np.einsum('ijk,ilk->ijl',stack1,np.conj(stack1))
We can also use np.matmul -
np.matmul(stack1,np.conj(stack1).swapaxes(1,2))
On Python 3.x, simplifies with # operator -
stack1 # np.conj(stack1).swapaxes(1,2)
Just try to correct your for loop
a=[]
for k in range(stack1.shape[0]):
A=stack1[k,:,:]
a.append(A.dot( numpy.conj(numpy.transpose(A)) ))
np.array(a)
Out[399]:
array([[[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.]],
[[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.]]])

How to use CNTK classification_error()?

I am trying to understand the correct usage of cntk.metrics.classification_error() and use it to verify a batch of predictions against their ground truths.
The below toy example (based on the Python API docs):
import numpy as np
from cntk.metrics import classification_error
predictions = np.asarray([[1., 2., 3., 4.],[1., 2., 3., 4.],[1., 2., 3., 4.]], dtype=np.float32)
labels = np.asarray([[0., 0., 0., 1.],[0., 0., 0., 1.],[0., 0., 1., 0.]], dtype=np.float32)
classification_error(predictions, labels).eval()
yields the following result:
array([[ 0., 0., 1.],
[ 0., 0., 1.],
[ 0., 0., 1.]], dtype=float32)
Is there a way I can obtain a vector rather than a square matrix which appears inefficient given I would like to process a large batch?
I've tried using the axis keyword when calling classification_error(), but whether I set axis=0 or axis=1 I get an empty result.
This happens because CNTK is trying to be user-friendly and ends up being confused about the types :-) You can tell because the classification error is not even correct.
If you add a little bit of typing information it gets the semantics right.
p = C.input(4)
y = C.input(4)
classification_error(p, y).eval({p:predictions, y:labels})
array([[ 0.],
[ 0.],
[ 1.]], dtype=float32)
We will work on a fix that will prevent the confusion.

Theano TypeError

I am reading jpg images and then reshaping them into a tensor. I am casting the images as float32:
def load(folder,table):
X=[]
train = pd.read_csv(table)
for i,img_id in enumerate(train['Image']):
img = io.imread(folder+img_id[2:])
X.append(img)
X = np.array(X)/255.
X = X.astype(np.float32)
X = X.reshape(-1, 1, 225, 225)
return X
However, I am getting this error
TypeError: ('Bad input argument to theano function with name "/Users/mas/PycharmProjects/Whale/nolearn_convnet/Zahraa5/lib/python2.7/site-packages/nolearn/lasagne/base.py:435" at index 1(0-based)', 'TensorType(int32, vector) cannot store a value of dtype float32 without risking loss of precision. If you do not mind this loss, you can: 1) explicitly cast your data to int32, or 2) set "allow_input_downcast=True" when calling "function".', 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., 0., 0., ..., 0., 0., 0.],
[ 0., 0., 0., ..., 0., 0., 0.]], dtype=float32))
This is a cross-post to the theano-users mailing list.
Doug provided an answer there:
The theano variable you are using is defined as integer, but you
passed in a float, hence the error 'TensorType(int32, vector) cannot
store a value of dtype float32...'. You can either modify your data
loading code to cast it as int32, or change the symbolic variable to
something that supports float32.
So somewhere you have a line that looks something like:
x = T.ivector()
or
x = T.vector(dtype='int32')
It looks like you need to change this to something like
x = T.tensor4()
where the dtype has been changed to equal theano.config.floatX and the dimensionality as been changed to 4 to match the 4-dimensional nature of X.
If you didn't figure it out, I had a similar error and here's how I fixed it:
Cast your y as int32. The x values can be floatx, but the y MUST be int32 in nolearn for classification.

Filling multiple diagonal elements of a numpy 2D array

What is the best way to fill multiple diagonal elements (but not all) of a 2 dimensional numpy array.
I know numpy.fill_diagonal is the recommended way to fill all the diagonal elements.
Currently I am just using a loop:
for i in a_list_of_indices: a_2d_array[i,i] = num
If the array is large and the number of diagonal elements to be filled is also large, is there a better way than above.
You can use this without looping:
a_2d_array[a_list_of_indices,a_list_of_indices] = num
Example:
a_2d_array = np.zeros((5,5))
a_list_of_indices = [2, 3]
returns:
array([[ 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0.],
[ 0., 0., 1., 0., 0.],
[ 0., 0., 0., 1., 0.],
[ 0., 0., 0., 0., 0.]])