<jupyter_start><jupyter_text>Analytique de l'apprentissage Extraction de relations, corrélations et de motifs Carnet web IPython (Jupyter Notebook) en complément du **«Chapitre 6 – Vers une IENA pilotée par les données » ** du livre : **« Vers une nouvelle ingénierie des environnements numériques d’apprentissage »**, auteurs du chapitre, <NAME> & <NAME>, éditeurs: <NAME>, <NAME>, licence code source libre MIT  Relation entre l'organisation du temps vs les notes et la certificationNous allons étudier la corrélation entre l’organisation du temps d’étude, les notes obtenues et la réussite du cours par l'obtention d'une attestation.L’analytique d’apprentissage consiste souvent en la vérification d’hypothèses. Par exemple, dans Ulibre, nous avons cherché à savoir s’il y avait une relation (une corrélation) entre l’organisation du temps d’étude et l’obtention de la certification (i.e. la complétion du cours).Le coefficient de corrélation linéaire, noté r, quantifie la force du lien linéaire entre les deux attributs d’une distribution.<jupyter_code># -*- coding: utf-8 -*-

import pandas as pd
import numpy as np
from matplotlib import pyplot as plt
path_to_datafile = "AA_data/"
DF_id_notes_attestation = pd.read_csv(path_to_datafile+"CTF_id_notes_attestation.csv", 
                                      na_values=[""], 
                                      index_col=False)
DF_id_notes_attestation.head()
DF_id_notes_attestation.rename(columns={'student_id':'etudiant_id','grade':'note'}, inplace=True)
DF_id_notes_attestation.head()
DF_id_notes_attestation.groupby('attestation').size()
DF_id_notes_attestation['attestation'] = DF_id_notes_attestation['attestation'].replace({'generating': 1, 'notpassing': 0})
DF_id_notes_attestation.head()
DF_id_horaire = pd.read_csv(path_to_datafile+"CTF_final_Q11_rep.csv", 
                            na_values=["***",None],
                            usecols=['student_id','time_organization'],
                            index_col=False)
pd.options.display.max_colwidth = 1000
DF_id_horaire.head()
DF_id_horaire.rename(columns={'student_id':"etudiant_id",'time_organization':"horaire"}, inplace=True)
DF_id_horaire.dropna(subset=['horaire'], inplace = True)
DF_id_horaire.head()
DF_id_horaire['horaire'] = DF_id_horaire['horaire'].apply(lambda horaire: (horaire.split('*')[0]))
DF_id_horaire.groupby('horaire').size()
DF_id_horaire['horaire'] = DF_id_horaire['horaire'].apply(lambda horaire: np.nan if len(str(horaire)) < 1 else horaire )
DF_id_horaire.groupby('horaire').size()
DF_fusion = pd.merge(left=DF_id_notes_attestation,right=DF_id_horaire,
                     on='etudiant_id', how='left')
DF_fusion.groupby('horaire').size()
DF_fusion.head()
DF_fusion.dropna(subset=['horaire'], inplace = True)
DF_fusion.groupby('horaire').size()
len(DF_fusion)
DF_fusion.head()
for index,row in DF_fusion.iterrows():
    print(row['horaire'])
DF_fusion = pd.get_dummies(DF_fusion, prefix =['horaire'] )
DF_fusion.head()
colonnes =['etudiant_id','note','attestation',
           'horaire_A des moments tres variables',
           'horaire_Plage de temps reservee avec quelques exceptions', 
           'horaire_Plage de temps strictement reservee'
          ]
DF_fusion.rename(columns={colonnes[3]:"+var",
                          colonnes[4]:"flex",
                          colonnes[5]:"fixe",
                         },
                 inplace=True)
DF_fusion.head()
DF_fusion_note = DF_fusion.drop(['etudiant_id','attestation'],axis=1)<jupyter_output><empty_output><jupyter_text>Corrélation de la matrice fusionnée<jupyter_code>DF_fusion_note.corr()
import matplotlib.pyplot as plt
%matplotlib inline

alpha = ['note', '+var', 'flex', 'fixe']

fig = plt.figure(figsize=(8,8))
ax = fig.add_subplot(111)
cax = ax.matshow(DF_fusion_note.corr(), cmap='bwr', interpolation='nearest')
fig.colorbar(cax)

