azizalto/vanilla-ml-algorithms
5
1# src: https://gist.github.com/iamaziz/ea5863beaee090937fd6828e88653f5e2 3 4class LinearRegressionGradient:5 def __init__(self, theta=None):6 self.theta = theta7 self.loss_ = float("inf")8 9 def hypothesis(self, x):10 return self.theta[0] + self.theta[1] * x11 12 def loss(self, X, y):13 m = len(X)14 return sum([(X[i] - y[i]) ** 2 for i in range(m)]) / (2 * m)15 16 def gradientDescent(self, X, y, theta, num_iter=3000, alpha=0.01):17 m = len(X)18 19 for j in range(num_iter):20 21 # predict22 h = list(map(self.hypothesis, X))23 24 # compute slope, aka derivative with current params (theta)25 deri_th0 = sum([(h[i] - y[i]) for i in range(m)]) / m26 deri_th1 = sum([(h[i] - y[i]) * X[i] for i in range(m)]) / m27 28 # update parameters (moving against the gradient 'derivative')29 theta[0] = theta[0] - alpha * deri_th030 theta[1] = theta[1] - alpha * deri_th131 32 # report33 if j % 200 == 0:34 self.loss_ = self.loss(X, y)35 msg = f"loss: {self.loss_}"36 print(msg)37 38 39def app():40 import streamlit as st41 42 def header():43 st.subheader("Linear Regression using Gradient Descent")44 desc = """> Plain Python (vanilla version) i.e. without importing any library"""45 st.markdown(desc)46 47 header()48 49 st1, st2 = st.columns(2)50 with st1:51 code_math()52 with st2:53 interactive_run()54 55 st.markdown(56 f"> source [notebook](https://gist.github.com/iamaziz/ea5863beaee090937fd6828e88653f5e)."57 )58 59 60def code_math():61 import inspect62 import streamlit as st63 64 tex = st.latex65 write = st.write66 mark = st.write67 codify = lambda func: st.code(inspect.getsource(func), language="python")68 cls = LinearRegressionGradient(theta=[0, 0])69 70 write("The class")71 codify(cls.__init__)72 73 write("the Hypothesis")74 tex(r"""h_\theta(x) = \theta_0 + \theta_1x""")75 codify(cls.hypothesis)76 mark('The Loss/Objective/Cost function "_minimize_"')77 tex(r"""J(\theta_0, \theta_1) = \frac{1}{2m}\sum(h_\theta(x^{(i)}) - y^{(i)})^2""")78 codify(cls.loss)79 write("The Gradient Descent algorithm")80 mark("> repeat until converge {")81 tex(82 r"""\theta_0 = \theta_0 - \alpha \frac{1}{m} \sum_{i=1}^{m} (h_\theta(x^{(i)}) - y^{(i)} )"""83 )84 tex(85 r"""\theta_1 = \theta_1 - \alpha \frac{1}{m} \sum_{i=1}^{m} (h_\theta(x^{(i)}) - y^{(i)}) x^{(i)})"""86 )87 mark("> }")88 codify(cls.gradientDescent)89 90 91def interactive_run():92 import streamlit as st93 import numpy as np94 95 mark = st.markdown96 tex = st.latex97 98 def random_data(n=10):99 def sample_linear_regression_dataset(n):100 # src: https://www.gaussianwaves.com/2020/01/generating-simulated-dataset-for-regression-problems-sklearn-make_regression/101 import numpy as np102 from sklearn import datasets103 import matplotlib.pyplot as plt # for plotting104 105 x, y, coef = datasets.make_regression(106 n_samples=n, # number of samples107 n_features=1, # number of features108 n_informative=1, # number of useful features109 noise=40, # bias and standard deviation of the guassian noise110 coef=True, # true coefficient used to generated the data111 random_state=0,112 ) # set for same data points for each run113 114 # Scale feature x (years of experience) to range 0..20115 # x = np.interp(x, (x.min(), x.max()), (0, 20))116 117 # Scale target y (salary) to range 20000..150000118 # y = np.interp(y, (y.min(), y.max()), (20000, 150000))119 120 plt.ion() # interactive plot on121 plt.plot(x, y, ".", label="training data")122 plt.xlabel("Years of experience")123 plt.ylabel("Salary $")124 plt.title("Experience Vs. Salary")125 # st.pyplot(plt.show())126 # st.write(type(x.tolist()))127 # st.write(x.tolist())128 129 X, y = x.reshape(x.shape[0],), y.reshape(130 y.shape[0],131 )132 return np.around(X, 2), np.around(y, 2)133 # return [a[0] for a in x.tolist()], [a[0] for a in y.tolist()]134 # return [item for sublist in x.tolist() for item in sublist], [135 # item for sublist in y for item in sublist136 # ]137 138 X_, y_ = sample_linear_regression_dataset(n)139 return X_, y_140 # st.write(type(X_), type(y_))141 # st.write(type(np.round(X, 2).tolist()))142 # st.write(X_) # , y_)143 # return X, y144 145 # return np.around(X, 2).tolist(), np.around(y, 2).tolist()146 147 X, y = random_data()148 theta = [0, 0] # initial values149 model = LinearRegressionGradient(theta)150 mark("# Example")151 n = st.slider("Number of samples", min_value=10, max_value=200, step=10)152 if st.button("generate new data and solve"):153 X, y = random_data(n=n)154 mark("_Input_")155 mark(f"_X_ = {X}")156 mark(f"_y_ = {y}")157 model.gradientDescent(X, y, theta) # run to optimize thetas158 mark("_Solution_")159 tex(f"y = {model.theta[0]:.1f} + {model.theta[1]:.1f} x") # print solution160 tex(f"loss = {model.loss_}")161 162 mark("> How to run")163 mark(164 """165 ```python166 X, y = random_data()167 theta = [0, 0] # initial values168 model = LinearRegressionGradient(theta)169 model.gradientDescent(X, y, theta) # run "i.e. optimize thetas"170 # print solution171 # print(f"y = {model.theta[0]:.1f} + {model.theta[1]:.1f} x")172 # print(f"loss = {model.loss_}")173 ```174 """175 )176 # -- visualize177 import matplotlib.pyplot as plt178 179 fig, ax = plt.subplots()180 ax.scatter(X, y, label="Linear Relation")181 y_pred = theta[0] + theta[1] * np.array(X)182 ax.plot(X, y_pred)183 ax.grid(color="black", linestyle="--", linewidth=0.5, markevery=int)184 ax.legend(loc=2)185 # ax.axis("scaled")186 st.pyplot(fig)187 # st.line_chart(X, y)188 