Autor : MEKA Moise Christian Junior
Email : junior.meka@facsciences-uy1.cm
Institution : Universite de Yaounde 1 - Cameroon

NOTICE DE DATA MINING

Cette notice a pour but d’aider les étudiants d’informatique M1 à la réalisation de leur TP de Fouille de Données 2 du 16-01-2025 et pourra être utilisé comme guide si le besoin se présente.

0- Packages à utiliser

0.1- Liste des packages

  • numpy
  • pandas
  • matplotlib
  • seaborn
  • scikit-learn
  • scipy
  • pyclustering
  • networkx
  • metis
  • scikit-mine
  • mlxtend
  • pycspade

0.2- Installation des packages python

##NB : Vous pouvez aussi juste utiliser pip

#installation de numpy, pandas, matplotlib et seaborn 
pip3 install numpy pandas matplotlib seaborn 

#Installer mlxtend
pip install mlxtend

#Installation de scikit-learn et scipy 
pip3 install scikit-learn scipy 

#Installation de scikit-mine
pip3 install scikit-mine

#installation de pyclustering
pip3 install pyclustering

#installation de pycspade
conda install conda-forge::pycspade

#INSTALLATION DE METIS sur UBUNTU/Linux
#Dans ton environnement de travail 
pip3 install metis

sudo apt-get update
sudo apt-get install libmetis-dev

sudo find / -name "libmetis.so*" 2>/dev/null

#Copier le chemin qui s'affiche sur la premier ligne de sortie de la precedente
#Exemple /usr/local/lib/libmetis.dylib 
#Ouvrez le fichier .bashrc de la racine avec la commande suivante 
nano ~/.bashrc 

#Coller la ligne suivante dans le fichier ~/.bashrc 
export METIS_DLL= [chemin copié precedement] 

#Redemarer votre terminal avec 
source ~/.bashrc 

#Bravo vous avez réussi

1- Clustering

1.1- Classification Assendante Hierarchique (CAH)

#Import Library 
from scipy.cluster.hierarchy import dendrogram, linkage
from sklearn.cluster import AgglomerativeClustering as agg
from sklearn.datasets import load_iris
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns

#Chargement des données
raw_data = load_iris()

X =raw_data['data']
Y = raw_data['target']
feature_names = raw_data['feature_names']
target_name = raw_data['target_names']

df = pd.DataFrame(data=X, columns=feature_names)
df['species']=Y
df.head()

def label_add(x):
    return target_name[x]

df['species'] = df['species'].apply(label_add)

#Prévisualisation des données
df.describe()
sns.pairplot(df, hue='species')

#Realisation de la CAH
cah = agg(n_clusters=3, metric="euclidean", linkage='ward') #Instancier la classe AgglomerativeClustering
cah.fit(X)
df["labels_pred"] = cah.labels_ #Prediction

#Visualisation de la CAH
plt.figure(figsize=[20,10])
link = linkage(X, method='ward')
dendrogram(link, color_threshold=8) #Il faut regarder l'axe des ordonnées pour définir une coupe "color_threshold"
plt.show()

1.2- KMEAN

#Import Library 
import numpy as np
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
import pandas as pd
import seaborn as sns

#Chargement des données
raw_data = load_iris()

X =raw_data['data']
Y = raw_data['target']
feature_names = raw_data['feature_names']
target_name = raw_data['target_names']

df = pd.DataFrame(data=X, columns=feature_names)
df['species']=Y
df.head()

def label_add(x):
    return target_name[x]

df['species'] = df['species'].apply(label_add)

#Prévisualisation des données
df.describe()
sns.pairplot(df, hue='species')

#Methode du coude
inertia = []
for k in range(1,11): #Ici le nombre max de cluster est 11
    model = KMeans(n_clusters=k, random_state=0)
    inertia.append(model.fit(X).inertia_)

#Visualisation de la méthode du coude
plt.plot(range(1,11), inertia)
plt.xticks(range(1,11))
plt.show()
best_k = xx #Definir ici le meilleur nombre de cluster en utilisant la méthode du coude
kmeans_model = KMeans(n_clusters=best_k) #Le nombre de cluster depend de vous 
kmeans_model.fit(X)
y_pred = kmeans_model.labels_

df["labels_pred"] = cah.labels_ #Prediction

1.3- DBSAN

#Import Library
from sklearn.cluster import DBSCAN
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.preprocessing import StandardScaler

#Load Data
FILEPATH = "some_file_dataset.csv"
SEP='\t'
dataset = pd.read_csv(FILEPATH, sep=SEP) #La valeur par defaut est de sep est la virgule
dataset = dataset.set_index('ID_Col_name') #Definir une colonne comme identifiant des exemples

#Previsualisation et resumé
dataset.head()
dataset.info()
dataset.describe()

#Encodage One Hot des variables catégorielles 
# NB : J'utilise la fonction onehot_encoder definie en bonus
cat_col_enc = onehot_encoder(dataset['cat_col_name'])
dataset = dataset.join(cat_col_enc)

#Standardisation des données
X = np.array(dataset)
scaler = StandardScaler() #Normalisation z-score (X-mean)/std
X_scale = scaler.fit_transform(X)

#Implémentation de DBSACN
model_dbscan = DBSCAN(eps=5, min_samples=10) #Les hyper paramettres eps et min_samples peuvent etre ajuster par l'étudiant
model_dbscan.fit(X_scale)
dataset['label_dbscan']=model_dbscan.labels_
sns.scatterplot(x=dataset["column_name1"], y=dataset['column_name2'],hue=dataset['label_dbscan'])

1.4- CLIQUE

lien vers les references du package pyclustering.
Dans ce package vous pouvez implémenter plus d’algorithme de clustering.

from pyclustering.cluster.clique import clique, clique_visualizer
from sklearn.datasets import load_iris
import numpy as np
import pandas as pd

raw_data = load_iris()

X =raw_data['data']
Y = raw_data['target']
feature_names = raw_data['feature_names']
target_name = raw_data['target_names']

df = pd.DataFrame(data=X, columns=feature_names)
df['species']=Y
df.head()

def label_add(x):
    return target_name[x]

df['species'] = df['species'].apply(label_add)

# create CLIQUE algorithm for processing
intervals = 5  # defines amount of cells in grid in each dimension
threshold = 0   # lets consider each point as non-outlier
#threshold = 5 means, block that contains 5 or less points is considered as a outlier as well as its points
clique_instance = clique(X, intervals, threshold)

# start clustering process and obtain results
clique_instance.process()
clusters = clique_instance.get_clusters()  # allocated clusters
noise = clique_instance.get_noise()     # points that are considered as outliers (in this example should be empty)
cells = clique_instance.get_cells()     # CLIQUE blocks that forms grid

print("Amount of clusters:", len(clusters))

y_pred = np.zeros(X.shape[0])

for i in range(len(clusters)):
    for j in range(len(clusters[i])):
        y_pred[clusters[i][j]] = i+1

if len(noise)>0:
    for i in noise:
            y_pred[i] = -1


# visualize clustering results in grid
## NB : Les grilles ici sont représentable pour les datasets à 3 variables
clique_visualizer.show_grid(cells, X)    # show grid that has been formed by the algorithm
clique_visualizer.show_clusters(X, clusters, noise)  # show clustering results

1.5- METIS

#Import Library
import pandas as pd
import networkx as nx
import matplotlib.pyplot as plt
from sklearn.metrics.pairwise import euclidean_distances
import metis
import numpy as np
import seaborn as sns
from sklearn.preprocessing import StandardScaler
from sklearn.datasets import load_iris

#Load Data
raw_data = load_iris()

X =raw_data['data']
Y = raw_data['target']
feature_names = raw_data['feature_names']
target_name = raw_data['target_names']

df = pd.DataFrame(data=X, columns=feature_names)
df.head()

#Création d'un graphe basé sur la dissimilarité
def create_graph_from_dataset(data, features, threshold=0.5):
    # Calcul des distances entre les clients
    X = np.array(data[features])
    scaler = StandardScaler()
    X = scaler.fit_transform(X)
    distances = euclidean_distances(X)
    G = nx.Graph()

    # Ajouter des nœuds (chaque client)
    for i in range(len(data)):
        G.add_node(i, label=f"Client {i}")

    # Ajouter des arêtes basées sur la dissimilarité
    for i in range(len(data)):
        for j in range(i + 1, len(data)):
            if distances[i][j] <= threshold:  # Ajouter une arête si la dissimilarité est en-dessous du seuil
                G.add_edge(i, j, weight=distances[i][j])
    
    return G, distances

threshold=4.5
G, dist = create_graph_from_dataset(df, feature_names, threshold)

#Partitionnement avec METIS
def metis_partition(G, k):
    # Assurez-vous d'avoir installé metis avec `pip install metis`

    # Convertir le graphe NetworkX au format METIS
    edgecuts, parts = metis.part_graph(G, nparts=k)

    # Regrouper les nœuds par partitions
    partitions = {i: [] for i in range(k)}
    for node, part in enumerate(parts):
        partitions[part].append(node)

    return partitions

partitions = metis_partition(G,k=3) #K est le nombre de cluster souhaité.

labels = np.ones(len(data), dtype=int)*(-1) #Les labels seront etiquete 0, 1, 2, 3, 4... Le -1 pour eviter les confusion et ressortir les bruits 
for key in partitions.keys():
    labels[partitions[key]]=key

1.6- Evaluation du clustering

from sklearn.metrics import silhouette_score, calinski_harabasz_score, rand_score

