Skip to content
Snippets Groups Projects
Commit d8a6187a authored by thibault.capt's avatar thibault.capt
Browse files

update

parent e50c7a0f
No related branches found
No related tags found
No related merge requests found
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="Black">
<option name="sdkName" value="Python 3.9 (tp-clustering)" />
</component>
<component name="MarkdownSettingsMigration"> <component name="MarkdownSettingsMigration">
<option name="stateVersion" value="1" /> <option name="stateVersion" value="1" />
</component> </component>
......
# Importation des bibliothèques # Importation des bibliothèques
from typing import Tuple, List
import pandas as pd import pandas as pd
import numpy as np import numpy as np
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
def import_csv(filename: str, h: int or None) -> pd.DataFrame:
"""
Importe un fichier CSV et retourne un DataFrame pandas.
Args:
filename (str): Le chemin du fichier CSV.
h (int or None, optional): L'entête du fichier CSV.
Returns:
pandas.DataFrame: Les données importées sous forme de DataFrame.
"""
return pd.read_csv(filename, header=h)
def manhattan_distance(x1: np.ndarray, x2: np.ndarray) -> float: def manhattan_distance(x1: np.ndarray, x2: np.ndarray) -> float:
""" distance = 0
Calcule la distance de Manhattan (L2) entre deux vecteurs. if x1.shape == x2.shape:
for i in range(x1.size):
Args: distance += np.abs(x1[i] - x2[i])
x1 (numpy.ndarray): Le premier vecteur. return distance
x2 (numpy.ndarray): Le deuxième vecteur.
Returns:
float: La distance de Manhattan entre x1 et x2.
"""
squared_diff = (x1 - x2) ** 2 # Carré des différences
l2_manhattan = np.sqrt(np.sum(squared_diff)) # Racine carrée de la somme des carrés
return l2_manhattan
def assign_clusters(X: np.ndarray, centroids: np.ndarray) -> np.ndarray:
"""
Attribue chaque point de données à son cluster le plus proche en utilisant la distance de Manhattan.
Args:
X (numpy.ndarray): Les données.
centroids (numpy.ndarray): Les centroïdes des clusters.
Returns:
numpy.ndarray: Les étiquettes de cluster attribuées à chaque point de données.
"""
distances = np.array([[manhattan_distance(x, centroid) for centroid in centroids] for x in X])
return np.argmin(distances, axis=1)
def k_means(X: np.ndarray, k: int, max_iterations: int = 100) -> Tuple[np.ndarray, np.ndarray]:
"""
Implémente l'algorithme K-Means pour regrouper les données en k clusters.
Args:
X (numpy.ndarray): Les données à regrouper.
k (int): Le nombre de clusters à former.
max_iterations (int, optional): Le nombre maximal d'itérations. Défaut à 100.
Returns:
tuple: Une paire contenant les étiquettes de cluster et les centroïdes finaux.
"""
# Initialisation des k-centroïdes de manière aléatoire
np.random.seed(0)
centroids = X[np.random.choice(X.shape[0], k, replace=False)] # séléctionne k points aléatoirement dans la liste X
old_centroids = np.zeros(centroids.shape) if __name__ == '__main__':
new_centroids = centroids.copy() dataset = pd.read_csv("Data/student-data-test.csv", header=0)
X = dataset.iloc[:, 1:].values
distances_history = [] # Pour stocker la somme des distances k = 3
iteration = 0
# pour vérifier que les centroides ne changent plus , il faut check que l'ancien et le nouveau soient pareils , on ajoute tout de même un nombre d'itérations max pour ne pas tourner à l'infini
while not np.array_equal(old_centroids, new_centroids) and iteration < max_iterations:
iteration += 1
labels = assign_clusters(X, new_centroids)
old_centroids = new_centroids.copy()
for i in range(k):
new_centroids[i] = np.mean(X[labels == i], axis=0)
# Calcul de la somme des distances au sein de chaque cluster (fonction objectif)
total_distance = 0
for i in range(k):
cluster_points = X[labels == i]
cluster_distance = np.sum([manhattan_distance(point, new_centroids[i]) for point in cluster_points])
total_distance += cluster_distance
distances_history.append(total_distance) # Initialisation des k-centroides de manière aléatoire
# Affichage des clusters à cette itération centroids = X[np.random.choice(X.shape[0], k, replace=False)]
plt.figure(figsize=(8, 6))
for i in range(k): max_iter = 100
cluster_points = X[labels == i]
plt.scatter(cluster_points[:, 0], cluster_points[:, 1], label=f"Cluster {i + 1}") # Algorithme K-Means
plt.scatter(new_centroids[:, 0], new_centroids[:, 1], marker="X", color="black", label="Centroids") for i in range(max_iter):
plt.xlabel("Caractéristique 1") # Créer des clusters vides
plt.ylabel("Caractéristique 2") clusters = [[] for _ in range(k)]
# Sauvegarder les anciens centroïdes
for point in X:
distances = [manhattan_distance(point, centroid) for centroid in centroids]
cluster_index = np.argmin(distances)
clusters[cluster_index].append(point)
# Sauvegarder les anciens centroïdes
old_centroids = centroids.copy()
# Mettre à jour les centroïdes en calculant la moyenne des points dans chaque cluster
for j in range(k):
if len(clusters[j]) > 0:
centroids[j] = np.mean(clusters[j], axis=0)
# Afficher les centroides finaux et les clusters
for iteration, centroid in enumerate(centroids):
cluster_points = np.array(clusters[iteration])
plt.scatter(cluster_points[:, 0], cluster_points[:, 1], label=f"Cluster {iteration}")
plt.scatter(centroid[0], centroid[1], marker="x", s=200, c="red", label=f"Centroïde {iteration + 1}")
plt.xlabel("Grade 1")
plt.ylabel("Grade 2")
plt.title(f"Clustering K-Means {i}")
plt.legend() plt.legend()
plt.title(f"Iteration {iteration}")
plt.show() plt.show()
# Tracer la somme des distances à chaque itération # Convergence ?
plt.figure(figsize=(8, 6)) if np.all(old_centroids == centroids):
plt.plot(range(1, iteration + 1), distances_history, marker='o') break
plt.xlabel("Iteration") \ No newline at end of file
plt.ylabel("Somme des distances")
plt.title("Evolution de la somme des distances")
plt.show()
return labels, new_centroids
if __name__ == "__main__":
# Initialiser k-centroides
# attribuer les points aux centroïde le plus proche (Manhattan / L2)
# Tant que les centroïdes bougent :
# Pour chaque cluster, calculer le point central du cluster (moyenne des coordonnées)
# noter si ancien centroïde ~= nouveau centroïde
# attribution des points aux nouveaux centroïdes
# calcul de la somme des distances au sein d'un cluster
# fonction objectif à minimiser
# plot la somme de la somme des distances à chaque itération
# afficher les nouveaux cluster à chaque itérations
# Charger les données depuis le fichier CSV
df = import_csv("Data/iris.csv", h=None)
X = df.iloc[:, :-1].values
k = 3
labels, centroids = k_means(X, k)
print("Nouveaux centroïdes finaux:")
print(centroids)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment