import numpy as np import typing from collections import defaultdict def kfold_split( num_objects: int, num_folds: int ) -> list[tuple[np.ndarray, np.ndarray]]: indices = np.arange(num_objects) fold_size = num_objects // num_folds result = [] for i in range(num_folds): start = i * fold_size if i == num_folds - 1: end = num_objects else: end = (i + 1) * fold_size val_indices = indices[start:end] train_indices = np.concatenate([indices[:start], indices[end:]]) result.append((train_indices, val_indices)) return result def knn_cv_score( X: np.ndarray, y: np.ndarray, parameters: dict[str, list], score_function: callable, folds: list[tuple[np.ndarray, np.ndarray]], knn_class: object, ) -> dict[str, float]: results = {} normalizers = parameters.get("normalizers", [(None, None)]) n_neighbors_list = parameters.get("n_neighbors", [5]) metrics_list = parameters.get("metrics", ["euclidean"]) weights_list = parameters.get("weights", ["uniform"]) for normalizer_tuple in normalizers: normalizer, normalizer_name = normalizer_tuple for n_neighbors in n_neighbors_list: for metric in metrics_list: for weight in weights_list: fold_scores = [] for train_idx, val_idx in folds: X_train, X_val = X[train_idx], X[val_idx] y_train, y_val = y[train_idx], y[val_idx] if normalizer is not None: normalizer_fitted = normalizer.fit(X_train) X_train = normalizer_fitted.transform(X_train) X_val = normalizer_fitted.transform(X_val) knn = knn_class( n_neighbors=n_neighbors, metric=metric, weights=weight ) knn.fit(X_train, y_train) y_pred = knn.predict(X_val) score = score_function(y_val, y_pred) fold_scores.append(score) mean_score = np.mean(fold_scores) key = (normalizer_name, n_neighbors, metric, weight) results[key] = mean_score return results