from __future__ import annotations def fit_ridge_regression( features: list[list[float]], targets: list[float], ridge_lambda: float, ) -> list[float] | None: if not features: return None width = len(features[0]) xtx = [[0.0 for _ in range(width)] for _ in range(width)] xty = [0.0 for _ in range(width)] for row, target in zip(features, targets): for i in range(width): xty[i] += row[i] * target for j in range(width): xtx[i][j] += row[i] * row[j] for i in range(1, width): xtx[i][i] += ridge_lambda return solve_linear_system(xtx, xty) def solve_linear_system( matrix: list[list[float]], vector: list[float], ) -> list[float] | None: size = len(vector) rows = [matrix[index][:] + [vector[index]] for index in range(size)] for pivot_index in range(size): pivot_row = max( range(pivot_index, size), key=lambda row_index: abs(rows[row_index][pivot_index]), ) if abs(rows[pivot_row][pivot_index]) < 1e-9: return None rows[pivot_index], rows[pivot_row] = rows[pivot_row], rows[pivot_index] pivot = rows[pivot_index][pivot_index] rows[pivot_index] = [value / pivot for value in rows[pivot_index]] for row_index in range(size): if row_index == pivot_index: continue factor = rows[row_index][pivot_index] rows[row_index] = [ value - factor * pivot_value for value, pivot_value in zip(rows[row_index], rows[pivot_index]) ] return [row[-1] for row in rows] def dot(left: list[float], right: list[float]) -> float: return sum(left_value * right_value for left_value, right_value in zip(left, right)) def quantile(values: list[float], q: float) -> float: if not values: return 0.0 sorted_values = sorted(values) index = round((len(sorted_values) - 1) * q) return sorted_values[index]