44"""
55
66import numpy as np
7+ from typing import Tuple , List , Union
78
89# List of input, output pairs
910train_data = (
1920LEARNING_RATE = 0.009
2021
2122
22- def _error (example_no , data_set = "train" ):
23+ def _error (example_no : int , data_set : str = "train" ) -> float :
2324 """
2425 :param data_set: train data or test data
2526 :param example_no: example number whose error has to be checked
@@ -30,7 +31,7 @@ def _error(example_no, data_set="train"):
3031 )
3132
3233
33- def _hypothesis_value (data_input_tuple ) :
34+ def _hypothesis_value (data_input_tuple : Tuple [ float , ...]) -> float :
3435 """
3536 Calculates hypothesis function value for a given input
3637 :param data_input_tuple: Input tuple of a particular example
@@ -46,7 +47,7 @@ def _hypothesis_value(data_input_tuple):
4647 return hyp_val
4748
4849
49- def output (example_no , data_set ) :
50+ def output (example_no : int , data_set : str ) -> float :
5051 """
5152 :param data_set: test data or train data
5253 :param example_no: example whose output is to be fetched
@@ -59,7 +60,7 @@ def output(example_no, data_set):
5960 return None
6061
6162
62- def calculate_hypothesis_value (example_no , data_set ) :
63+ def calculate_hypothesis_value (example_no : int , data_set : str ) -> float :
6364 """
6465 Calculates hypothesis value for a given example
6566 :param data_set: test data or train_data
@@ -73,7 +74,7 @@ def calculate_hypothesis_value(example_no, data_set):
7374 return None
7475
7576
76- def summation_of_cost_derivative (index , end = m ) :
77+ def summation_of_cost_derivative (index : int , end : int = m ) -> float :
7778 """
7879 Calculates the sum of cost function derivative
7980 :param index: index wrt derivative is being calculated
@@ -91,7 +92,7 @@ def summation_of_cost_derivative(index, end=m):
9192 return summation_value
9293
9394
94- def get_cost_derivative (index ) :
95+ def get_cost_derivative (index : int ) -> float :
9596 """
9697 :param index: index of the parameter vector wrt to derivative is to be calculated
9798 :return: derivative wrt to that index
@@ -102,7 +103,7 @@ def get_cost_derivative(index):
102103 return cost_derivative_value
103104
104105
105- def run_gradient_descent ():
106+ def run_gradient_descent () -> None :
106107 global parameter_vector
107108 # Tune these values to set a tolerance value for predicted output
108109 absolute_error_limit = 0.000002
@@ -127,13 +128,89 @@ def run_gradient_descent():
127128 print (("Number of iterations:" , j ))
128129
129130
130- def test_gradient_descent ():
131+ def test_gradient_descent () -> None :
131132 for i in range (len (test_data )):
132133 print (("Actual output value:" , output (i , "test" )))
133134 print (("Hypothesis output:" , calculate_hypothesis_value (i , "test" )))
134135
135136
137+ def run_gradient_descent_vectorized () -> None :
138+ """
139+ Vectorized implementation of gradient descent for a linear hypothesis
140+ using NumPy arrays for efficient matrix operations.
141+ """
142+ global parameter_vector
143+
144+ # Convert training data into NumPy arrays
145+ X = np .array ([x for x , _ in train_data ])
146+ y = np .array ([y for _ , y in train_data ])
147+
148+ # Add bias term (column of ones)
149+ X = np .hstack ((np .ones ((X .shape [0 ], 1 )), X ))
150+
151+ # Convert parameter vector to NumPy array
152+ theta = np .array (parameter_vector , dtype = float )
153+
154+ absolute_error_limit = 0.000002
155+ relative_error_limit = 0
156+ j = 0
157+
158+ while True :
159+ j += 1
160+
161+ # Compute predictions
162+ predictions = X @ theta
163+
164+ # Compute errors
165+ errors = predictions - y
166+
167+ # Compute gradient
168+ gradient = (X .T @ errors ) / len (y )
169+
170+ # Update parameters
171+ new_theta = theta - LEARNING_RATE * gradient
172+
173+ # Check for convergence
174+ if np .allclose (
175+ theta ,
176+ new_theta ,
177+ atol = absolute_error_limit ,
178+ rtol = relative_error_limit ,
179+ ):
180+ break
181+
182+ theta = new_theta
183+
184+ parameter_vector = theta .tolist ()
185+ print (("Number of iterations (vectorized):" , j ))
186+
187+
188+ def test_gradient_descent_vectorized () -> None :
189+ """
190+ Tests the vectorized gradient descent implementation on test data
191+ and prints predicted vs actual outputs.
192+ """
193+ X_test = np .array ([x for x , _ in test_data ])
194+ y_test = np .array ([y for _ , y in test_data ])
195+
196+ # Add bias term
197+ X_test = np .hstack ((np .ones ((X_test .shape [0 ], 1 )), X_test ))
198+
199+ theta = np .array (parameter_vector , dtype = float )
200+ predictions = X_test @ theta
201+
202+ for i in range (len (test_data )):
203+ print (("Actual output value:" , y_test [i ]))
204+ print (("Hypothesis output:" , predictions [i ]))
205+
206+
136207if __name__ == "__main__" :
208+ print ("Running naive (loop-based) gradient descent...\n " )
137209 run_gradient_descent ()
138210 print ("\n Testing gradient descent for a linear hypothesis function.\n " )
139211 test_gradient_descent ()
212+
213+ print ("\n Running vectorized gradient descent using NumPy...\n " )
214+ run_gradient_descent_vectorized ()
215+ print ("\n Testing vectorized gradient descent.\n " )
216+ test_gradient_descent_vectorized ()
0 commit comments