File size: 8,162 Bytes
15bcfd9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10d269d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15bcfd9
2d93c49
 
 
 
 
 
 
 
10d269d
 
15bcfd9
 
 
10d269d
15bcfd9
 
10d269d
 
 
15bcfd9
10d269d
 
15bcfd9
 
7b5300c
 
 
 
 
 
 
15bcfd9
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
import streamlit as st
import seaborn as sns
import pandas as pd
import numpy as np
from sklearn.linear_model import LinearRegression
import itertools
import matplotlib.pyplot as plt

# ------------------------------
# Configuration Streamlit
# ------------------------------
st.set_page_config(layout="wide")

st.sidebar.title("Exploration des corrélations partielles")
st.sidebar.markdown("---")
st.sidebar.header("Configuration")

# Sélection dataset
available_datasets = []

for name in sns.get_dataset_names():
    try:
        df_test = sns.load_dataset(name).dropna()
        numeric_cols = df_test.select_dtypes(include=['float64', 'int64']).columns
        if len(numeric_cols) >= 3:
            available_datasets.append(name)
    except:
        pass

dataset_name = st.sidebar.selectbox("Sélectionnez un jeu de données Seaborn :", available_datasets)

df = sns.load_dataset(dataset_name).dropna()

# Colonnes numériques uniquement
df_numeric = df.select_dtypes(include=['float64', 'int64'])

# Choix Pearson / Spearman
corr_type = st.sidebar.radio(
    "Type de corrélation :",
    ["Pearson", "Spearman"],
    index=0
)

# Choix variables à éliminer
all_vars = list(df_numeric.columns)
control_vars = st.sidebar.multiselect(
    "Variables dont vous voulez éliminer l'influence :",
    all_vars
)

# Variables restantes
vars_remaining = [v for v in all_vars if v not in control_vars]

if len(vars_remaining) < 2:
    st.error("Il faut au moins deux variables restantes pour afficher une corrélation.")
    st.stop()

# ------------------------------
# Prétraitement Spearman (si sélectionné)
# ------------------------------
if corr_type == "Spearman":
    df_for_corr = df_numeric.rank()
else:
    df_for_corr = df_numeric.copy()

# ------------------------------
# Matrice brute
# ------------------------------
corr_raw = df_for_corr[vars_remaining].corr(method=("spearman" if corr_type=="Spearman" else "pearson"))

# ------------------------------
# Fonction corrélation partielle
# ------------------------------
def partial_corr(df, controls):
    vars_to_corr = [v for v in df.columns if v not in controls]

    partial_corr_matrix = pd.DataFrame(
        np.zeros((len(vars_to_corr), len(vars_to_corr))),
        columns=vars_to_corr,
        index=vars_to_corr
    )

    for x, y in itertools.product(vars_to_corr, repeat=2):
        if x == y:
            partial_corr_matrix.loc[x, y] = 1.0
            continue

        X = df[[x]]
        Y = df[[y]]

        if len(controls) > 0:
            Z = df[controls]

            model_x = LinearRegression().fit(Z, X)
            X_res = X - model_x.predict(Z)

            model_y = LinearRegression().fit(Z, Y)
            Y_res = Y - model_y.predict(Z)

            r = np.corrcoef(X_res.T, Y_res.T)[0, 1]
        else:
            r = df[[x, y]].corr(method=("spearman" if corr_type=="Spearman" else "pearson")).iloc[0, 1]

        partial_corr_matrix.loc[x, y] = r

    return partial_corr_matrix

# ------------------------------
# Matrice partielle
# ------------------------------
corr_partial = partial_corr(df_for_corr, control_vars)

# ------------------------------
# Calcul des différences
# ------------------------------
# Extraire uniquement les paires uniques (triangle supérieur sans diagonale)
diff_data = []
n = len(vars_remaining)
for i in range(n):
    for j in range(i+1, n):
        var1 = vars_remaining[i]
        var2 = vars_remaining[j]
        raw_val = corr_raw.loc[var1, var2]
        partial_val = corr_partial.loc[var1, var2]
        diff = partial_val - raw_val
        diff_data.append({
            'Paire': f"{var1} - {var2}",
            'Différence': diff
        })

df_diff = pd.DataFrame(diff_data).sort_values('Différence', ascending=True)

# ------------------------------
# ONGLET PRINCIPAL
# ------------------------------
tab1, tab2 = st.tabs(["📊 Matrices", "📄 Données"])

