# Import some stuff
import numpy as np
import pandas as pd
import scipy.spatial.distance as spd
from pymer4.simulate import easy_multivariate_normal
from pymer4.models import Lm
import matplotlib.pyplot as plt
% matplotlib inline

# Prep some data 
X = easy_multivariate_normal(50,2,corrs=.2)
a, b = X[:,0], X[:,1]

"""
Explanation: Relationship between common similarity metrics
Reference
End of explanation
"""


np.dot(a,b)

"""
Explanation: Inner product
End of explanation
"""


a_centered = a - a.mean()
b_centered = b - b.mean()

np.dot(a_centered,b_centered) / len(a) # could have used len(b) instead

# Check our work
np.cov(a,b,ddof=0)[0][1]

"""
Explanation: Covariance
Average centered inner product
End of explanation
"""


# Euclidean/L2 norm = square root of sum of squared values
# algebra form
a_norm = np.sqrt(np.sum(np.power(a,2)))
# matrix form
b_norm = np.sqrt(np.dot(b,b.T)) 
# numpy short-cut
# np.linalg.norm(a)
np.dot(a,b) / (a_norm * b_norm)

# Check our work (subract 1 because scipy returns distances)
1 - spd.cosine(a,b)

"""
Explanation: Cosine Similarity
Normalized (L2) inner product
End of explanation
"""


# Can think of this as normalized covariance OR centered cosine similarity
a_centered_norm = np.linalg.norm(a_centered)
b_centered_norm = np.linalg.norm(b_centered)
np.dot(a_centered,b_centered) / (a_centered_norm * b_centered_norm)

# Check our work
1 - spd.correlation(a,b)

"""
Explanation: Pearson Correlation
Normalized (L2) centered inner product
End of explanation
"""


# Can think of this as cosine similarity using only one vector
np.dot(a,b) / (a_norm * a_norm)

# Check our work
model = Lm('B ~ 0 + A',data=pd.DataFrame({'A':a,'B':b}))
model.fit(summarize=False)
model.coefs.iloc[-1,0]

"""
Explanation: OLS (univariate w/o intercept)
Partially normalized inner product, where partially means applied to only one vector
End of explanation
"""


# In the numerator we could actually center a or b, or both.
np.dot(a_centered,b) / (a_centered_norm * a_centered_norm)

# Check our work
model = Lm('B ~ A',data=pd.DataFrame({'A':a,'B':b}))
model.fit(summarize=False)
model.coefs.iloc[-1,0]

"""
Explanation: OLS (univariate w/ intercept)
Centered, partially normalized inner product, where partially means applied to only one vector
End of explanation
"""