#Evaluation du clustering
silhouette = silhouette_score(X, model_labels) #Silhouette
print(f"Silhouette Score : {silhouette:.3f}")

#Note Silhouette 
# Silhouette au point i :
# s(i) = (b(i)-a(i))/max(b(i),a(i))
# Ou :
# - b(i) est la distance du point i au cluster le plus proche
# - a(i) est la distance du point i par rapport à son cluster
# s_final = (sum(s(i)))/k
# ou k est le nombre de cluster.
# NB : Pour voir chaque point a été bien classé. Des valeurs positive indique un bon clustering

calinski = calinski_harabasz_score(X, model_labels) #calinski et harabasz
print(f"Calinski & Harabasz Score : {calinski:.3f}")

#Note calinski et harabasz
#Aussi connu sous le nom de ratio de variance criterion, calinski et harabasz est le ratio entre l'inercie inter cluster (Ib) et la variance intra cluster (Iw).
#Etant donné que l'on veut minimiser l'inercie entra cluster, des valeurs élevées de ce score indiquons que le clustering s'est bien passé et les points sont très proches les uns des autres.

rand = rand_score(Y, model_labels) #Rand Score
print(f"Rand Score : {rand:.3f}")

#Note Rand Score
#Lorsqu'on dispose des informations sur les groupes, le score de rand permet d'évaluer la similarité entre les données prédite et les données réelles.

1.7- Bonus

#Lire un dataset csv avec pandas 
import pandas as pd

df = pd.read_csv("path_to_file/file_name.csv", sep=",", na_values="#", decimal=".") 
#Le separateur peut etre ";" ou "\t"
#na_values indique le caractere qui represente la valeur manquante 
#decimal indique le separateur decimal.

#Definir sa propore fonction onehot_encoder
def onehot_encoder(column):
    values = np.unique(column)
    result = {}
    for value in values :
        result[value]=[]
    for item in column:
        result[item].append(1)
        for value in values:
            if value!=item:
                result[value].append(0)

    return pd.DataFrame(result, index=column.index)

#reduction de dimensionallité 
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler

## Standardisation des données
X = np.array(dataset)
scaler = StandardScaler() #Normalisation z-score (X-mean)/std
X_scale = scaler.fit_transform(X)

## Implémentation avec PCA (Principal Component Analysis)
model_pca = PCA(n_components=nb_val_prop)
X_reduce = model_pca.fit_transform(X_scale)

2- Regles d’association

2.1- FP-Growth

import pandas as pd
from mlxtend.preprocessing import TransactionEncoder
from mlxtend.frequent_patterns import fpgrowth

# Exemple de transactions
dataset = [['Milk', 'Onion', 'Nutmeg', 'Kidney Beans', 'Eggs', 'Yogurt'],
           ['Dill', 'Onion', 'Nutmeg', 'Kidney Beans', 'Eggs', 'Yogurt'],
           ['Milk', 'Apple', 'Kidney Beans', 'Eggs'],
           ['Milk', 'Unicorn', 'Corn', 'Kidney Beans', 'Yogurt'],
           ['Corn', 'Onion', 'Onion', 'Kidney Beans', 'Ice cream', 'Eggs']]


# Conversion des transaction en On-Hot encoding labels
te = TransactionEncoder()
te_ary = te.fit(dataset).transform(dataset)
df = pd.DataFrame(te_ary, columns=te.columns_)


# utilisation de FP-Growth
frequent_itemsets = fpgrowth(df, min_support=0.6, use_colnames=True)
frequent_itemsets

2.2- APRIORI

import pandas as pd
from mlxtend.preprocessing import TransactionEncoder
from mlxtend.frequent_patterns import apriori

# Exemple de transactions
dataset = [['Milk', 'Onion', 'Nutmeg', 'Kidney Beans', 'Eggs', 'Yogurt'],
           ['Dill', 'Onion', 'Nutmeg', 'Kidney Beans', 'Eggs', 'Yogurt'],
           ['Milk', 'Apple', 'Kidney Beans', 'Eggs'],
           ['Milk', 'Unicorn', 'Corn', 'Kidney Beans', 'Yogurt'],
           ['Corn', 'Onion', 'Onion', 'Kidney Beans', 'Ice cream', 'Eggs']]

# Conversion des transaction en On-Hot encoding labels
te = TransactionEncoder()
te_ary = te.fit(dataset).transform(dataset)
df = pd.DataFrame(te_ary, columns=te.columns_)

# utilisation de Apriori
frequent_itemsets = apriori(df, min_support=0.6, use_colnames=True)
frequent_itemsets

2.3- LCM

#Import library
from skmine.itemsets import LCM
import pandas as pd

#Lecture d'un fichier de transaction
PATH="lastfm.csv"
SEP=","
MINSUP=100

