"""
Module: RNN et LSTM
Catégorie : Deep learning
Difficulté : Avancé

Généré depuis la plateforme ML Formation
"""

# Imports
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, mean_squared_error, r2_score

# Charger le dataset
df = pd.read_csv('stock_prices.csv')

# Explorer les données
# Type: Code exécutable
print("=" * 70)
print("       EXPLORATION DE LA SERIE TEMPORELLE")
print("=" * 70)

print("""
Les RNN/LSTM sont specialises pour les DONNEES SEQUENTIELLES.
Nous allons travailler avec une serie temporelle de prix boursiers.

OBJECTIF:
  Apprendre a predire le prix de demain a partir de l'historique recent.

POURQUOI LES RNN?
  • Les prix d'aujourd'hui dependent des prix passes
  • Il y a une MEMOIRE dans les donnees
  • Un reseau classique ignorerait cette dependance temporelle
""")

print("\n" + "=" * 70)
print("1. APERCU DES DONNEES")
print("=" * 70)
display(df.head(15), title="Serie Temporelle (Prix Boursiers)")

print("""
STRUCTURE:
  • 'day': jour (index temporel)
  • 'price': prix de l'action a ce jour
""")

print("\n" + "=" * 70)
print("2. STATISTIQUES DE LA SERIE")
print("=" * 70)

prices = df['price'].values
n_days = len(prices)

print(f"""
PERIODE:
  • Premier jour: {df['day'].min()}
  • Dernier jour: {df['day'].max()}
  • Nombre total de jours: {n_days}

STATISTIQUES DES PRIX:
  • Prix minimum: {prices.min():.2f}
  • Prix maximum: {prices.max():.2f}
  • Prix moyen: {prices.mean():.2f}
  • Ecart-type: {prices.std():.2f}
  • Amplitude: {prices.max() - prices.min():.2f}
""")

print("\n" + "=" * 70)
print("3. ANALYSE DE LA VOLATILITE")
print("=" * 70)

# Calculer les rendements journaliers
returns = np.diff(prices) / prices[:-1] * 100

print(f"""
RENDEMENTS JOURNALIERS:
  • Moyenne: {returns.mean():+.2f}%
  • Ecart-type (volatilite): {returns.std():.2f}%
  • Min: {returns.min():+.2f}% (pire journee)
  • Max: {returns.max():+.2f}% (meilleure journee)

INTERPRETATION:
  Une volatilite de {returns.std():.2f}% signifie que le prix varie
  typiquement de +/-{returns.std():.2f}% d'un jour a l'autre.
""")

print("\n" + "=" * 70)
print("4. VISUALISATION")
print("=" * 70)

fig, axes = plt.subplots(2, 1, figsize=(14, 8))

# Serie temporelle
axes[0].plot(df['day'], df['price'], color='#9B7AC4', linewidth=2)
axes[0].fill_between(df['day'], df['price'], alpha=0.3, color='#9B7AC4')
axes[0].set_xlabel('Jour', fontsize=11)
axes[0].set_ylabel('Prix', fontsize=11)
axes[0].set_title('Evolution du Prix Boursier', fontsize=13, fontweight='bold')
axes[0].grid(True, alpha=0.3)

# Marquer min et max
min_idx = prices.argmin()
max_idx = prices.argmax()
axes[0].scatter([df['day'].iloc[min_idx]], [prices.min()], s=100, c='#e74c3c', zorder=5, label=f'Min: {prices.min():.2f}')
axes[0].scatter([df['day'].iloc[max_idx]], [prices.max()], s=100, c='#27ae60', zorder=5, label=f'Max: {prices.max():.2f}')
axes[0].legend()

# Distribution des rendements
axes[1].hist(returns, bins=20, color='#F7E64D', edgecolor='black', alpha=0.7)
axes[1].axvline(x=0, color='#e74c3c', linestyle='--', linewidth=2, label='0%')
axes[1].axvline(x=returns.mean(), color='#9B7AC4', linestyle='-', linewidth=2, label=f'Moyenne: {returns.mean():.2f}%')
axes[1].set_xlabel('Rendement journalier (%)', fontsize=11)
axes[1].set_ylabel('Frequence', fontsize=11)
axes[1].set_title('Distribution des Rendements Journaliers', fontsize=13, fontweight='bold')
axes[1].legend()
axes[1].grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

print("""
OBSERVATIONS:
  • La serie presente des tendances et des fluctuations
  • Les rendements sont approximativement centres autour de 0
  • Ces patterns temporels sont ce que le RNN va apprendre!
""")

print("\n" + "=" * 70)
print("              EXPLORATION TERMINEE!")
print("=" * 70)


# Préparer les séquences
# Type: Code exécutable
print("=" * 70)
print("       PREPARATION DES SEQUENCES POUR LE RNN")
print("=" * 70)

