0% ont trouvé ce document utile (0 vote)
1 vues15 pages

Code 1

Ce document présente une méthode d'analyse MCR-ALS pour séparer les spectres d'absorption de nanoparticules Co3O4 et du colorant RB5, en utilisant des fichiers Excel pour les données expérimentales. Il décrit les étapes de prétraitement, d'initialisation, d'optimisation et de reconstruction des données, ainsi que l'analyse des résultats obtenus, y compris les pics d'absorption et la distribution du colorant. Enfin, les résultats sont visualisés et exportés dans un fichier CSV.

Transféré par

rania mahdi
Copyright
© All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
1 vues15 pages

Code 1

Ce document présente une méthode d'analyse MCR-ALS pour séparer les spectres d'absorption de nanoparticules Co3O4 et du colorant RB5, en utilisant des fichiers Excel pour les données expérimentales. Il décrit les étapes de prétraitement, d'initialisation, d'optimisation et de reconstruction des données, ainsi que l'analyse des résultats obtenus, y compris les pics d'absorption et la distribution du colorant. Enfin, les résultats sont visualisés et exportés dans un fichier CSV.

Transféré par

rania mahdi
Copyright
© All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

# -*- coding: utf-8 -*-

"""
MCR-ALS pour analyse UV-Visible (Co3O4 + RB5)
Avec séparation du colorant libre et adsorbé - VERSION CORRIGÉE
"""

# Installation des packages nécessaires


!pip install pandas numpy scikit-learn matplotlib openpyxl scipy

# Import des bibliothèques


import pandas as pd
import numpy as np
import [Link] as plt
from [Link] import lstsq
from [Link] import nnls, minimize, curve_fit
from [Link] import PCA
from [Link] import savgol_filter
from [Link] import UnivariateSpline
from [Link] import files
import warnings
[Link]('ignore')

print("=" * 80)
print("MCR-ALS pour analyse UV-Visible (Nanoparticules Co3O4 + Colorant
RB5)")
print("Avec séparation colorant libre vs adsorbé")
print("=" * 80)

#
=======================================================================
=====
# 1. UPLOAD DES FICHIERS EXCEL
#
=======================================================================
=====

print("\n" + "=" * 60)


print("ÉTAPE 1: TÉLÉVERSEMENT DES FICHIERS")
print("=" * 60)

print("\nVeuillez sélectionner vos 3 fichiers Excel:")


print("1. Spectre des nanoparticules seules (Co3O4)")
print("2. Spectre du colorant RB5 seul")
print("3. Spectre du mélange (Nanoparticules + RB5)")

uploaded_files = {}

for i, nom_fichier in enumerate(["Nanoparticules", "RB5", "Melange"],


1):
print(f"\n--- Téléversement fichier {i}/3: {nom_fichier} ---")
uploaded = [Link]()
filename = list([Link]())[0]
uploaded_files[nom_fichier] = filename
print(f"✓ Fichier chargé: {filename}")

print("\n✓ TOUS LES FICHIERS ONT ÉTÉ CHARGÉS")

#
=======================================================================
=====
# 2. LECTURE DES DONNÉES
#
=======================================================================
=====

def load_uv_data(filename):
try:
df = pd.read_excel(filename, header=None)
wavelength = [Link][:, 0].[Link](float)
absorbance = [Link][:, 1].[Link](float)
return wavelength, absorbance
except:
df = pd.read_excel(filename)
wavelength = [Link][:, 0].[Link](float)
absorbance = [Link][:, 1].[Link](float)
return wavelength, absorbance

wl_np, abs_np = load_uv_data(uploaded_files['Nanoparticules'])


wl_rb5, abs_rb5 = load_uv_data(uploaded_files['RB5'])
wl_mix, abs_mix = load_uv_data(uploaded_files['Melange'])

# Interpolation
wl_min = max(wl_np[0], wl_rb5[0], wl_mix[0])
wl_max = min(wl_np[-1], wl_rb5[-1], wl_mix[-1])
wl_common = [Link](wl_min, wl_max, 500)

abs_np_interp = [Link](wl_common, wl_np, abs_np)


abs_rb5_interp = [Link](wl_common, wl_rb5, abs_rb5)
abs_mix_interp = [Link](wl_common, wl_mix, abs_mix)

#
=======================================================================
=====
# 3. PRÉTRAITEMENT
#
=======================================================================
=====
def normalize_spectrum(absorbance):
return (absorbance - [Link](absorbance)) / ([Link](absorbance) -
[Link](absorbance) + 1e-10)

