From 557aa7a24ad964650fba3c27e8f053eacb8f218e Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 11 Feb 2026 17:37:36 +0000 Subject: [PATCH] Add simple linear regression implementation using OOP concepts Demonstrates dataclasses, composition, magic methods (__str__, __repr__, __call__), and least-squares regression with standard library only. https://claude.ai/code/session_01Bxm15bjeKqWxyKcstiJP4E --- linear_regression.py | 106 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 linear_regression.py diff --git a/linear_regression.py b/linear_regression.py new file mode 100644 index 0000000..c467dc7 --- /dev/null +++ b/linear_regression.py @@ -0,0 +1,106 @@ +# Python Object Oriented Programming by Joe Marini course example +# Simple linear regression using OOP concepts + +from dataclasses import dataclass + + +@dataclass +class DataPoint: + """Represents a single (x, y) data observation.""" + x: float + y: float + + def __str__(self): + return f"({self.x}, {self.y})" + + +class SimpleLinearRegression: + """Performs simple linear regression (y = mx + b) using least squares.""" + + def __init__(self, data_points): + if len(data_points) < 2: + raise ValueError("At least 2 data points are required") + + self._x_data = [p.x for p in data_points] + self._y_data = [p.y for p in data_points] + self._slope = None + self._intercept = None + self._fit() + + def _fit(self): + """Compute slope and intercept using the least-squares method.""" + n = len(self._x_data) + sum_x = sum(self._x_data) + sum_y = sum(self._y_data) + sum_xy = sum(x * y for x, y in zip(self._x_data, self._y_data)) + sum_x2 = sum(x ** 2 for x in self._x_data) + + denominator = n * sum_x2 - sum_x ** 2 + if denominator == 0: + raise ValueError("All x values are identical; cannot compute regression") + + self._slope = (n * sum_xy - sum_x * sum_y) / denominator + self._intercept = (sum_y - self._slope * sum_x) / n + + def predict(self, x): + """Predict y for a given x value.""" + return self._slope * x + self._intercept + + def get_r_squared(self): + """Compute the R-squared (coefficient of determination).""" + y_mean = sum(self._y_data) / len(self._y_data) + ss_tot = sum((y - y_mean) ** 2 for y in self._y_data) + if ss_tot == 0: + return 1.0 + ss_res = sum( + (y - self.predict(x)) ** 2 + for x, y in zip(self._x_data, self._y_data) + ) + return 1 - (ss_res / ss_tot) + + def __str__(self): + return (f"LinearRegression: y = {self._slope:.4f}x + " + f"{self._intercept:.4f} (R²={self.get_r_squared():.4f})") + + def __repr__(self): + return (f"SimpleLinearRegression(n={len(self._x_data)}, " + f"slope={self._slope:.4f}, intercept={self._intercept:.4f})") + + def __call__(self, x): + """Make the model callable for predictions.""" + return self.predict(x) + + +# ~~~~~~~~~ TEST CODE ~~~~~~~~~ +# Sample data: years of experience vs. salary (in thousands) +data = [ + DataPoint(1.0, 45.0), + DataPoint(2.0, 50.0), + DataPoint(3.0, 55.0), + DataPoint(4.0, 60.0), + DataPoint(5.0, 68.0), + DataPoint(6.0, 72.0), + DataPoint(7.0, 80.0), + DataPoint(8.0, 85.0), + DataPoint(9.0, 90.0), + DataPoint(10.0, 95.0), +] + +# Create the regression model +model = SimpleLinearRegression(data) + +# Display the model equation +print(model) + +# Make predictions using the predict method +print(f"Predicted salary for 5 years exp: {model.predict(5.0):.2f}k") +print(f"Predicted salary for 15 years exp: {model.predict(15.0):.2f}k") + +# Use the model as a callable (demonstrates __call__) +print(f"Predicted salary for 12 years exp: {model(12.0):.2f}k") + +# Display model details using repr +print(repr(model)) + +# Show R-squared value +print(f"R-squared: {model.get_r_squared():.4f}")