diff --git a/numpy_questions.py b/numpy_questions.py index 21fcec4b..8ae289c0 100644 --- a/numpy_questions.py +++ b/numpy_questions.py @@ -18,7 +18,7 @@ import numpy as np -def max_index(X): +def max_index(X: np.ndarray) -> tuple: """Return the index of the maximum in a numpy array. Parameters @@ -37,12 +37,24 @@ def max_index(X): If the input is not a numpy array or if the shape is not 2D. """ - i = 0 - j = 0 + # 1. Contrôle du type d'entrée (Doit être un np.ndarray) + if not isinstance(X, np.ndarray): + raise ValueError( + f"""L'entrée doit être un np.ndarray, mais le type + {type(X)} a été reçu.""") - # TODO - - return i, j + # 2. Contrôle des dimensions (Doit être 2D) + if X.ndim != 2: + raise ValueError( + f"""Le tableau doit être 2D pour cette fonction (il a + {X.ndim} dimensions).""") + # 3. Recherche de l'indice du maximum + for i in range(X.shape[0]): + for j in range(X.shape[1]): + if X[i, j] == np.max(X): + return (i, j) + # La fonction retourne la première occurrence du maximum en parcourant les + # lignes puis les colonnnes. def wallis_product(n_terms): @@ -62,6 +74,28 @@ def wallis_product(n_terms): pi : float The approximation of order `n_terms` of pi using the Wallis product. """ - # XXX : The n_terms is an int that corresponds to the number of - # terms in the product. For example 10000. - return 0. + if not isinstance(n_terms, int): + raise ValueError( + f"""Le paramètre doit être un entier, + (il est du type{type(n_terms)}""") + if n_terms < 1: + return 1.0 + + product = 1.0 + + # Itère de k=1 à n_terms (inclus) + for k in range(1, n_terms + 1): + # Calcule le numérateur (2k) et les dénominateurs (2k-1, 2k+1) + # On utilise des flottants (2.0 * k) pour garantir une division + # flottante + numerator = 2.0 * k + denominator1 = numerator - 1.0 + denominator2 = numerator + 1.0 + + # Le terme d'ordre k est (2k / (2k - 1)) * (2k / (2k + 1)) + term = (numerator / denominator1) * (numerator / denominator2) + + product *= term + # Le produit final est multiplié par 2 pour obtenir + # l'approximation de pi vu que l'intégrale donne pi/2. + return 2.0 * product diff --git a/sklearn_questions.py b/sklearn_questions.py index f65038c6..bf47eb6c 100644 --- a/sklearn_questions.py +++ b/sklearn_questions.py @@ -16,7 +16,8 @@ calling `flake8` at the root of the repo. Finally, you need to write docstring similar to the one in `numpy_questions` -for the methods you code and for the class. The docstring will be checked using +for the methods you code and for the class. The docstring will be checked +using `pydocstyle` that you can also call at the root of the repo. """ import numpy as np @@ -29,29 +30,59 @@ class OneNearestNeighbor(BaseEstimator, ClassifierMixin): - "OneNearestNeighbor classifier." + """OneNearestNeighbor classifier.""" def __init__(self): # noqa: D107 pass def fit(self, X, y): - """Write docstring. - - And describe parameters + """Le but du fit est juste de stocker les données d'entraînement. + + Parameters + ---------- + X : array, shape (n_samples, n_features) + Les échantillons d'entraînement. + y : array, shape (n_samples,) + Les étiquettes cibles des échantillons d'entraînement. + + Returns + ------- + self : object + L'estimateur entraîné (c'est à dire contenant les données + d'entraînement). """ X, y = check_X_y(X, y) check_classification_targets(y) self.classes_ = np.unique(y) self.n_features_in_ = X.shape[1] - # XXX fix + # Rajout des données d'entraînement dans l'estimateur + self.X_train_ = X + self.y_train_ = y + + # Marquer l'estimateur comme "entraîné" + self.is_fitted_ = True + return self def predict(self, X): - """Write docstring. + """Le but de la méthode predict est de prédire les étiquettes. - And describe parameters + Pour les chantillons de test X en utilisant les données d'entraînement + qui ont précédemment été stockées dans l'estimateur lors de + l'appel à fit. + + Parameters + ---------- + X : array-like, shape (n_samples, n_features) + Les échantillons de test pour lesquels prédire les étiquettes. + + Returns + ------- + y_pred : ndarray, shape (n_samples,) + Les étiquettes de classe prédites pour chaque échantillon de test. """ + # Vérification que l'estimateur a bien été entraîné check_is_fitted(self) X = check_array(X) y_pred = np.full( @@ -59,16 +90,39 @@ def predict(self, X): dtype=self.classes_.dtype ) - # XXX fix + # Itération sur chaque échantillon de test + for i in range(X.shape[0]): + x_test = X[i, :] + + # Calcul de la distance euclidienne entre x_test et tous + # les points + # d'entraînement (self.X_) + + distances = np.sum((self.X_train_ - x_test)**2, axis=1) + + # Trouver l'indice du point d'entraînement le plus proche + closest_index = np.argmin(distances) + + # L'étiquette prédite est celle du voisin le plus proche + y_pred[i] = self.y_train_[closest_index] + return y_pred def score(self, X, y): - """Write docstring. - - And describe parameters + """Retourne le pourcentage d'étiquettes bien pédites (Accuracy). + + Parameters + ---------- + X : array, shape (n_samples, n_features) + Les échantillons de test. + y : array, shape (n_samples,) + Les étiquettes cibles vraies pour X. + Returns + ------- + score : float + Le pourcentage d'étiquettes bien pédites. """ X, y = check_X_y(X, y) y_pred = self.predict(X) - # XXX fix - return y_pred.sum() + return np.mean(y_pred == y)