#!/usr/bin/env python # coding: utf-8 # ## numpy broadcasting is like "sharing" a smaller array for the bigger array # - An array sharing a number # - Regression paramters/weights sharing 1 intercept # - Image data classification 2-D array of weights sharing 1-D array of intercept weights # # # ### Remember: # # # 1. shape (3,) is treated as (1,3) # # 2. shape column sizes must match in order to broadcast # # 3. any ufunc can be broadcasted, not just +- # In[1]: import numpy as np # # # ## [Broadcasting 1 number](#Broadcasting1Number) # # ## [Broadcasting 1D array](#Broadcasting1D) # # ## [Broadcast 2 ways](#two-way) # # ## [Examples](#examples) # # *** # # ## Broadcasting 1 number # In[2]: a = np.arange(10) a # In[3]: a +10 # In[4]: a = np.arange(15).reshape(3,5) # In[5]: a + 1000 # # ## Broadcasting 1D array # In[6]: a = np.arange(3) a # In[7]: b = np.eye(3) b # In[8]: a + b # In[9]: b = np.ones((2,3), int) # In[10]: a + b #
# Won't work: when column sizes don't match unless one of them has only 1 column! Column sizes must match! (3,) is treated as (1,3) when broadcasting. (6,) is treated as (1,6) #
# In[11]: b = np.arange(10) b # In[12]: a + b # In[ ]: # even though 6 is divisable by 3, a refuses to be shared :( b = np.arange(6) a + b # In[ ]: # as soon as we reshape b to have the same column size as a, it works. a + b.reshape(2,3) # # ## Broadcast two ways # In[ ]: a = np.arange(3) a.shape # In[ ]: a # In[ ]: b = np.arange(3)[:, np.newaxis] b.shape # In[ ]: b # In[ ]: # it is working because b has 1 column a + b # # ## Examples # ### Ex. 1 long - wide # - long duplicates itself horizontally to match wide's width # - wide duplicates itself vertically to match long's width # In[ ]: X = np.ones((2,1), dtype=int) X # In[ ]: Y = np.ones((1,2), dtype=int) Y # In[ ]: X - Y # ### Ex. 2 long - wide # - long duplicates itself horizontally to match wide's width # - wide duplicates itself vertically to match long's width # In[ ]: X = np.full((2,1),2) X # In[ ]: Y = np.full((1,2),1) Y # In[ ]: X - Y # ### Ex. 3 long - wide # - long duplicates itself horizontally to match wide's width # - wide duplicates itself vertically to match long's width # In[ ]: X = np. array([[1],[2]]) X # In[ ]: Y = np.array([[2, 1]]) Y # In[ ]: X -Y # ## Tricking it into doing something with evey row # If we think of each row is a point on 2-D space (like a sheet of paper), if we want to get its distance from all other points, including itself,which we called X here, # # then we reshape a copy of it into 3-D space, which we call Y. So when we take the difference between them, X will be duplicated along the 3rd dimension. # # The trick is that we do not reshape Y in (2,2,1). Rather, we reshape Y in (2,1,2). # # In the first 2D space, X is (2,2) whereas Y is (2,1). So Y has to duplicate itself to become (2,2). # # In the last dimension, X has to duplicate itself for Y. # In[ ]: X = np.array([[1,0], [2,1]]) X # In[ ]: Y = X.reshape(2,1,2) Y # In[ ]: #[[0,0] ,[-1,-1]] = [[1, 0]] - [[1, 0],[2, 1]] #[[ 1, 1],[ 0, 0]]] = [[2, 1]] - [[1, 0],[2, 1]] Y-X # #### Let's check to see if we can replicate what numpy did # In[ ]: np.array([[1, 0]]) - np.array([[1, 0],[2, 1]]) # In[ ]: np.array([[2, 1]]) - np.array([[1, 0],[2, 1]]) # In[ ]: np.hstack((np.array([[1, 0]]) - np.array([[1, 0],[2, 1]]), np.array([[2, 1]])) - np.array([[1, 0],[2, 1]]) )