# Linear Regression : It is only for study
# Copyright : yoonkt200@gmail.com
# Apache License 2.0
# =============================================================================

import numpy as np


class OLS():
    def __init__(self, x_data, y_data):
        self._x_data = x_data
        self._y_data = y_data

    def fit(self):
        # exactly same as MLE (when y has normal distribution)
        self._coefficients = np.linalg.inv(self._x_data.transpose().dot(self._x_data)).dot(self._x_data.transpose()).dot(self._y_data)
        y_hat = np.sum(self._x_data * self._coefficients, axis=1)
        mse = np.mean(np.square(self._y_data - y_hat))
        mse_of_average_data = np.mean(np.square(self._y_data - np.mean(self._y_data)))
        self._r2_score = 1 - (mse / mse_of_average_data)

    def print_results(self):
        print(self._coefficients)
        print(self._r2_score)


if __name__ == "__main__":
    # intercept, friends, work hour, Acquired doctoral degree
    input = [[1, 49, 4, 0], [1, 41, 9, 0], [1, 40, 8, 0], [1, 25, 6, 0], [1, 21, 1, 0], [1, 21, 0, 0], [1, 19, 3, 0],
             [1, 19, 0, 0], [1, 18, 9, 0], [1, 18, 8, 0], [1, 16, 4, 0], [1, 15, 3, 0], [1, 15, 0, 0], [1, 15, 2, 0],
             [1, 15, 7, 0], [1, 14, 0, 0], [1, 14, 1, 0], [1, 13, 1, 0], [1, 13, 7, 0], [1, 13, 4, 0], [1, 13, 2, 0],
             [1, 12, 5, 0], [1, 12, 0, 0], [1, 11, 9, 0], [1, 10, 9, 0], [1, 10, 1, 0], [1, 10, 1, 0], [1, 10, 7, 0],
             [1, 10, 9, 0], [1, 10, 1, 0], [1, 10, 6, 0], [1, 10, 6, 0], [1, 10, 8, 0], [1, 10, 10, 0], [1, 10, 6, 0],
             [1, 10, 0, 0], [1, 10, 5, 0], [1, 10, 3, 0], [1, 10, 4, 0], [1, 9, 9, 0], [1, 9, 9, 0], [1, 9, 0, 0],
             [1, 9, 0, 0], [1, 9, 6, 0], [1, 9, 10, 0], [1, 9, 8, 0], [1, 9, 5, 0], [1, 9, 2, 0], [1, 9, 9, 0],
             [1, 9, 10, 0], [1, 9, 7, 0], [1, 9, 2, 0], [1, 9, 0, 0], [1, 9, 4, 0], [1, 9, 6, 0], [1, 9, 4, 0],
             [1, 9, 7, 0], [1, 8, 3, 0], [1, 8, 2, 0], [1, 8, 4, 0], [1, 8, 9, 0], [1, 8, 2, 0], [1, 8, 3, 0],
             [1, 8, 5, 0], [1, 8, 8, 0], [1, 8, 0, 0], [1, 8, 9, 0], [1, 8, 10, 0], [1, 8, 5, 0], [1, 8, 5, 0],
             [1, 7, 5, 0], [1, 7, 5, 0], [1, 7, 0, 0], [1, 7, 2, 0], [1, 7, 8, 0], [1, 7, 10, 0], [1, 7, 5, 0],
             [1, 7, 3, 0], [1, 7, 3, 0], [1, 7, 6, 0], [1, 7, 7, 0], [1, 7, 7, 0], [1, 7, 9, 0], [1, 7, 3, 0],
             [1, 7, 8, 0], [1, 6, 4, 0], [1, 6, 6, 0], [1, 6, 4, 0], [1, 6, 9, 0], [1, 6, 0, 0], [1, 6, 1, 0],
             [1, 6, 4, 0], [1, 6, 1, 0], [1, 6, 0, 0], [1, 6, 7, 0], [1, 6, 0, 0], [1, 6, 8, 0], [1, 6, 4, 0],
             [1, 6, 2, 1], [1, 6, 1, 1], [1, 6, 3, 1], [1, 6, 6, 1], [1, 6, 4, 1], [1, 6, 4, 1], [1, 6, 1, 1],
             [1, 6, 3, 1], [1, 6, 4, 1], [1, 5, 1, 1], [1, 5, 9, 1], [1, 5, 4, 1], [1, 5, 6, 1], [1, 5, 4, 1],
             [1, 5, 4, 1], [1, 5, 10, 1], [1, 5, 5, 1], [1, 5, 2, 1], [1, 5, 4, 1], [1, 5, 4, 1], [1, 5, 9, 1],
             [1, 5, 3, 1], [1, 5, 10, 1], [1, 5, 2, 1], [1, 5, 2, 1], [1, 5, 9, 1], [1, 4, 8, 1], [1, 4, 6, 1],
             [1, 4, 0, 1], [1, 4, 10, 1], [1, 4, 5, 1], [1, 4, 10, 1], [1, 4, 9, 1], [1, 4, 1, 1], [1, 4, 4, 1],
             [1, 4, 4, 1], [1, 4, 0, 1], [1, 4, 3, 1], [1, 4, 1, 1], [1, 4, 3, 1], [1, 4, 2, 1], [1, 4, 4, 1],
             [1, 4, 4, 1], [1, 4, 8, 1], [1, 4, 2, 1], [1, 4, 4, 1], [1, 3, 2, 1], [1, 3, 6, 1], [1, 3, 4, 1],
             [1, 3, 7, 1], [1, 3, 4, 1], [1, 3, 1, 1], [1, 3, 10, 1], [1, 3, 3, 1], [1, 3, 4, 1], [1, 3, 7, 1],
             [1, 3, 5, 1], [1, 3, 6, 1], [1, 3, 1, 1], [1, 3, 6, 1], [1, 3, 10, 1], [1, 3, 2, 1], [1, 3, 4, 1],
             [1, 3, 2, 1], [1, 3, 1, 1], [1, 3, 5, 1], [1, 2, 4, 1], [1, 2, 2, 1], [1, 2, 8, 1], [1, 2, 3, 1],
             [1, 2, 1, 1], [1, 2, 9, 1], [1, 2, 10, 1], [1, 2, 9, 1], [1, 2, 4, 1], [1, 2, 5, 1], [1, 2, 0, 1],
             [1, 2, 9, 1], [1, 2, 9, 1], [1, 2, 0, 1], [1, 2, 1, 1], [1, 2, 1, 1], [1, 2, 4, 1], [1, 1, 0, 1],
             [1, 1, 2, 1], [1, 1, 2, 1], [1, 1, 5, 1], [1, 1, 3, 1], [1, 1, 10, 1], [1, 1, 6, 1], [1, 1, 0, 1],
             [1, 1, 8, 1], [1, 1, 6, 1], [1, 1, 4, 1], [1, 1, 9, 1], [1, 1, 9, 1], [1, 1, 4, 1], [1, 1, 2, 1],
             [1, 1, 9, 1], [1, 1, 0, 1], [1, 1, 8, 1], [1, 1, 6, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 5, 1]]
    x_data = np.array(input)

    # output hour
    output = [68.77, 51.25, 52.08, 38.36, 44.54, 57.13, 51.4, 41.42, 31.22, 34.76, 54.01, 38.79, 47.59, 49.1, 27.66,
              41.03, 36.73, 48.65, 28.12, 46.62, 35.57, 32.98, 35, 26.07, 23.77, 39.73, 40.57, 31.65, 31.21, 36.32,
              20.45, 21.93, 26.02, 27.34, 23.49, 46.94, 30.5, 33.8, 24.23, 21.4, 27.94, 32.24, 40.57, 25.07, 19.42,
              22.39, 18.42, 46.96, 23.72, 26.41, 26.97, 36.76, 40.32, 35.02, 29.47, 30.2, 31, 38.11, 38.18, 36.31,
              21.03, 30.86, 36.07, 28.66, 29.08, 37.28, 15.28, 24.17, 22.31, 30.17, 25.53, 19.85, 35.37, 44.6, 17.23,
              13.47, 26.33, 35.02, 32.09, 24.81, 19.33, 28.77, 24.26, 31.98, 25.73, 24.86, 16.28, 34.51, 15.23, 39.72,
              40.8, 26.06, 35.76, 34.76, 16.13, 44.04, 18.03, 19.65, 32.62, 35.59, 39.43, 14.18, 35.24, 40.13, 41.82,
              35.45, 36.07, 43.67, 24.61, 20.9, 21.9, 18.79, 27.61, 27.21, 26.61, 29.77, 20.59, 27.53, 13.82, 33.2, 25,
              33.1, 36.65, 18.63, 14.87, 22.2, 36.81, 25.53, 24.62, 26.25, 18.21, 28.08, 19.42, 29.79, 32.8, 35.99,
              28.32, 27.79, 35.88, 29.06, 36.28, 14.1, 36.63, 37.49, 26.9, 18.58, 38.48, 24.48, 18.95, 33.55, 14.24,
              29.04, 32.51, 25.63, 22.22, 19, 32.73, 15.16, 13.9, 27.2, 32.01, 29.27, 33, 13.74, 20.42, 27.32, 18.23,
              35.35, 28.48, 9.08, 24.62, 20.12, 35.26, 19.92, 31.02, 16.49, 12.16, 30.7, 31.22, 34.65, 13.13, 27.51,
              33.2, 31.57, 14.1, 33.42, 17.44, 10.12, 24.42, 9.82, 23.39, 30.93, 15.03, 21.67, 31.09, 33.29, 22.61,
              26.89, 23.48, 8.38, 27.81, 32.35, 23.84]
    y_data = np.array(output)

    # fit OLS
    ols = OLS(x_data=x_data, y_data=y_data)
    ols.fit()
    ols.print_results()
