# numpy

import numpy as np
# Introspect
b = [1, 2, 3]
b?
print?
Docstring:
print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)

Prints the values to a stream, or to sys.stdout by default.
Optional keyword arguments:
file:  a file-like object (stream); defaults to the current sys.stdout.
sep:   string inserted between values, default a space.
end:   string appended after the last value, default a newline.
flush: whether to forcibly flush the stream.
Type:      builtin_function_or_method
# ndarray
arr = np.array([1, 2, 3, 4, 5])
arrr = np.array([6, 7, 8, 9, 10])
# Elementwise ops
arr + arr
array([ 2,  4,  6,  8, 10])
arr * arr
array([ 1,  4,  9, 16, 25])
arr * 2
array([ 2,  4,  6,  8, 10])
# Dot product
arr @ arr
55
arr @ arrr
130
# Dimensions
ndarray = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
ndarray.shape
(3, 3)
ndarray.dtype
dtype('int32')
ndarray.ndim
2
# Standard arrays
np.empty((1, 2)) # Uninitialized, may contain garbage values
np.full((1, 2), 1)
zeroes = np.zeros((2, 1))
ones = np.ones((3, 4))
print(f"{zeroes} \n{ones}")
[[0.]
 [0.]] 
[[1. 1. 1. 1.]
 [1. 1. 1. 1.]
 [1. 1. 1. 1.]]
# Range of values with step
np.arange(0.0, 1.0, 0.01)
array([0.  , 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 0.1 ,
       0.11, 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19, 0.2 , 0.21,
       0.22, 0.23, 0.24, 0.25, 0.26, 0.27, 0.28, 0.29, 0.3 , 0.31, 0.32,
       0.33, 0.34, 0.35, 0.36, 0.37, 0.38, 0.39, 0.4 , 0.41, 0.42, 0.43,
       0.44, 0.45, 0.46, 0.47, 0.48, 0.49, 0.5 , 0.51, 0.52, 0.53, 0.54,
       0.55, 0.56, 0.57, 0.58, 0.59, 0.6 , 0.61, 0.62, 0.63, 0.64, 0.65,
       0.66, 0.67, 0.68, 0.69, 0.7 , 0.71, 0.72, 0.73, 0.74, 0.75, 0.76,
       0.77, 0.78, 0.79, 0.8 , 0.81, 0.82, 0.83, 0.84, 0.85, 0.86, 0.87,
       0.88, 0.89, 0.9 , 0.91, 0.92, 0.93, 0.94, 0.95, 0.96, 0.97, 0.98,
       0.99])
# numpy datatypes
# np.string_ is a fixed length type and can truncate input
np.float16, np.uint16
(numpy.float16, numpy.uint16)
# Casting
np.array([], dtype=np.float64)
arr.astype(float) # Aliases to numpy types - np.float64 or f64
array([1., 2., 3., 4., 5.])
# Comparison (always elementwise)
arr > arr
array([False, False, False, False, False])
# Copies
# array slices are views on the original array.
# This means that the data is not copied, and any modifications to the view will be reflected in the source array. 
arr[2:4] = 5
arr
array([1, 2, 5, 5, 5])
arr.copy()[2:4] = 6 # deepcopy
arr
array([1, 2, 5, 5, 5])
# Indexing
ndarray[1, 2] == ndarray[1][2]
True
ndarray[:1, :2]
array([[1, 2]])
# Broadcasting
arrr = np.arange(12.).reshape((3, 4))
arrr - arrr[0]
array([[0., 0., 0., 0.],
       [4., 4., 4., 4.],
       [8., 8., 8., 8.]])
# Boolean indexing

# arr[~(arr == 2)] to negate or !=
# & for and , | for or
arr[arr == 2] 
array([2])
arr[arr > 2] = 10
arr
array([ 1,  2, 10, 10, 10])
# Fancy (array) indexing
ndarray[[2, 1]] # Copies data, takes according to row (2nd & then 1st row)
array([[7, 8, 9],
       [4, 5, 6]])
# Transpose & swap
np.dot(ndarray, ndarray.T) # T => transpose
ndarray @ ndarray.T
array([[ 14,  32,  50],
       [ 32,  77, 122],
       [ 50, 122, 194]])
ndarray.swapaxes(0, 1)
array([[1, 4, 7],
       [2, 5, 8],
       [3, 6, 9]])
# Pseudorandom samples
np.random.standard_normal(size=(5, 6))
array([[-0.69697595, -1.74038051, -0.06783632, -1.16146471, -0.12316914,
        -0.71279215],
       [-1.41162033,  0.83912327, -0.71976249, -1.47986609,  1.20433132,
         1.16619095],
       [-0.16042064, -0.11361358,  0.28245719, -0.9234597 ,  0.04988898,
         1.99353839],
       [ 1.46035852, -1.09550908, -1.14346266,  0.27899005, -0.70222611,
         1.90438647],
       [ 0.82745044,  1.09988516, -0.61022683,  0.55364067, -0.88242841,
         2.54438623]])
# Conditional logic functions
arr2 = np.random.standard_normal((4, 5))
np.where(arr2 < 0, -arr2, arr2)  # converts all negatives to positives
array([[0.75398837, 0.2977341 , 1.04743015, 1.51088881, 0.28397074],
       [0.54370474, 0.81307432, 0.26192031, 0.66278521, 0.49174989],
       [0.63724535, 0.17849544, 1.60944674, 1.96907561, 0.47699173],
       [2.0593055 , 0.54681449, 0.27932672, 0.96107564, 2.0786397 ]])
bools = np.array([True, False, False])
print(f"{np.any(bools)}\n{np.all(bools)}")
True
False
arr2.cumsum(axis=0)
array([[-0.75398837, -0.2977341 ,  1.04743015,  1.51088881, -0.28397074],
       [-0.21028363,  0.51534022,  0.78550984,  2.17367402,  0.20777914],
       [ 0.42696172,  0.33684477,  2.39495658,  0.20459841,  0.68477088],
       [-1.63234378,  0.88365926,  2.67428331, -0.75647724,  2.76341057]])
np.unique(arr)
array([ 1,  2, 10])
# Linear algebra
np.linalg.det(ndarray)
6.66133814775094e-16
np.linalg.eig(ndarray)
(array([ 1.61168440e+01, -1.11684397e+00, -4.22209278e-16]),
 array([[-0.23197069, -0.78583024,  0.40824829],
        [-0.52532209, -0.08675134, -0.81649658],
        [-0.8186735 ,  0.61232756,  0.40824829]]))