Use of None in Array indexing in Python - python

I am using the LSTM tutorial for Theano (http://deeplearning.net/tutorial/lstm.html). In the lstm.py (http://deeplearning.net/tutorial/code/lstm.py) file, I don't understand the following line:
c = m_[:, None] * c + (1. - m_)[:, None] * c_
What does m_[:, None] mean? In this case m_ is the theano vector while c is a matrix.

This question has been asked and answered on the Theano mailing list, but is actually about the basics of numpy indexing.
Here are the question and answer
https://groups.google.com/forum/#!topic/theano-users/jq92vNtkYUI
For completeness, here is another explanation: slicing with None adds an axis to your array, see the relevant numpy documentation, because it behaves the same in both numpy and Theano:
http://docs.scipy.org/doc/numpy/reference/arrays.indexing.html#numpy.newaxis
Note that np.newaxis is None:
import numpy as np
a = np.arange(30).reshape(5, 6)
print a.shape # yields (5, 6)
print a[np.newaxis, :, :].shape # yields (1, 5, 6)
print a[:, np.newaxis, :].shape # yields (5, 1, 6)
print a[:, :, np.newaxis].shape # yields (5, 6, 1)
Typically this is used to adjust shapes to be able to broadcast to higher dimensions. E.g. tiling 7 times in the middle axis can be achieved as
b = a[:, np.newaxis] * np.ones((1, 7, 1))
print b.shape # yields (5, 7, 6), 7 copies of a along the second axis

I think the Theano vector's __getitem__ method expects a tuple as an argument! like this:
class Vect (object):
def __init__(self,data):
self.data=list(data)
def __getitem__(self,key):
return self.data[key[0]:key[1]+1]
a=Vect('hello')
print a[0,2]
Here print a[0,2] when a is an ordinary list will raise an exception:
>>> a=list('hello')
>>> a[0,2]
Traceback (most recent call last):
File "<string>", line 1, in <module>
TypeError: list indices must be integers, not tuple
But here the __getitem__ method is different and it accepts a tuple as an argument.
You can pass the : sign to __getitem__ like this as : means slice:
class Vect (object):
def __init__(self,data):
self.data=list(data)
def __getitem__(self,key):
return self.data[0:key[1]+1]+list(key[0].indices(key[1]))
a=Vect('hello')
print a[:,2]
Speaking about None, it can be used when indexing in plain Python as well:
>>> 'hello'[None:None]
'hello'

Related

How to input a 1-D array of dimensions into numpy.random.randn?

Say I have a 1-D array dims:
dims = np.array((1,2,3,4))
I want to create a n-th order normally distributed tensor where n is the size of the dims and dims[i] is the size of the i-th dimension.
I tried to do
A = np.random.randn(dims)
But this doesn't work. I could do
A = np.random.randn(1,2,3,4)
which would work but n can be large and n can be random in itself. How can I read in a array of the size of the dimensions in this case?
Use unpacking with an asterisk:
np.random.randn(*dims)
Unpacking is standard Python when the signature is randn(d0, d1, ..., dn)
In [174]: A = np.random.randn(*dims)
In [175]: A.shape
Out[175]: (1, 2, 3, 4)
randn docs suggests standard_normal which takes a tuple (or array which can be treated as a tuple):
In [176]: B = np.random.standard_normal(dims)
In [177]: B.shape
Out[177]: (1, 2, 3, 4)
In fact the docs, say new code should use this:
In [180]: rgn = np.random.default_rng()
In [181]: rgn.randn
Traceback (most recent call last):
File "<ipython-input-181-b8e8c46209d0>", line 1, in <module>
rgn.randn
AttributeError: 'numpy.random._generator.Generator' object has no attribute 'randn'
In [182]: rgn.standard_normal(dims).shape
Out[182]: (1, 2, 3, 4)

How to create an empty array and append it?

I am new to programming.
I am trying to run this code
from numpy import *
x = empty((2, 2), int)
x = append(x, array([1, 2]), axis=0)
x = append(x, array([3, 5]), axis=0)
print(x)
But i get this error
Traceback (most recent call last):
File "/home/samip/PycharmProjects/MyCode/test.py", line 3, in <module>
x = append(x, array([1, 2]), axis=0)
File "<__array_function__ internals>", line 5, in append
File "/usr/lib/python3/dist-packages/numpy/lib/function_base.py", line 4700, in append
return concatenate((arr, values), axis=axis)
File "<__array_function__ internals>", line 5, in concatenate
ValueError: all the input arrays must have same number of dimensions, but the array at index 0 has 2 dimension(s) and the array at index 1 has 1 dimension(s)
I suspect you are trying to replicate this working list code:
In [56]: x = []
In [57]: x.append([1,2])
In [58]: x
Out[58]: [[1, 2]]
In [59]: np.array(x)
Out[59]: array([[1, 2]])
But with arrays:
In [53]: x = np.empty((2,2),int)
In [54]: x
Out[54]:
array([[73096208, 10273248],
[ 2, -1]])
Despite the name, the np.empty array is NOT a close of the empty list. It has 4 elements, the shape that you specified.
In [55]: np.append(x, np.array([1,2]), axis=0)
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-55-64dd8e7900e3> in <module>
----> 1 np.append(x, np.array([1,2]), axis=0)
<__array_function__ internals> in append(*args, **kwargs)
/usr/local/lib/python3.6/dist-packages/numpy/lib/function_base.py in append(arr, values, axis)
4691 values = ravel(values)
4692 axis = arr.ndim-1
-> 4693 return concatenate((arr, values), axis=axis)
4694
4695
<__array_function__ internals> in concatenate(*args, **kwargs)
ValueError: all the input arrays must have same number of dimensions, but the array at index 0 has 2 dimension(s) and the array at index 1 has 1 dimension(s)
Note that np.append has passed the task on to np.concatenate. With the axis parameter, that's all this append does. It is NOT a list append clone.
np.concatenate demands consistency in the dimensions of its inputs. One is (2,2), the other (2,). Mismatched dimensions.
np.append is a dangerous function, and not that useful even when used correctly. np.concatenate (and the various stack) functions are useful. But you need to pay attention to shapes. And don't use them iteratively. List append is more efficient for that.
When you got this error, did you look up the np.append, np.empty (and np.concatenate) functions? Read and understand the docs? In the long run SO questions aren't a substitute for reading the documentation.
You can create empty list by []. In order to add new item use append. For add other list use extend.
x = [1, 2, 3]
x.append(4)
x.extend([5, 6])
print(x)
# [1, 2, 3, 4, 5, 6]
The issue is that the line x = empty((2, 2), int) is creating a 2D array.
Later when you try to append array([1, 2]) you get an error because it is a 1D array.
You can try the code below.
from numpy import *
x = empty((2, 2), int)
x = append(x,[1,2])
print(x)
as you can see in the error your two arrays must match the same shape, x.shape returns (2,2), and array([1,2]).shape returns (2,) so what you have to do is
x = np.append(x, np.array([1,2]).reshape((1,2)), axis=0)
Printing x returns :
array([[1.966937e-316, 4.031792e-313],
[0.000000e+000, 4.940656e-324],
[1.000000e+000, 2.000000e+000]])

Numpy: multiply 3D array with 2D array [duplicate]

This question already has an answer here:
Multiple matrix multiplication
(1 answer)
Closed 3 years ago.
I have 2 arrays, one of shape (4, 2, 2), another of shape (4, 2).
A = np.random.rand(4, 2, 2)
B = np.random.rand(4, 2)
So, for every 0<= i <= 3, I want to have np.dot(A[i, :, :], B[i, :]).
How to do it without using a for-loop?
(A # B[...,np.newaxis])[...,0] should work (synactic sugar for np.matmul(A, B[...,np.newaxis])[...,0]).
Per the documentation for matmul:
If either argument is N-D, N > 2, it is treated as a stack of matrices residing in the last two indexes.
You can also use Einstein summation np.einsum("ijk,ik->ij", A, B), although on my machine this is apparently slower than broadcasting matmul:
import timeit
import numpy as np
A = np.random.rand(4, 2, 2)
B = np.random.rand(4, 2)
def broadcast_matmul():
return (A # B[..., np.newaxis])[..., 0]
def list_map():
return np.array(list(map(np.dot, A, B)))
def einsum():
return np.einsum("ijk,ik->ij", A, B)
print(timeit.timeit(broadcast_matmul))
print(timeit.timeit(list_map))
print(timeit.timeit(einsum))
# Results on my machine:
# 1.870921753
# 6.705698656999999
# 2.765732645
Here's how this could be done using np.einsum:
np.einsum('ijk,ik->ij', A, B)
array([[0.39437083, 0.45360039],
[0.75211742, 0.40669922],
[0.18131254, 0.19473085],
[0.2919673 , 0.10398859]])
Quick check using the first elements that are multiplied:
np.dot(A[0], B[0])
# array([0.39437083, 0.45360039])
This should do the trick:
list(map(np.dot, A, B))

How to upsample numpy array with nearest neighbor without storing repeated values?

Let's say I have an array 3x3 a and would like to upsample it to a 30x30 array b with nearest neighbor interpolation.
Is it possible to use a technique which does not actually store repeated values? Something similar on how broadcasting works in numpy.
e.g. I would like to have an object such that when I call b[x, x] with 0 < x < 10 I get a[0, 0].
I don't believe there is any way to do this using numpy. The way broadcasting works in numpy is that each axis has a "stride" parameter which controls how to calculate the next element along the axis. So for example:
In [1]: a = np.arange(10)
In [2]: a
Out[2]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
In [3]: b = a[::2]
In [4]: b
Out[4]: array([0, 2, 4, 6, 8])
In [5]: b.strides
Out[5]: (16,)
In [6]: a.strides
Out[6]: (8,)
In this case you can see that b is just a view of a obtained by doubling the stride along the first dimension. So when you access b[1], the offset is calculated as b.__array_interface__['data'][0] + b.strides[0].
In your case you essentially want a nonlinear stride, which isn't supported.
You could of course achieve this affect yourself by calculating the indexes yourself, i.e.:
a[x//10,x//10]
You could achieve an object like the one you describe by creating a class that wraps a numpy array and implements a custom __getitem__ method. That could look something like the below, where factor is the factor with which you want to upsample.
class UpSampled:
__slots__ = ('arr', 'factor')
def __init__(self, arr, factor):
self.arr = arr
self.factor = factor
def __getitem__(self, key):
return self.arr[key // self.factor]
You would then use it like below:
o = UpSampled(np.array([
UpSampled(np.array([0, 1, 2]), 10),
UpSampled(np.array([3, 4, 5]), 10),
UpSampled(np.array([6, 7, 8]), 10),
]), 10)
print(o[23][13]) # prints 7
If you need the object to be iterable you would then also implement __next__ and __iter__:
class UpSampled:
__slots__ = ('arr', 'factor', '__index')
def __init__(self, arr, factor):
self.arr = arr
self.factor = factor
self.__index = 0
def __getitem__(self, key):
return self.arr[key // self.factor]
def __iter__(self):
self.__index = 0
return self
def __next__(self):
try:
result = self[self.__index]
except IndexError:
raise StopIteration
self.__index += 1
return result
Though I'm not sure that would work well with libraries that specifically expect a numpy array.

numpy: syntax/idiom to cast (n,) array to a (n, 1) array?

I'd like to cast a numpy ndarray object of shape (n,) into one having shape (n, 1). The best I've come up with is to roll my own _to_col function:
def _to_col(a):
return a.reshape((a.size, 1))
But it is hard for me to believe that such a ubiquitous operation is not already built into numpy's syntax. I figure that I just have not been able to hit upon the right Google search to find it.
I'd use the following:
a[:,np.newaxis]
An alternative (but perhaps slightly less clear) way to write the same thing is:
a[:,None]
All of the above (including your version) are constant-time operations.
np.expand_dims is my favorite when I want to add arbitrary axis.
None or np.newaxis is good for code that doesn't need to have flexible axis. (aix's answer)
>>> np.expand_dims(np.arange(5), 0).shape
(1, 5)
>>> np.expand_dims(np.arange(5), 1).shape
(5, 1)
example usage: demean an array by any given axis
>>> x = np.random.randn(4,5)
>>> x - x.mean(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: shape mismatch: objects cannot be broadcast to a single shape
>>> ax = 1
>>> x - np.expand_dims(x.mean(ax), ax)
array([[-0.04152658, 0.4229244 , -0.91990969, 0.91270622, -0.37419434],
[ 0.60757566, 1.09020783, -0.87167478, -0.22299015, -0.60311856],
[ 0.60015774, -0.12358954, 0.33523495, -1.1414706 , 0.32966745],
[-1.91919832, 0.28125008, -0.30916116, 1.85416974, 0.09293965]])
>>> ax = 0
>>> x - np.expand_dims(x.mean(ax), ax)
array([[ 0.15469413, 0.01319904, -0.47055919, 0.57007525, -0.22754506],
[ 0.70385617, 0.58054228, -0.52226447, -0.66556131, -0.55640947],
[ 1.05009459, -0.27959876, 1.03830159, -1.23038543, 0.73003287],
[-1.90864489, -0.31414256, -0.04547794, 1.32587149, 0.05392166]])

Categories