ax.set_xticklabels(['']+alpha)
ax.set_yticklabels(['']+alpha)

plt.show()<jupyter_output><ipython-input-29-38884823c611>:11: UserWarning: FixedFormatter should only be used together with FixedLocator
  ax.set_xticklabels(['']+alpha)
<ipython-input-29-38884823c611>:12: UserWarning: FixedFormatter should only be used together with FixedLocator
  ax.set_yticklabels(['']+alpha)<jupyter_text>Utilisation de la bibliothèque scipy<jupyter_code>from scipy import stats

notes = DF_fusion_note['note'].values
for i, horaire in zip([1,2,3],['+var', 'flex', 'fixe']):
    horaire_flexible = DF_fusion_note.iloc[: , [i]].values
    # .ravel() return a contiguous flattened array
    r, valeur_p = stats.pearsonr(notes.ravel(), horaire_flexible.ravel())
    print(horaire,'r:',r, ', valeur p:',valeur_p)<jupyter_output>+var r: -0.044652142622459166 , valeur p: 0.5738175189524354
flex r: 0.15673167035237448 , valeur p: 0.04708947831740449
fixe r: -0.14067127799208326 , valeur p: 0.07509694872811744<jupyter_text>Nous observons une faible corrélation à 0.16 entre la note obtenue et un horaire de travail flexible (flex) avec des plages de temps réservées et quelques exceptions. Par contre on observe une effet quasi nul (-0.04) si l'horaire est très variable (+var) et un léger effet négatif (corrélation négative à -0.14) dans le cas d'un horaire strict (fixe).<jupyter_code>DF_fusion_attestation = DF_fusion.drop(['etudiant_id','note'],axis=1)
DF_fusion_attestation.corr()
import matplotlib.pyplot as plt
%matplotlib inline

alpha = ['att', '+var', 'flex', 'fixe']

fig = plt.figure(figsize=(8,8))
ax = fig.add_subplot(111)
cax = ax.matshow(DF_fusion_attestation.corr(), cmap='bwr', interpolation='nearest')
fig.colorbar(cax)

ax.set_xticklabels(['']+alpha)
ax.set_yticklabels(['']+alpha)

plt.show()<jupyter_output><ipython-input-33-4e5331bfa6af>:11: UserWarning: FixedFormatter should only be used together with FixedLocator
  ax.set_xticklabels(['']+alpha)
<ipython-input-33-4e5331bfa6af>:12: UserWarning: FixedFormatter should only be used together with FixedLocator
  ax.set_yticklabels(['']+alpha)<jupyter_text>Utilisation de la bibliothèque scipy<jupyter_code>from scipy import stats

notes = DF_fusion_attestation['attestation'].values
for i, horaire in zip([1,2,3],['+var', 'flex', 'fixe']):
    horaire_flexible = DF_fusion_attestation.iloc[: , [i]].values
    # .ravel() return a contiguous flattened array
    r, valeur_p = stats.pearsonr(notes.ravel(), horaire_flexible.ravel())
    print(horaire,'r:',r, ', valeur p:',valeur_p)<jupyter_output>+var r: -0.10591226609886824 , valeur p: 0.18116751461877723
flex r: 0.10820716519580295 , valeur p: 0.171841021863228
fixe r: -0.06286185570937121 , valeur p: 0.42824614431914865<jupyter_text>Nous observons une faible corrélation à 0.11 entre l'obtention d'une attestation et un horaire de travail flexible avec des plages de temps réservées et quelques exceptions (flex). Par contre on observe un léger effet négatif (corrélation négative à -0.11) pour un horaire strict (fixe) et une effet presque nul (-0.06) si l'horaire est très variable (+var).  Information mutuelleL'information mutuelle révèle une association, que l'association soit linéaire (ce que mesure la corrélation) ou non, alors que la corrélation peut être nulle et que les variables peuvent encore être stochastiquement dépendantes.<jupyter_code># Code from: Entropy in machine learning - may 06 2019 - <NAME>
# https://gist.github.com/rlangone/71d93b68d38a89c6722f414fc96f4792

