Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
ofilangi committed Dec 23, 2024
0 parents commit 468dfc7
Show file tree
Hide file tree
Showing 5 changed files with 272 additions and 0 deletions.
91 changes: 91 additions & 0 deletions Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# Analyse des Features avec Régression Linéaire, Quadratique et Cubique

Ce programme permet d'analyser des features issues de données expérimentales en utilisant des modèles de régression linéaire, quadratique et cubique pour prédire le cumul d'oxygène (cumul_O2) en tant que variable dépendante (y). Les analyses sont effectuées en quatre paquets distincts, chacun correspondant à un type de relation entre les features et le cumul_O2 :

- Modèle de Régression Linéaire (lm1) :
- Ce modèle est utilisé pour analyser les substrats, où l'abondance des substrats suit une tendance décroissante au fil du temps : abondance à t1 > t2 > t3.
- Modèle de Régression Linéaire (lm2) :
- Ce modèle s'applique aux produits, où l'abondance des produits montre une tendance croissante : abondance à t1 < t2 < t3.
- Modèle de Régression Quadratique (lm3) :
- Ce modèle est destiné aux features transitoires, représentant une relation non linéaire : abondance à t1 < t2 > t3, indiquant un pic d'abondance à t2 suivi d'une diminution.
- Modèle de Régression Cubique (lm4) :
- Ce modèle analyse les features recyclées, où l'abondance évolue selon un modèle plus complexe : abondance à t1 < t2 > t3 < t4, montrant des variations significatives au fil du temps.


## Installation
### Prérequis

```bash
python -m venv env
source env/bin/activate
pip install pandas statsmodels scikit-learn tqdm colorama tabulate
```

## Exécution

- data-test/data_M2PHENOX_AD_v2.xlsx.
- Le fichier doit contenir deux feuilles :
- sample_metadata : Contient les métadonnées des échantillons (par exemple, injectionOrder, vol_O2, etc.).
- AUC_data : Contient les features à analyser (par exemple, les noms des features et leurs valeurs).

```bash
python data_feature_classifier.py
```

## Résultats

- Un résumé des résultats affiché dans la console.
- Deux fichiers CSV générés dans le répertoire courant :

- Features_Results.csv
- Features_Results_Type.csv

### Affichage Console

- Le programme affiche un tableau récapitulatif des catégories de features analysées :

- Produits : Features identifiées comme ayant une pente linéaire positive significative.
- Substrats : Features avec une pente linéaire négative significative.
- Transitoires : Features présentant une relation quadratique significative.
- Recyclés : Features présentant une relation cubique significative.
- Non classés : Features ne correspondant à aucune des catégories ci-dessus.

- Chaque catégorie est divisée en deux colonnes :

- Éligible : Nombre total de features appartenant à cette catégorie.
- Exclusif (1 seule catégorie) : Nombre de features appartenant exclusivement à cette catégorie.

### Fichier CSV : Features_Results.csv

- Ce fichier contient les résultats détaillés pour chaque feature. Les colonnes incluent :

- Feature : Nom de la feature.
- P-value_linear, Pente_linear, R2_linear, etc. : Statistiques du modèle linéaire.
- P-value_quadratic, etc. : Statistiques du modèle quadratique.
- P-value_cubic, etc. : Statistiques du modèle cubique.
- Type : Classification de la feature (Produit, Substrat, Transitoire, ou Recyclé).

### Fichier CSV : Features_Results_Type.csv

- Ce fichier contient uniquement les types associés à chaque feature.

### Personnalisation

#### Ajout de Covariables :

Dans le script, vous pouvez ajouter ou retirer des covariables en modifiant la liste suivante :

```python
covariates = ['injectionOrder', 'vol_O2', 'num_prelevement'] + val_dummies_fix
```

#### Modification des Critères de Classification :
La logique pour classifier les features peut être modifiée dans la fonction suivante :

```python
def get_type_feature(res):
# Exemple de logique actuelle
if res['P-value_linear'] < 0.05 and res['Pente_linear'] > 0:
return 'Produit'
# Ajoutez vos propres conditions ici
```
1 change: 1 addition & 0 deletions data-test/.~lock.data_M2PHENOX_AD_v2.xlsx#
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
,ofilangi,REN-1349-A167,23.12.2024 08:48,file:///home/ofilangi/.config/libreoffice/4;
Binary file added data-test/analyse_data.ods
Binary file not shown.
Binary file added data-test/data_M2PHENOX_AD_v2.xlsx
Binary file not shown.
180 changes: 180 additions & 0 deletions data_feature_classifier.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
import pandas as pd
import statsmodels.api as sm
from sklearn.preprocessing import StandardScaler
from tqdm import tqdm
from tabulate import tabulate
from colorama import Fore, Style,init