# ----------- TAB 1 -----------
with tab1:
    col1, col2 = st.columns(2)

    # Heatmap corrélation brute (triangle inférieur)
    # with col1:
    #     st.write(f"**Corrélation brute ({corr_type})**")
    #     mask_raw = np.triu(np.ones_like(corr_raw, dtype=bool))
    #     fig, ax = plt.subplots(figsize=(5.5, 4))
    #     sns.heatmap(corr_raw, annot=True, cmap="coolwarm", center=0, ax=ax, 
    #                 mask=mask_raw, square=True, vmin=-1, vmax=1, cbar_kws={'shrink': 0.75}, annot_kws={'size': 9})
    #     plt.tight_layout()
    #     st.pyplot(fig)

    # # Heatmap corrélation partielle (triangle inférieur)
    # with col2:
    #     st.write(f"**Corrélation partielle ({corr_type})**")
    #     mask_partial = np.triu(np.ones_like(corr_partial, dtype=bool))
    #     fig2, ax2 = plt.subplots(figsize=(5.5, 4))
    #     sns.heatmap(corr_partial, annot=True, cmap="coolwarm", center=0, ax=ax2,
    #                 mask=mask_partial, square=True, vmin=-1, vmax=1, cbar_kws={'shrink': 0.75}, annot_kws={'size': 9})
    #     plt.tight_layout()
    #     st.pyplot(fig2)

    # # Graphique des différences (pleine largeur en dessous)
    # st.write("**Différences (Partielle - Brute)**")
    # fig3, ax3 = plt.subplots(figsize=(12, 2.2))
    # colors = ['#d7191c' if x < 0 else '#2b83ba' for x in df_diff['Différence']]
    # ax3.barh(df_diff['Paire'], df_diff['Différence'], color=colors, height=0.55)
    # ax3.axvline(0, color='black', linewidth=0.8, linestyle='--')
    # ax3.set_xlabel('Différence de corrélation', fontsize=8)
    # ax3.tick_params(axis='both', labelsize=7.5)
    # ax3.grid(axis='x', alpha=0.3, linestyle=':')
    # plt.tight_layout()
    # st.pyplot(fig3)

    with col1:
        st.write(f"**Corrélation brute ({corr_type})**")
        mask_raw = np.triu(np.ones_like(corr_raw, dtype=bool))
        fig, ax = plt.subplots(figsize=(5, 4)) # Diminuez un peu la taille pour la place
        sns.heatmap(corr_raw, annot=True, cmap="coolwarm", center=0, ax=ax, 
                    mask=mask_raw, square=True, vmin=-1, vmax=1, cbar_kws={'shrink': 0.75}, annot_kws={'size': 9})
        ax.tick_params(axis='both', labelsize=8) # Ajout pour fixer la taille de la police
        # RETRAIT de plt.tight_layout()
        st.pyplot(fig, use_container_width=False) # **IMPORTANT : Forcer la taille fixe**

    # --- COLONNE 2 : CORRÉLATION PARTIELLE ---
    with col2:
        st.write(f"**Corrélation partielle ({corr_type})**")
        mask_partial = np.triu(np.ones_like(corr_partial, dtype=bool))
        fig2, ax2 = plt.subplots(figsize=(5, 4)) # Même taille que fig
        sns.heatmap(corr_partial, annot=True, cmap="coolwarm", center=0, ax=ax2,
                    mask=mask_partial, square=True, vmin=-1, vmax=1, cbar_kws={'shrink': 0.75}, annot_kws={'size': 9})
        ax2.tick_params(axis='both', labelsize=8) # Ajout pour fixer la taille de la police
        # RETRAIT de plt.tight_layout()
        st.pyplot(fig2, use_container_width=False) # **IMPORTANT : Forcer la taille fixe**

    # --- GRAPHIQUE DES DIFFÉRENCES (Celui-ci est souvent moins problématique) ---
    # Vous pouvez garder plt.tight_layout() ici ou le remplacer par ax3.set_... si le problème persiste.
    st.write("**Différences (Partielle - Brute)**")
    fig3, ax3 = plt.subplots(figsize=(12, 2.2))
    colors = ['#d7191c' if x < 0 else '#2b83ba' for x in df_diff['Différence']]
    ax3.barh(df_diff['Paire'], df_diff['Différence'], color=colors, height=0.55)
    ax3.axvline(0, color='black', linewidth=0.8, linestyle='--')
    ax3.set_xlabel('Différence de corrélation', fontsize=8)
    ax3.tick_params(axis='both', labelsize=7.5)
    ax3.grid(axis='x', alpha=0.3, linestyle=':')
    plt.tight_layout()
    st.pyplot(fig3)
    
    st.caption("🔵 Corrélation renforcée après contrôle | 🔴 Corrélation affaiblie après contrôle")

# ----------- TAB 2 -----------
with tab2:
    st.write("**Aperçu des données (10 premières lignes)**")
    st.dataframe(df_numeric.head(10))