#Fonction pour lire fichier de transaction
def read_transaction_file(path:str, sep:str):
    data = []
    try:
        file=open(path,"r")
        for line in file:
            itemset=line.split(sep)
            temp=[]
            for item in itemset:
                item=item.replace("\n","")
                if item!="":
                    temp.append(item)
            data.append(temp)
        file.close()
    except:
        print(f"Erreur de lecture du fichier {path}")
    return data

#Afficher quelques transactions
trans = read_transaction_file(PATH, SEP)
trans[:5]

#Nombre total de transaction
len(trans)

#Fonction pour réaliser LCM et stocker les resultats dans un DataFrame pandas
def make_LCM_ItemSet(data, n_jobs=20):
    lcm = LCM(min_supp=MINSUP, n_jobs=20)
    patterns = lcm.fit_transform(data)
    return patterns

#Fonction pour filtrer les itemset vides apres LCM
def filter_empty_itemset(data):
    result=[]
    for itemset ,support in zip(data["itemset"],data["support"]):
        if len(itemset)>1:
            result.append({"itemset" : itemset, "support" : support})
    return pd.DataFrame(result)

#Definir une liste de processus
process_LCM = [make_LCM_ItemSet, filter_empty_itemset]

#Appliquer LCM aux transactions
inputs = trans
for action in process_LCM:
    result = action(inputs)
    inputs = result

#Visualiser les premieres transactions
results_LCM.sort_values(by='support',ascending=False).head()

2.4- SPade

Voir l’implémentation sur la video youtude

#Import library
from pycspade.helpers import spade, print_result

result = spade(filename='file.txt', support = 0.3, parse=True)

print_result(result)

#NB : Les données contenues dans le fichier file.txt sont de la forme 
#  1 10 2 3 4
#  1 15 3 1 2 3
#  1 20 3 1 2 6
#  1 25 4 1 3 4 6
#  2 15 3 1 2 6
#  2 20 1 5
#  3 10 3 1 2 6
#  4 10 3 4 7 8
#  4 20 2 2 6
#  4 25 3 1 7 8

# La premiere colonne correspond à l'Id du client
# La deuxieme colonne correspond à la date
# La troiseme colonne correspond on nombre d'élement de l'itemset 2 = len([3,4])
# Les autres colonnes sont les elements de l'itemset

#On peut aussi l'utiliser de la maniere suivante pour le meme jeux de données 

data = [
[1, 10, [3, 4]],
[1,15,[1,2,3]],
[1,20,[1,2,6]],
[1,25,[1,3,4,6]],
[2,15,[1, 2, 6]],
[2, 20, [1, 5]],
[3, 10, [1, 2, 6]],
[4, 10, [4, 7, 8]],
[4, 20, [2, 6]],
[4, 25, [1, 7, 8]]
]
result = spade(data=data, support = 0.3, parse=True)

print_result(result)

2.5- Generer les regles

#Calculer le support d'un itemset
def support(itemset, transactions):
    return sum(1 for transaction in transactions if itemset.issubset(transaction))

#Calculer la confiance
def calculate_confidence(itemset, consequent, transactions):
    antecedent = itemset - consequent
    return support(itemset, transactions) / support(antecedent, transactions)

#Calculer le lift
def calculate_lift(itemset, consequent, transactions):
    antecedent = itemset - consequent
    return support(itemset, transactions) / (support(antecedent, transactions) * support(consequent, transactions))

#Generer les regles
def generate_rules(frequent_itemsets, transactions, min_confidence):
    rules = []
    for itemset in frequent_itemsets:
        for r in range(1, len(itemset)):
            for consequent in combinations(itemset, r):
                consequent_set = set(consequent)
                if consequent_set != itemset: 
                    confidence = calculate_confidence(itemset, consequent_set, transactions)
                    if confidence >= min_confidence:
                        lift = calculate_lift(itemset, consequent_set, transactions)
                        rules.append((itemset - consequent_set, consequent_set, confidence, lift))
    return rules

#Considerons cette variable contenant les resultats de Apriori, LCM, FP-Growth...
frequent_itemsets 

MINCONF = 0.3
rules = generate_rules(frequent_itemsets, all_trans, MINCONF)
rules = pd.DataFrame(rules, columns=["antecedent", "consequent", "confidence", "lift"])

3- Classification

3.1- SVC

from sklearn.svm import SVC
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from sklearn.datasets import load_iris

raw_data = load_iris()

X =raw_data['data']
Y = raw_data['target']

# Couper le jeux de données en train-test set
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# Creation d'un modèle SVC
model = SVC()

# Entrainer le modele 
model.fit(X_train, y_train)

# Prediction
y_pred = model.predict(X_test)

# Evaluation
accuracy = accuracy_score(y_test, y_pred)
print("Accuracy:", accuracy)