abs_np_norm = normalize_spectrum(abs_np_interp)
abs_rb5_norm = normalize_spectrum(abs_rb5_interp)
abs_mix_norm = normalize_spectrum(abs_mix_interp)

print("\n✓ Prétraitement appliqué")

#
=======================================================================
=====
# 4. CLASSE MCR-ALS CORRIGÉE
#
=======================================================================
=====

class MCRALS_Adsorption:
"""MCR-ALS avec séparation du colorant libre et adsorbé - VERSION
CORRIGÉE"""

def __init__(self, D, n_components=3, max_iter=500, tol=1e-8):


self.D = D
self.n_components = n_components
self.max_iter = max_iter
[Link] = tol
self.C = None
[Link] = None
self.loss_history = []

def initialize_with_pure_spectra(self, pure_spectra_list):


"""Initialisation avec spectres purs connus"""
n_samples, n_wavelengths = [Link]
[Link] = [Link]((self.n_components, n_wavelengths))

for i in range(min(len(pure_spectra_list), self.n_components)):


[Link][i, :] = pure_spectra_list[i]

for i in range(len(pure_spectra_list), self.n_components):


[Link][i, :] = [Link](n_wavelengths)

self.C = [Link]([Link].T, self.D.T, rcond=None)[0].T


self._apply_constraints()

def _apply_constraints(self):
"""Application des contraintes de non-négativité"""
self.C = [Link](self.C, 0)
[Link] = [Link]([Link], 0)
# Normalisation
norms = [Link]([Link], axis=1, keepdims=True)
norms[norms == 0] = 1
[Link] = [Link] / norms
self.C = self.C * norms.T

def fit(self):
"""Optimisation ALS"""
print(f"Optimisation avec {self.n_components} composants...")

for iteration in range(self.max_iter):


# Mise à jour des concentrations
self.C = [Link]([Link].T, self.D.T,
rcond=None)[0].T
self._apply_constraints()

# Mise à jour des spectres


[Link] = [Link](self.C, self.D, rcond=None)[0]
self._apply_constraints()

# Calcul de la perte
D_reconstructed = [Link](self.C, [Link])
loss = [Link]((self.D - D_reconstructed)**2) /
[Link](self.D**2)
self.loss_history.append(loss)

if len(self.loss_history) > 1:
if abs(self.loss_history[-2] - loss) < [Link]:
print(f"✓ Convergence à l'itération {iteration}")
break

if iteration % 50 == 0 and iteration > 0:


print(f" Itération {iteration}: Loss = {loss:.2e}")

return self.C, [Link]

def reconstruct(self):
"""Reconstruction des données"""
return [Link](self.C, [Link])

#
=======================================================================
=====
# 5. DÉCONVOLUTION POUR OBTENIR LE SPECTRE DU COLORANT ADSORBÉ
#
=======================================================================
=====
print("\n" + "=" * 60)
print("ÉTAPE: DÉCONVOLUTION LIBRE/ADSORBÉ")
print("=" * 60)

# Matrice des données


D = [Link]([abs_np_norm, abs_rb5_norm, abs_mix_norm])

# Première estimation avec 2 composants pour trouver le résidu


mcr2 = MCRALS_Adsorption(D, n_components=2)
mcr2.initialize_with_pure_spectra([abs_np_norm, abs_rb5_norm])
C2, ST2 = [Link]()
D_reconstructed2 = [Link]()

# Le résidu (3ème composant) est attribué au colorant adsorbé


residual = D[2, :] - D_reconstructed2[2, :]
spectrum_adsorbed = [Link](residual, 0)
if [Link](spectrum_adsorbed) > 0:
spectrum_adsorbed = spectrum_adsorbed / [Link](spectrum_adsorbed)

print("✓ Spectre du colorant adsorbé estimé")

#
=======================================================================
=====
# 6. MCR-ALS FINAL AVEC 3 COMPOSANTS
#
=======================================================================
=====

print("\n" + "=" * 60)


print("ÉTAPE: MCR-ALS AVEC 3 COMPOSANTS")
print("=" * 60)

mcr3 = MCRALS_Adsorption(D, n_components=3)


mcr3.initialize_with_pure_spectra([abs_np_norm, abs_rb5_norm,
spectrum_adsorbed])
C3, ST3 = [Link]()
D_reconstructed3 = [Link]()

#
=======================================================================
=====
# 7. ANALYSE DES RÉSULTATS
#
=======================================================================
=====

# Calcul du shift spectral


peak_free_idx = [Link](ST3[1, :])
peak_ads_idx = [Link](ST3[2, :])
peak_free = wl_common[peak_free_idx]
peak_ads = wl_common[peak_ads_idx]
shift = peak_ads - peak_free