# Import libraries
import pandas as pd
import numpy as np
from scipy.stats import iqr
from numpy import histogram2d
from sklearn.metrics import mutual_info_score

# Define mutual information function
def minfo(x, y):
    # Compute mutual information between x and y
    bins_x = max(2,int(2*iqr(x)*len(x)**-(1/3))) # use Freedman-Diaconis's Rule of thumb
    bins_y = max(2,int(2*iqr(y)*len(y)**-(1/3)))
    c_xy = histogram2d(x, y, [bins_x,bins_y])[0]
    mi = mutual_info_score(None, None, contingency=c_xy)
    return mi

# Build MI matrix
num_features = DF_fusion_attestation.shape[1]
MI_matrix = np.zeros((num_features,num_features))
for i,col_i in enumerate(DF_fusion_attestation):
    for j,col_j in enumerate(DF_fusion_attestation):
        MI_matrix[i,j] = minfo(DF_fusion_attestation[col_i],DF_fusion_attestation[col_j])
MI_df = pd.DataFrame(MI_matrix,columns = DF_fusion_attestation.columns, index = DF_fusion_attestation.columns)
print(MI_df)

# Ajustements pour faire ressortir les contrastes
MI_df['attestation'][0] = 1.0
MI_df['attestation'][1] *= 100
MI_df['attestation'][2] *= 100
MI_df['attestation'][3] *= 100
MI_df['+var'][0] *= 100
MI_df['+var'][1] = 1.0
MI_df['flex'][0] *= 100
MI_df['flex'][2] = 1.0
MI_df['fixe'][0] *= 100
MI_df['fixe'][3] = 1.0
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
%matplotlib inline
import numpy as np

# Une rustine un peu compliquée pour faire correspondre 0.0 à la couleur blanche
# https://stackoverflow.com/questions/20144529/shifted-colorbar-matplotlib/20146989#20146989
from matplotlib.colors import Normalize

class MidpointNormalize(Normalize):

    def __init__(self, vmin=None, vmax=None, midpoint=None, clip=False):
        self.midpoint = midpoint
        Normalize.__init__(self, vmin, vmax, clip)

    def __call__(self, value, clip=None):
        x, y = [self.vmin, self.midpoint, self.vmax], [0, 0.5, 1]
        return np.ma.masked_array(np.interp(value, x, y))

norm = MidpointNormalize(midpoint=0)
    
alpha = ["attestation","+var","flex","fixe"]

fig = plt.figure(figsize=(7,7))
ax = fig.add_subplot(111)
cax = ax.matshow(MI_df, norm=norm, cmap='bwr', interpolation='nearest')
fig.colorbar(cax)

# 2 lignes suivantes, une rustine pour éviter un avertissement
# UserWarning: FixedFormatter should only be used together with FixedLocator
# https://stackoverflow.com/questions/63723514/userwarning-fixedformatter-should-only-be-used-together-with-fixedlocator
ticks_loc = ax.get_xticks().tolist()[:-1]
ax.xaxis.tick_bottom()
ax.xaxis.set_major_locator(mticker.FixedLocator(ticks_loc))
# Afficher les noms des attributs selon l'axe horizontal
ax.set_xticklabels(['']+alpha,rotation=60)

# 2 lignes suivantes, une rustine pour éviter un avertissement (voir plus haut)
ticks_loc = ax.get_yticks().tolist()[:-1]
ax.yaxis.set_major_locator(mticker.FixedLocator(ticks_loc))
# Afficher les noms des attributs selon l'axe vertical
ax.set_yticklabels(['']+alpha)

plt.title("Matrice d'information Mutuelle",fontsize=20)
plt.show()<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.1247597078046905, 'fraction_numerical': 0.04267589388696655, 'mean_word_length': 5.407019704433497, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 30, 'https://': 3, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '6', 'dir': 'jupyter-structured-clean-dedup', 'id': '219992', 'license': 'Apache-2.0', 'n_tokens_mistral': 4037, 'n_tokens_neox': 3671, 'n_words': 841, 'path': 'AA-Extraction_relations_correlations_motifs.ipynb', 'repo_name': 'ClaudeCoulombe/Analytique_Apprentissage', 'size': '10450'}