3. Copies and views
np.may_share_memory() to check if two arrays share the same memory block.
>> a = np.arange(10)
>> a
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>> b = a[::2]
>> b
array([0, 2, 4, 6, 8])
>> np.may_share_memory(a, b) # <--
True
>> b[0] = 12
>> b
array([12, 2, 4, 6, 8])
>> a # (!)
array([12, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>> a = np.arange(10)
>> c = a[::2].copy() # force a copy
>> c[0] = 12
>> a
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>> np.may_share_memory(a, c)
False
Compute prime numbers in 0–99, with a sieve
Construct a shape (100,) boolean array is_prime, filled with True in the beginning:
>> is_prime = np.ones((100,), dtype=bool)
Cross out 0 and 1 which are not primes:
>> is_prime[:2] = 0
For each integer j starting from 2, cross out its higher multiples:
>> N_max = int(np.sqrt(len(is_prime) - 1))
>> for j in range(2, N_max + 1):
is_prime[2*j::j] = False
>> np.nonzero(is_prime)
(array([ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59,
61, 67, 71, 73, 79, 83, 89, 97]),)
Skim through help(np.nonzero), and print the prime numbers
Follow-up:
– Move the above code into a script file named prime_sieve.py – Run it to check it works
– Use the optimization suggested in the sieve of Eratosthenes:
- Skip j which are already known to not be primes
- The first number to cross out is $𝑗^2$
4. Fancy indexing
Using boolean masks
>> np.random.seed(3)
>> a = np.random.randint(0, 21, 15)
>> a
array([10, 3, 8, 0, 19, 10, 11, 9, 10, 6, 0, 20, 12, 7, 14])
>> (a % 3 == 0)
array([False, True, False, True, False, False, False, True, False,
True, True, False, True, False, False])
>> mask = (a % 3 == 0)
>> extract_from_a = a[mask] # or, a[a%3==0]
>> extract_from_a # extract a sub-array with the mask
array([ 3, 0, 9, 6, 0, 12])
>> a[a % 3 == 0] = -1
>> a
array([10, -1, 8, -1, 19, 10, 11, -1, 10, -1, -1, 20, -1, 7, 14])
Indexing with an array of integers
>> a = np.arange(0, 100, 10)
>> a
array([ 0, 10, 20, 30, 40, 50, 60, 70, 80, 90])
>> a[[2,3,2,4,2]] # note: it is a python list
array([20, 30, 20, 40, 20])
>> a[[9, 7]] = -100
>> a
array([ 0, 10, 20, 30, 40, 50, 60, -100, 80, -100])
Tip: When a new array is created by indexing with an array of integers, the new array has the same shape as the array of integers:
>> a = np.arange(10)
>> idx = np.array([[3, 4], [9, 7]])
>> idx.shape
(2, 2)
>> a[idx]
array([[3, 4],
[9, 7]])