# Distribution du colorant dans le mélange


total_rb5 = C3[2, 1] + C3[2, 2]
if total_rb5 > 0:
pct_free = (C3[2, 1] / total_rb5) * 100
pct_ads = (C3[2, 2] / total_rb5) * 100
else:
pct_free = pct_ads = 50

print(f"\n📊 RÉSULTATS QUANTITATIFS:")


print(f" • Pic RB5 libre: {peak_free:.1f} nm")
print(f" • Pic RB5 adsorbé: {peak_ads:.1f} nm")
print(f" • Shift spectral: {shift:+.1f} nm")
print(f" • RB5 libre dans mélange: {pct_free:.1f}%")
print(f" • RB5 adsorbé dans mélange: {pct_ads:.1f}%")

#
=======================================================================
=====
# 8. VISUALISATIONS
#
=======================================================================
=====

# Figure 1: Spectres purs (NP, RB5 libre, RB5 adsorbé)


fig, ax = [Link](figsize=(12, 6))
[Link](wl_common, ST3[0, :], 'b-', linewidth=2, label='Nanoparticules
Co₃O₄')
[Link](wl_common, ST3[1, :], 'g-', linewidth=2, label='Colorant RB5
(libre)')
[Link](wl_common, ST3[2, :], 'r-', linewidth=2, label='Colorant RB5
(adsorbé)')
ax.set_xlabel('Longueur d\'onde (nm)', fontsize=12)
ax.set_ylabel('Absorbance normalisée', fontsize=12)
ax.set_title('Spectres purs résolus par MCR-ALS', fontsize=14)
[Link]()
[Link](True, alpha=0.3)
plt.tight_layout()
[Link]()

# Figure 2: Comparaison libre vs adsorbé


fig, ax = [Link](figsize=(12, 6))
[Link](wl_common, ST3[1, :], 'g-', linewidth=2, label='RB5 libre',
alpha=0.8)
[Link](wl_common, ST3[2, :], 'r-', linewidth=2, label='RB5 adsorbé',
alpha=0.8)
if abs(shift) > 2:
[Link](peak_free-10, peak_ads+10, alpha=0.2, color='yellow',
label=f'Shift = {shift:.1f} nm')
ax.set_xlabel('Longueur d\'onde (nm)', fontsize=12)
ax.set_ylabel('Absorbance normalisée', fontsize=12)
ax.set_title('Comparaison: Colorant RB5 libre vs adsorbé', fontsize=14)
[Link]()
[Link](True, alpha=0.3)
plt.tight_layout()
[Link]()

# Figure 3: Déconvolution du mélange


fig, axes = [Link](1, 3, figsize=(15, 5))

# Contribution NP
axes[0].plot(wl_common, C3[2, 0] * ST3[0, :], 'b-', linewidth=2)
axes[0].set_title(f'Nanoparticules (conc. = {C3[2, 0]:.3f})',
fontsize=12)
axes[0].set_xlabel('Longueur d\'onde (nm)')
axes[0].grid(True, alpha=0.3)

# Contribution RB5 libre


axes[1].plot(wl_common, C3[2, 1] * ST3[1, :], 'g-', linewidth=2)
axes[1].set_title(f'RB5 libre (conc. = {C3[2, 1]:.3f})', fontsize=12)
axes[1].set_xlabel('Longueur d\'onde (nm)')
axes[1].grid(True, alpha=0.3)

# Contribution RB5 adsorbé


axes[2].plot(wl_common, C3[2, 2] * ST3[2, :], 'r-', linewidth=2)
axes[2].set_title(f'RB5 adsorbé (conc. = {C3[2, 2]:.3f})', fontsize=12)
axes[2].set_xlabel('Longueur d\'onde (nm)')
axes[2].grid(True, alpha=0.3)

[Link]('Contributions individuelles au spectre du mélange',


fontsize=14)
plt.tight_layout()
[Link]()

# Figure 4: Qualité de reconstruction


fig, ax = [Link](figsize=(12, 6))
[Link](wl_common, D[2, :], 'b-', linewidth=2, label='Mélange
expérimental')
[Link](wl_common, D_reconstructed3[2, :], 'r--', linewidth=2,
label='Reconstruit MCR-ALS')
ax.set_xlabel('Longueur d\'onde (nm)', fontsize=12)
ax.set_ylabel('Absorbance normalisée', fontsize=12)
ax.set_title('Qualité de la reconstruction du mélange', fontsize=14)
[Link]()
[Link](True, alpha=0.3)
plt.tight_layout()
[Link]()

# Figure 5: Résidus
fig, ax = [Link](figsize=(12, 5))
residuals = D[2, :] - D_reconstructed3[2, :]
[Link](wl_common, residuals, 'purple', linewidth=1.5)
[Link](y=0, color='k', linestyle='-', linewidth=0.5)
ax.fill_between(wl_common, 0, residuals, alpha=0.3, color='purple')
ax.set_xlabel('Longueur d\'onde (nm)', fontsize=12)
ax.set_ylabel('Résidus', fontsize=12)
ax.set_title(f'Résidus de reconstruction (RMSD =
{[Link]([Link](residuals**2)):.4f})', fontsize=14)
[Link](True, alpha=0.3)
plt.tight_layout()
[Link]()

# Figure 6: Courbe de convergence


fig, ax = [Link](figsize=(10, 5))
[Link](mcr3.loss_history, 'b-', linewidth=2)
ax.set_xlabel('Itération', fontsize=12)
ax.set_ylabel('Erreur relative (RSS)', fontsize=12)
ax.set_title('Convergence de MCR-ALS', fontsize=14)
ax.set_yscale('log')
[Link](True, alpha=0.3)
plt.tight_layout()
[Link]()

#
=======================================================================
=====
# 9. EXPORT DES RÉSULTATS
#
=======================================================================
=====

print("\n" + "=" * 60)


print("EXPORT DES RÉSULTATS")
print("=" * 60)

results_df = [Link]()
results_df['Longueur_donde_nm'] = wl_common
results_df['Nanoparticules'] = ST3[0, :]
results_df['RB5_libre'] = ST3[1, :]
results_df['RB5_adsorbe'] = ST3[2, :]
results_df['Melange_experimental'] = D[2, :]
results_df['Melange_reconstruit'] = D_reconstructed3[2, :]
results_df['Residus'] = residuals

csv_filename = 'resultats_MCR_ALS_complet.csv'
results_df.to_csv(csv_filename, index=False)
print(f"✓ Résultats sauvegardés dans '{csv_filename}'")
[Link](csv_filename)

# Rapport texte
report = f"""
=======================================================================
=========
RAPPORT MCR-ALS - ADSORPTION RB5 SUR NANOPARTICULES Co₃O₄
=======================================================================
=========

📊 RÉSULTATS SPECTROSCOPIQUES:
• Longueur d'onde max RB5 libre: {peak_free:.1f} nm
• Longueur d'onde max RB5 adsorbé: {peak_ads:.1f} nm
• Shift spectral: {shift:+.1f} nm

📈 DISTRIBUTION DU COLORANT DANS LE MÉLANGE:


• RB5 libre: {pct_free:.1f}%
• RB5 adsorbé: {pct_ads:.1f}%
• Rapport adsorbé/libre: {pct_ads/pct_free:.2f}

🎯 QUALITÉ DU MODÈLE:
• R² de reconstruction: {1 -
[Link](residuals**2)/[Link](D[2,:]**2):.4f}
• RMSD: {[Link]([Link](residuals**2)):.4f}
• Itérations MCR-ALS: {len(mcr3.loss_history)}

=======================================================================
=========
"""

with open('rapport_adsorption.txt', 'w') as f:


[Link](report)
print("✓ Rapport sauvegardé")
[Link]('rapport_adsorption.txt')

print("\n" + "=" * 60)


print("✓ ANALYSE TERMINÉE AVEC SUCCÈS")
print("=" * 60)

print("\n📁 FICHIERS PRODUITS:")


print(" • resultats_MCR_ALS_complet.csv (données complètes)")
print(" • rapport_adsorption.txt (résumé)")
print("\n✅ Vous avez maintenant les spectres du colorant LIBRE et
ADSORBÉ!")
Requirement already satisfied: pandas in /usr/local/lib/python3.12/dist-
packages (2.2.2)
Requirement already satisfied: numpy in /usr/local/lib/python3.12/dist-
packages (2.0.2)
Requirement already satisfied: scikit-learn in
/usr/local/lib/python3.12/dist-packages (1.6.1)
Requirement already satisfied: matplotlib in
/usr/local/lib/python3.12/dist-packages (3.10.0)
Requirement already satisfied: openpyxl in /usr/local/lib/python3.12/dist-
packages (3.1.5)
Requirement already satisfied: scipy in /usr/local/lib/python3.12/dist-
packages (1.16.3)
Requirement already satisfied: python-dateutil>=2.8.2 in
/usr/local/lib/python3.12/dist-packages (from pandas) (2.9.0.post0)
Requirement already satisfied: pytz>=2020.1 in
/usr/local/lib/python3.12/dist-packages (from pandas) (2025.2)
Requirement already satisfied: tzdata>=2022.7 in
/usr/local/lib/python3.12/dist-packages (from pandas) (2026.1)
Requirement already satisfied: joblib>=1.2.0 in
/usr/local/lib/python3.12/dist-packages (from scikit-learn) (1.5.3)
Requirement already satisfied: threadpoolctl>=3.1.0 in
/usr/local/lib/python3.12/dist-packages (from scikit-learn) (3.6.0)
Requirement already satisfied: contourpy>=1.0.1 in
/usr/local/lib/python3.12/dist-packages (from matplotlib) (1.3.3)
Requirement already satisfied: cycler>=0.10 in
/usr/local/lib/python3.12/dist-packages (from matplotlib) (0.12.1)
Requirement already satisfied: fonttools>=4.22.0 in
/usr/local/lib/python3.12/dist-packages (from matplotlib) (4.62.1)
Requirement already satisfied: kiwisolver>=1.3.1 in
/usr/local/lib/python3.12/dist-packages (from matplotlib) (1.5.0)
Requirement already satisfied: packaging>=20.0 in
/usr/local/lib/python3.12/dist-packages (from matplotlib) (26.1)
Requirement already satisfied: pillow>=8 in /usr/local/lib/python3.12/dist-
packages (from matplotlib) (11.3.0)
Requirement already satisfied: pyparsing>=2.3.1 in
/usr/local/lib/python3.12/dist-packages (from matplotlib) (3.3.2)
Requirement already satisfied: et-xmlfile in
/usr/local/lib/python3.12/dist-packages (from openpyxl) (2.0.0)
Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.12/dist-
packages (from python-dateutil>=2.8.2->pandas) (1.17.0)
===========================================================================
=====
MCR-ALS pour analyse UV-Visible (Nanoparticules Co3O4 + Colorant RB5)
Avec séparation colorant libre vs adsorbé
===========================================================================
=====

============================================================
ÉTAPE 1: TÉLÉVERSEMENT DES FICHIERS
============================================================

Veuillez sélectionner vos 3 fichiers Excel:


1. Spectre des nanoparticules seules (Co3O4)
2. Spectre du colorant RB5 seul
3. Spectre du mélange (Nanoparticules + RB5)

--- Téléversement fichier 1/3: Nanoparticules ---


• nanoparticule [Link](application/[Link]-
[Link]) - 41012 bytes, last modified: n/a - 100% done
Saving nanoparticule [Link] to nanoparticule seul (1).xlsx
✓ Fichier chargé: nanoparticule seul (1).xlsx
--- Téléversement fichier 2/3: RB5 ---
• colorant [Link](application/[Link])
- 39422 bytes, last modified: n/a - 100% done
Saving colorant [Link] to colorant seule (1).xlsx
✓ Fichier chargé: colorant seule (1).xlsx

--- Téléversement fichier 3/3: Melange ---


• mélange nanoparticule + [Link](application/[Link]-
[Link]) - 46346 bytes, last modified: n/a - 100% done
Saving mélange nanoparticule + [Link] to mélange nanoparticule +
colorant (1).xlsx
✓ Fichier chargé: mélange nanoparticule + colorant (1).xlsx

✓ TOUS LES FICHIERS ONT ÉTÉ CHARGÉS

✓ Prétraitement appliqué

============================================================
ÉTAPE: DÉCONVOLUTION LIBRE/ADSORBÉ
============================================================
Optimisation avec 2 composants...
✓ Convergence à l'itération 2
✓ Spectre du colorant adsorbé estimé

============================================================
ÉTAPE: MCR-ALS AVEC 3 COMPOSANTS
============================================================
Optimisation avec 3 composants...
✓ Convergence à l'itération 16

RÉSULTATS QUANTITATIFS:
• Pic RB5 libre: 601.6 nm
• Pic RB5 adsorbé: 225.2 nm
• Shift spectral: -376.4 nm
• RB5 libre dans mélange: 82.4%
• RB5 adsorbé dans mélange: 17.6%
============================================================
EXPORT DES RÉSULTATS
============================================================
✓ Résultats sauvegardés dans 'resultats_MCR_ALS_complet.csv'
✓ Rapport sauvegardé
============================================================
✓ ANALYSE TERMINÉE AVEC SUCCÈS
============================================================

FICHIERS PRODUITS:
• resultats_MCR_ALS_complet.csv (données complètes)
• rapport_adsorption.txt (résumé)

✅ Vous avez maintenant les spectres du colorant LIBRE et ADSORBÉ!

Vous aimerez peut-être aussi