#!/usr/bin/python3 # -*- coding: utf-8 -*- # %% numpy import numpy as np import timeit help(np) help(np.array) a = np.array([0, 1, 2, 3]) print(type(a)) print(type(a[0])) # Which is faster: L = range(1000) # This is ipython magic: # %timeit [i**2 for i in L] print(timeit.timeit(stmt="[i**2 for i in L]", setup="L = range(1000)", number=1000)) # versus a = np.arange(1000) # This is ipython magic: # %timeit a**2 print( timeit.timeit( stmt="a**2", setup="import numpy as np; a = np.arange(1000)", number=1000 ) ) # basic arrays a = np.array([0, 1, 2, 3]) print(a) print(a.ndim) print(a.shape) print(len(a)) # higher Dimensionality b = np.array([[0, 1, 2], [3, 4, 5]]) # 2 x 3 array print(b) print(b.ndim) print(b.shape) # returns the size of the first dimension print(len(b)) # creating arrays help(np.arange) a = np.arange(10) # 0 .. n-1 (!) print(a) b = np.arange(1, 9, 2) # start, end (exclusive), step print(b) help(np.ones) a = np.ones((3, 3)) # reminder: (3, 3) is a tuple print(a) # default dtype for ones is float64 print(type(a[0][0])) help(np.zeros) b = np.zeros((2, 2)) print(b) help(np.eye) c = np.eye(3) print(c) help(np.diag) d = np.diag(np.array([1, 2, 3, 4])) print(d) # data types in arrays a = np.array([1, 2, 3]) print(a.dtype) b = np.array([1.0, 2.0, 3.0]) print(b.dtype) # indexing: The usual python idiom for reversing a sequence is supported: a = np.arange(10) print(a) print(a[0], a[2], a[-1]) print(a[::-1]) # For multidimensional arrays, indexes are tuples of integers: a = np.diag(np.arange(3)) print(a) print(a[1][1]) # regular python indexing for 2d print(a[1, 1]) # nicer numpy indexing a[2, 1] = 10 # third line, second column print(a[2][1]) print(a) print(a[:, 1]) # col 2 print(a[1]) # row 2 """ In 2D, the first dimension corresponds to rows, the second to columns. for multidimensional a, a[0] is interpreted by taking all elements in the unspecified dimensions. """ # copying: NOT like regular python arrays """ A slicing operation creates a view on the original array, which is just a way of accessing array data. Thus the original array is not copied in memory. You can use np.may_share_memory() to check if two arrays share the same memory block. Note however, that this uses heuristics and may give you false positives. When modifying the view, the original array is modified as well: """ a = np.arange(10) print(a) b = a[::2] print(b) help(np.may_share_memory) print(np.may_share_memory(a, b)) b[0] = 12 print(b) print(a) # (!) a = np.arange(10) help(np.copy) c = a[::2].copy() # force a copy c[0] = 12 print(a) print(np.may_share_memory(a, c)) # array indexing using masks help(np.random.randint) np.random.seed(3) a = np.random.randint(0, 21, 15) print(a) print((a % 3 == 0)) mask = a % 3 == 0 extract_from_a = a[mask] # or, a[a%3==0] print(extract_from_a) # extract a sub-array with the mask a[a % 3 == 0] = -1 print(a) # Indexing with an array of integers a = np.arange(0, 100, 10) print(a) print(a[[2, 3, 2, 4, 2]]) # note: [2, 3, 2, 4, 2] is a Python list a[[9, 7]] = -100 print(a)