In [1]:
import seaborn as sns
sns.set_style('darkgrid')
In [2]:
plt.rcParams['animation.ffmpeg_path'] = '/home/uschmidt/bin/ffmpeg'
In [3]:
from matplotlib import animation, rc
from IPython.display import HTML
import matplotlib.patches as patches
In [4]:
plt.rcParams['font.size'] = 16
In [5]:
set_cell_width(75)








Data

In [6]:
M = [[153,5],[154,6],[154,6],[155,6],[158,5],[159,7],[160,6],[161,5],[163,6],[164,7],[165,7],[165,6],
     [165,7],[166,10],[167,9.5],[167,10],[168,10],[168,9],[170,10.5],[170,9.5],[170,8.5],[171,9],[173,10],
     [174,8],[174,10],[174,9],[175,12],[175,11],[176,9],[177,10],[178,11],[178,11],[178,12],[179,10.5],
     [179,11.5],[179,11],[180,13],[180,12],[183,12.5],[185,13]]
M = np.array(M)
M[:,0] /= 100 # convert to meters
#M = M[np.random.choice(len(M),size=20,replace=False)]
In [7]:
x, y = M[:,0], M[:,1]
X = np.stack((x, np.ones(len(M))),axis=-1)
Y = np.expand_dims(y,-1)
m_hat, b_hat = np.linalg.solve( X.T.dot(X), X.T.dot(Y) )
m_hat, b_hat = m_hat[0], b_hat[0]
In [8]:
plt.figure(figsize=(17,12))
plt.plot(x,y,'o',markersize=15)
plt.xlabel('height')
plt.ylabel('shoe size')
plt.ylim(3,15)
plt.xlim(1.5,1.9)
None;








Model

$ \Huge f(x) = \color{orange}{m} \cdot x \color{gray}{+b} $

In [9]:
r       = np.linspace(np.min(M[:,0]-0.2),np.max(M[:,0])+0.2)
ms      = np.linspace(m_hat-2,m_hat+2,21)
ms_many = np.linspace(ms[0],ms[-1],1001)
In [10]:
def fm(m):
    return (lambda x: m*x + b_hat)
In [11]:
plt.figure(figsize=(17,12))
plt.plot(x,y,'o',markersize=15)
plt.xlabel('height')
plt.ylabel('shoe size')
plt.plot(r,fm(m_hat)(r),'-',linewidth=5,label='f(x)')
plt.plot(1.66,fm(m_hat)(1.66),'o',markersize=15)
plt.text(1.665,7.7,'Prediction',color='C2',fontsize=20)
plt.ylim(3,15)
plt.xlim(1.5,1.9)
plt.legend()
None;








How good is the model?

In [12]:
def C(m):
    p = fm(m)(x)
    return np.sum(np.abs(y-p))

def plot_points(ax=None):
    return (plt.gca() if ax is None else ax).plot(x,y,'o',markersize=15)

def plot_line(m,ax=None):
    return (plt.gca() if ax is None else ax).plot(r,fm(m)(r),linewidth=5)
In [13]:
fig, ax = plt.subplots(1,2, figsize=(24,10))
fig.set_tight_layout(True)
plt.close()

def animate_cost(i):
    m = ms[i]
    artists = []
    for a in ax:
        a.clear()
    
    a = ax[0]
    for _x,_y in zip(x,y):
        artists.append(a.plot([_x,_x],[_y,fm(m)(_x)],'-',color='C8',alpha=1,linewidth=3))
    artists.append(plot_points(a))
    artists.append(plot_line(m,a))
    a.set_xlabel('height')
    a.set_ylabel('shoe size')
    a.set_ylim(3,15)
    a.set_xlim(1.5,1.9)
    #a.set_xlim(0,1.9)
    #a.set_ylim(b_hat,20)

    a = ax[1]
    artists.append(a.plot(ms_many,list(map(C,ms_many)),'-',color='C0',linewidth=5))
    artists.append(a.plot(m,C(m),'o',color='C1',markersize=20))
    a.set_xlabel('parameter m')
    a.set_ylabel('cost')
    
    return artists
In [14]:
anim = animation.FuncAnimation(fig, animate_cost, frames=0+1*len(ms), interval=250, blit=False)
HTML(anim.to_jshtml())
Out[14]:


Once Loop Reflect








Learning a good model

In [15]:
def dC(m):
    p = fm(m)(x)    
    return np.sum(np.sign(y-p) * x)

def tangentm(m):
    return lambda p: C(m) - dC(m)*(p-m)
In [16]:
fig, ax = plt.subplots(figsize=(17,12))
fig.set_tight_layout(True)
plt.close()

def get_m(m,t,i):
    _m = m
    for _ in range(i):
        _m += t*dC(_m)/len(x)
    return _m

def animate_learning(t=0.3,m_start=23.3):
    def _animate(i):
        artists = []
        ax.clear()

        artists.append(ax.plot(ms_many,list(map(C,ms_many)),'--',color='C0',linewidth=2))
        ax.set_xlabel('parameter m')
        ax.set_ylabel('cost')

        m = get_m(m_start,t,i)

        m_next = m + t*dC(m)/len(x)

        tangent = tangentm(m)
        p = 3
        artists.append(ax.plot([m-p,m+p],[tangent(m-p),tangent(m+p)],'-k',linewidth=3,alpha=0.3))

        ax.add_patch(patches.FancyArrowPatch(
            (m,C(m)),(m_next,tangent(m_next)),arrowstyle='->',mutation_scale=30,linewidth=5)
        )

        artists.append(ax.plot(m,C(m),'.',color='C1',markersize=25))
        #m = m_next
        ax.set_ylim(20, 140)
        ax.set_xlim((23, 27))
        return artists
    return _animate
In [17]:
anim = animation.FuncAnimation(fig, animate_learning(0.5), frames=30, interval=250, blit=False)
HTML(anim.to_jshtml())
Out[17]:


Once Loop Reflect
In [18]:
anim = animation.FuncAnimation(fig, animate_learning(0.1,26.6), frames=50, interval=200, blit=False)
HTML(anim.to_jshtml())
Out[18]:


Once Loop Reflect