# Initialiser Colorama
init(autoreset=True)

# Charger le fichier Excel
file_path = 'data-test/data_M2PHENOX_AD_v2.xlsx'

# Charger les données
sample_metadata = pd.read_excel(file_path, sheet_name='sample_metadata')
auc_data = pd.read_excel(file_path, sheet_name='AUC_data')

# Extraire les données nécessaires

features_names = auc_data['name']
cultivar_Y = sample_metadata['cultivar']
repetition_Y = sample_metadata['repeat']
unique_cultivars = cultivar_Y.unique()
unique_repetitions = repetition_Y.unique()

scaler = StandardScaler()

sample_metadata[['injectionOrder', 'vol_O2', 'num_prelevement','cumul_O2']] = scaler.fit_transform(
sample_metadata[['injectionOrder', 'vol_O2', 'num_prelevement','cumul_O2']]
)

y = sample_metadata['cumul_O2']

# Préparer les échantillons (X)
samples = auc_data.drop(columns=['name'])

samples_normalized = scaler.fit_transform(samples)

# Dictionnaire pour stocker les résultats par feature
results = []

# Modèle de régression linéaire avec pente positive
for index in tqdm(range(samples_normalized.shape[0]), desc="Analyse des lignes"):
# Extraire les données pour la feature actuelle
X_feature = samples_normalized[index]

# Créer le DataFrame avec les données nécessaires
data = pd.DataFrame(
{
'x': X_feature,
'y': sample_metadata['cumul_O2'],
# covariate
'injectionOrder' : sample_metadata['injectionOrder'],
#'vol_O2' : sample_metadata['vol_O2'],
#'num_prelevement' : sample_metadata['num_prelevement'],
# effet fixes
'batch' : sample_metadata['batch'],
'cultivar': [c.strip() for c in sample_metadata['cultivar']],
'repeat': sample_metadata['repeat'],
#'kinetic': sample_metadata['kinetic']
}
)

y = data['y']

# Ajouter des variables indicatrices (dummies)
data = pd.get_dummies(data, columns=['cultivar', 'repeat', 'batch'], drop_first=True)

# Utiliser filter pour obtenir les colonnes contenant les motifs souhaités
val_dummies_fix = data.filter(regex='^(cultivar_|repeat_|batch_)').columns.tolist()

data[val_dummies_fix] = data[val_dummies_fix].astype(int)

# Inclure injectionOrder comme covariable dans tous les modèles
# vol_O2 et num_prelevement sont des covariables potentielles =>
covariates = ['injectionOrder' ] + val_dummies_fix

# Modèle linéaire avec pente positive
X = data[['x'] + covariates]
X = sm.add_constant(X)

# Vérifier les valeurs manquantes avant d'ajuster le modèle
if X.isnull().any().any() or y.isnull().any():
print(f"Valeurs manquantes détectées à l'index {index}.")
continue # Passer à l'itération suivante si des valeurs manquantes sont trouvées

model_lin = sm.OLS(y, X).fit()
pvalue_lin = model_lin.pvalues.get('x', None)
slope_linear = model_lin.params['x']
# Coefficient de détermination
r_squared = model_lin.rsquared
# Statistique F
f_statistic = model_lin.fvalue
# Intervalle de confiance
conf_int = model_lin.conf_int().loc['x'].tolist()

# Ajouter le terme quadratique (x^2)
data['x_squared'] = data['x'] ** 2
X_quad = data[['x', 'x_squared'] + covariates]
X_quad = sm.add_constant(X_quad)

model_quad = sm.OLS(y, X_quad).fit()
pvalue_quad = model_quad.pvalues.get('x_squared', None)
slope_quad = model_quad.params['x_squared']
r_squared_quad = model_quad.rsquared
f_statistic_quad = model_quad.fvalue
conf_int_quad = model_quad.conf_int().loc['x_squared'].tolist()

# Ajouter le terme cubique (x^3)
data['x_cubed'] = data['x'] ** 3
X_cubic = data[['x', 'x_squared', 'x_cubed'] + covariates]
X_cubic = sm.add_constant(X_cubic)

