import pandas as pd
import numpy as np
import string as str

"""
Explanation: Generalized Linear Model
4 Features ==> 1 Target
Employs Gradient Descent
It works
End of explanation
"""


train_data = pd.read_csv('train_data.csv',header = 0)

y = train_data["Target"]
y = y.values #convert to ndarray

train_data = train_data.drop("Target",1)
x = train_data.values

x = np.c_[np.ones(x.shape[0]),x]


def calculateCost (HypothesisFn,y,x):
    distance = HypothesisFn - y
    return (np.sum((distance)**2)/(2*distance.size))

def derivativeOf(HypothesisFn,y,x):
    distance = HypothesisFn - y
    deriv = np.dot(x.transpose(), distance)
    deriv /= y.shape[0]
    return deriv

Parameters = np.zeros(5) #initialize parameters
HypothesisFn = np.dot(x,Parameters)

"""
Explanation: x ==> Array of Feature Values
x[1] returns a column of training values for the second feature
y ==> Result Array. The values the Hypothesis fn should train to.
End of explanation
"""


LearningRate = 0.1
while True:
    Parameters = Parameters - LearningRate*derivativeOf(HypothesisFn,y,x)
    HypothesisFn = np.dot(x,Parameters)
    cost = calculateCost (HypothesisFn,y,x)
    if ( cost <= 10**(-25)):
        break

# 10^-25 seems pretty negligible. = ¯\_(ツ)_/¯

print ("\nThe Hypothesis function is {0}".format(Parameters[0])),
for i in range(1,Parameters.size):
    print (" + {0}x{1}".format(Parameters[i],i)),

test_input = pd.read_csv('test_input.csv',header = 0)
test_input = test_input.values
test_input = np.c_[np.ones(test_input.shape[0]),test_input]

prediction = np.dot (test_input, Parameters)

test_input = np.delete(test_input, (0), axis=1)
test_input = np.c_[test_input,prediction]

output = pd.DataFrame(data=test_input, columns = ["Variable 1","Variable 2","Variable 3","Variable 4","Prediction"])
output.to_csv('test_output.csv', index=False, header=True, sep=',')
print output #Boom shakalaka

"""
Explanation: If anyone's wondering why I didn't transpose my Parameters array, one dimensional arrays do not need to be transposed to be multiplied. np.dot figures it out on its own. 
np.dot is the real bae
End of explanation
"""