print("""
Pour entrainer un RNN, on transforme la serie temporelle en SEQUENCES.
Chaque sequence est une "fenetre glissante" sur les donnees.

PRINCIPE:
  Input: [prix_t-4, prix_t-3, prix_t-2, prix_t-1, prix_t]
  Output: prix_t+1 (le jour suivant)

Le RNN apprend: "Etant donne les 5 derniers jours, predire demain"
""")

print("\n" + "=" * 70)
print("1. FONCTION DE CREATION DE SEQUENCES")
print("=" * 70)

def create_sequences(data, seq_length):
    """Cree des paires (X, y) pour l'entrainement du RNN."""
    X, y = [], []
    for i in range(len(data) - seq_length):
        X.append(data[i:i+seq_length])
        y.append(data[i+seq_length])
    return np.array(X), np.array(y)

print("""
FONCTION create_sequences():
  • data: la serie temporelle complete
  • seq_length: nombre de pas de temps en entree
  • Retourne: X (sequences), y (cibles)

COMMENT CA MARCHE:
  Pour chaque position i dans les donnees:
    - X[i] = [data[i], data[i+1], ..., data[i+seq_length-1]]
    - y[i] = data[i+seq_length]
""")

print("\n" + "=" * 70)
print("2. APPLICATION AUX DONNEES")
print("=" * 70)

prices = df['price'].values
seq_length = 5  # Utiliser 5 jours pour predire le suivant

X, y = create_sequences(prices, seq_length)

print(f"""
PARAMETRES:
  • Longueur de sequence: {seq_length} jours
  • Donnees totales: {len(prices)} jours

RESULTAT:
  • Nombre de sequences: {len(X)}
  • Shape de X: {X.shape} → ({len(X)} sequences, {seq_length} jours chacune)
  • Shape de y: {y.shape} → ({len(y)} valeurs cibles)

POURQUOI {len(X)} sequences?
  {len(prices)} - {seq_length} = {len(X)}
  (on perd {seq_length} points pour creer la premiere sequence complete)
""")

print("\n" + "=" * 70)
print("3. EXEMPLES DE SEQUENCES")
print("=" * 70)

print("""
Visualisons quelques exemples pour comprendre la structure:
""")

print("-" * 65)
print(f"{'Sequence':<10} {'Entree (5 derniers jours)':<40} {'Cible'}")
print("-" * 65)

for i in range(5):
    input_str = "[" + ", ".join([f"{x:.1f}" for x in X[i]]) + "]"
    print(f"{i:<10} {input_str:<40} {y[i]:.2f}")

print("-" * 65)

print("""
LECTURE:
  • Sequence 0: jours 1-5 → predire jour 6
  • Sequence 1: jours 2-6 → predire jour 7
  • etc.

La fenetre "glisse" d'un jour a chaque sequence.
""")

print("\n" + "=" * 70)
print("4. VISUALISATION D'UNE SEQUENCE")
print("=" * 70)

fig, ax = plt.subplots(figsize=(12, 5))

# Choisir une sequence
idx = 10

# Tracer l'historique
x_hist = range(idx, idx + seq_length)
ax.plot(x_hist, X[idx], 'o-', color='#9B7AC4', linewidth=2, markersize=10,
        label=f'Entree ({seq_length} jours)')

# Tracer la cible
ax.plot(idx + seq_length, y[idx], 's', color='#F7E64D', markersize=15,
        label='Cible a predire')

# Tracer le contexte complet
ax.plot(range(len(prices)), prices, '--', color='gray', alpha=0.3, label='Serie complete')

ax.axvline(x=idx + seq_length - 0.5, color='#e74c3c', linestyle=':', linewidth=2, alpha=0.7)
ax.text(idx + seq_length - 0.3, prices.max(), 'Frontiere\nprediction', fontsize=10, color='#e74c3c')

ax.set_xlabel('Jour', fontsize=11)
ax.set_ylabel('Prix', fontsize=11)
ax.set_title(f'Exemple de Sequence #{idx}', fontsize=13, fontweight='bold')
ax.legend(loc='best')
ax.grid(True, alpha=0.3)
ax.set_xlim(idx - 2, idx + seq_length + 3)

plt.tight_layout()
plt.show()

print(f"""
CETTE SEQUENCE:
  • Entree: prix des jours {idx} a {idx + seq_length - 1}
  • Cible: prix du jour {idx + seq_length}

Le RNN va apprendre a predire le point jaune
a partir des points violets!
""")

print("\n" + "=" * 70)
print("              SEQUENCES PREPAREES!")
print("=" * 70)


# ----------------------------------------------------------------------
# La suite de ce module demande un compte.
# Les cellules de code restantes ne sont pas dans ce fichier.
# ----------------------------------------------------------------------