model_cubic = sm.OLS(y, X_cubic).fit()
pvalue_cubic = model_cubic.pvalues.get('x_cubed', None)
slope_cubic = model_cubic.params['x_cubed']
r_squared_cubic = model_cubic.rsquared
f_statistic_cubic = model_cubic.fvalue
conf_int_cubic = model_cubic.conf_int().loc['x_cubed'].tolist()

# Stocker les résultats pour la feature actuelle
results.append({
'Feature': features_names[index],
'P-value_linear': pvalue_lin,
'Pente_linear': slope_linear,
'R2_linear': r_squared,
'F-statistic_linear': f_statistic,
'Confidence_interval_linear': conf_int,
'P-value_quadratic': pvalue_quad,
'Pente_quadratic': slope_quad,
'R2_quadratic': r_squared_quad,
'F-statistic_quadratic': f_statistic_quad,
'Confidence_interval_quadratic': conf_int_quad,
'P-value_cubic': pvalue_cubic,
'Pente_cubic': slope_cubic,
'R2_cubic': r_squared_cubic,
'F-statistic_cubic': f_statistic_cubic,
})

def get_type_feature(res):
out =""
if res['P-value_linear'] < 0.05 and res['Pente_linear']>0:
out += 'Produit,'
if res['P-value_linear'] < 0.05 and res['Pente_linear']<0:
out += 'Substrat,'
if res['P-value_quadratic'] < 0.05:
out += 'Transitoire,'
if res['P-value_cubic'] < 0.05:
out += 'Recyclé,'

return out[:-1]

# Sauvegarder dans un fichier CSV avec formatage des p-values
results = [{**x, 'Type': get_type_feature(x)} for x in results]
pd.DataFrame(results).to_csv('Features_Results.csv', index=False, float_format="%.5f")
pd.DataFrame({'Res': [x['Type'] for x in results]}).to_csv('Features_Results_Type.csv', index=False)

# Filtrer les résultats par catégorie
produits = [x['Feature'] for x in results if x['P-value_linear'] < 0.05 and x['Pente_linear'] > 0]
produits_exc = [x['Feature'] for x in results if x['P-value_linear'] < 0.05 and x['Pente_linear'] > 0 and x['P-value_quadratic'] >= 0.05 and x['P-value_cubic'] >= 0.05]
substrats = [x['Feature'] for x in results if x['P-value_linear'] < 0.05 and x['Pente_linear'] < 0]
substrats_exc = [x['Feature'] for x in results if x['P-value_linear'] < 0.05 and x['Pente_linear'] < 0 and x['P-value_quadratic'] >= 0.05 and x['P-value_cubic'] >= 0.05]
transitoires = [x['Feature'] for x in results if x['P-value_quadratic'] < 0.05]
transitoires_exc = [x['Feature'] for x in results if x['P-value_quadratic'] < 0.05 and x['P-value_linear'] >= 0.05 and x['P-value_cubic'] >= 0.05]
recycles = [x['Feature'] for x in results if x['P-value_cubic'] < 0.05]
recycles_exc = [x['Feature'] for x in results if x['P-value_cubic'] < 0.05 and x['P-value_linear'] >= 0.05 and x['P-value_quadratic'] >= 0.05]
non_classes = [x['Feature'] for x in results if x['P-value_cubic'] >= 0.05 and x['P-value_quadratic'] >= 0.05 and x['P-value_linear'] >= 0.05]

# Créer un tableau des résultats
table_data = [
[f"{Fore.GREEN}Produits{Style.RESET_ALL}", len(produits), len(produits_exc)],
[f"{Fore.RED}Substrats{Style.RESET_ALL}", len(substrats), len(substrats_exc)],
[f"{Fore.YELLOW}Transitoires{Style.RESET_ALL}", len(transitoires),len(transitoires_exc)],
[f"{Fore.BLUE}Recyclés{Style.RESET_ALL}", len(recycles), len(recycles_exc)],
[f"{Fore.WHITE}Non classés{Style.RESET_ALL}", len(non_classes),len(results)-len(produits_exc)-len(substrats_exc)-len(transitoires_exc)-len(recycles_exc)],
]

# Afficher le tableau
print(f"\n{Style.BRIGHT}{Fore.CYAN}Résumé des Résultats :\n")
print(tabulate(table_data, headers=["Catégorie", "Éligible", "Exclusif (1 seule catégorie)"], tablefmt="grid"))

0 comments on commit 468dfc7

Please sign in to comment.