maalouf imad commited on
Commit
47f1575
·
verified ·
1 Parent(s): a266016
cours-pdf.html ADDED
@@ -0,0 +1,915 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="fr">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>Cours de Machine Learning - ML Academy</title>
6
+ <link rel="preconnect" href="https://fonts.googleapis.com">
7
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
8
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
9
+ <script>
10
+ window.MathJax = {
11
+ tex: { inlineMath: [['$', '$']], displayMath: [['$$', '$$']] },
12
+ options: { skipHtmlTags: ['script','noscript','style','textarea','pre'] }
13
+ };
14
+ </script>
15
+ <script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
16
+ <style>
17
+ /* Reset */
18
+ * { box-sizing: border-box; margin: 0; padding: 0; }
19
+ body { margin: 0; padding: 0; font-family: 'Inter', -apple-system, sans-serif; }
20
+
21
+ /* Page setup */
22
+ @page {
23
+ size: A4;
24
+ margin: 2.5cm 2cm;
25
+ @bottom-center {
26
+ content: "Imad Maalouf — ML Academy";
27
+ font-size: 9pt;
28
+ color: #666;
29
+ }
30
+ @bottom-right {
31
+ content: counter(page);
32
+ font-size: 9pt;
33
+ color: #666;
34
+ }
35
+ }
36
+
37
+ @page :first {
38
+ margin: 0;
39
+ @bottom-center { content: none; }
40
+ @bottom-right { content: none; }
41
+ }
42
+
43
+ /* Cover page */
44
+ .cover {
45
+ width: 210mm;
46
+ height: 297mm;
47
+ margin: 0;
48
+ position: relative;
49
+ overflow: hidden;
50
+ page-break-after: always;
51
+ background: linear-gradient(135deg, #0f0f1a 0%, #1a1a2e 50%, #252542 100%);
52
+ }
53
+
54
+ .cover-decoration {
55
+ position: absolute;
56
+ top: 0;
57
+ left: 0;
58
+ right: 0;
59
+ bottom: 0;
60
+ overflow: hidden;
61
+ }
62
+
63
+ .cover-circle {
64
+ position: absolute;
65
+ border-radius: 50%;
66
+ opacity: 0.1;
67
+ }
68
+
69
+ .cover-circle-1 {
70
+ width: 400px;
71
+ height: 400px;
72
+ background: #6366f1;
73
+ top: -100px;
74
+ right: -100px;
75
+ }
76
+
77
+ .cover-circle-2 {
78
+ width: 300px;
79
+ height: 300px;
80
+ background: #06b6d4;
81
+ bottom: 10%;
82
+ left: -80px;
83
+ }
84
+
85
+ .cover-circle-3 {
86
+ width: 200px;
87
+ height: 200px;
88
+ background: #f59e0b;
89
+ top: 40%;
90
+ right: 15%;
91
+ }
92
+
93
+ .cover-content {
94
+ position: absolute;
95
+ top: 50%;
96
+ left: 50%;
97
+ transform: translate(-50%, -50%);
98
+ text-align: center;
99
+ width: 80%;
100
+ z-index: 1;
101
+ }
102
+
103
+ .cover-badge {
104
+ display: inline-block;
105
+ padding: 8px 16px;
106
+ background: rgba(99, 102, 241, 0.2);
107
+ border: 1px solid rgba(99, 102, 241, 0.4);
108
+ border-radius: 20px;
109
+ font-family: 'JetBrains Mono', monospace;
110
+ font-size: 10pt;
111
+ color: #818cf8;
112
+ text-transform: uppercase;
113
+ letter-spacing: 2px;
114
+ margin-bottom: 30px;
115
+ }
116
+
117
+ .cover-title {
118
+ font-size: 36pt;
119
+ font-weight: 700;
120
+ color: #f8fafc;
121
+ margin-bottom: 15px;
122
+ line-height: 1.2;
123
+ }
124
+
125
+ .cover-subtitle {
126
+ font-size: 14pt;
127
+ color: #94a3b8;
128
+ margin-bottom: 60px;
129
+ }
130
+
131
+ .cover-author {
132
+ font-size: 12pt;
133
+ color: #818cf8;
134
+ margin-bottom: 10px;
135
+ }
136
+
137
+ .cover-info {
138
+ font-size: 10pt;
139
+ color: #64748b;
140
+ }
141
+
142
+ /* Content styles */
143
+ .content {
144
+ padding: 0;
145
+ }
146
+
147
+ h1 {
148
+ font-size: 20pt;
149
+ font-weight: 700;
150
+ color: #1a1a2e;
151
+ margin: 30pt 0 15pt 0;
152
+ padding-bottom: 8pt;
153
+ border-bottom: 2px solid #6366f1;
154
+ page-break-after: avoid;
155
+ }
156
+
157
+ h2 {
158
+ font-size: 14pt;
159
+ font-weight: 600;
160
+ color: #1a1a2e;
161
+ margin: 20pt 0 10pt 0;
162
+ page-break-after: avoid;
163
+ }
164
+
165
+ h3 {
166
+ font-size: 12pt;
167
+ font-weight: 600;
168
+ color: #333;
169
+ margin: 15pt 0 8pt 0;
170
+ page-break-after: avoid;
171
+ }
172
+
173
+ p {
174
+ font-size: 11pt;
175
+ line-height: 1.7;
176
+ color: #333;
177
+ margin-bottom: 10pt;
178
+ text-align: justify;
179
+ text-align-last: left;
180
+ }
181
+
182
+ strong {
183
+ font-weight: 600;
184
+ color: #1a1a2e;
185
+ }
186
+
187
+ em {
188
+ font-style: italic;
189
+ color: #444;
190
+ }
191
+
192
+ /* Info box */
193
+ .info-box {
194
+ background: #f8f9fa;
195
+ border-left: 4px solid #6366f1;
196
+ padding: 12pt 15pt;
197
+ margin: 15pt 0;
198
+ page-break-inside: avoid;
199
+ }
200
+
201
+ .info-box-title {
202
+ font-weight: 600;
203
+ color: #6366f1;
204
+ margin-bottom: 5pt;
205
+ font-size: 10pt;
206
+ }
207
+
208
+ .info-box p {
209
+ margin: 0;
210
+ font-size: 10pt;
211
+ }
212
+
213
+ /* Equation block */
214
+ .equation-block {
215
+ background: #f8f9fa;
216
+ border: 1px solid #e2e8f0;
217
+ border-left: 3px solid #6366f1;
218
+ border-radius: 4px;
219
+ padding: 15pt;
220
+ margin: 15pt 0;
221
+ text-align: center;
222
+ page-break-inside: avoid;
223
+ }
224
+
225
+ .equation-label {
226
+ display: block;
227
+ font-family: 'JetBrains Mono', monospace;
228
+ font-size: 8pt;
229
+ color: #64748b;
230
+ text-align: right;
231
+ margin-top: 8pt;
232
+ }
233
+
234
+ /* Cards grid */
235
+ .cards-grid {
236
+ display: grid;
237
+ grid-template-columns: repeat(3, 1fr);
238
+ gap: 12pt;
239
+ margin: 15pt 0;
240
+ }
241
+
242
+ .card {
243
+ background: #f8f9fa;
244
+ border: 1px solid #e2e8f0;
245
+ border-radius: 6px;
246
+ padding: 12pt;
247
+ page-break-inside: avoid;
248
+ }
249
+
250
+ .card-icon {
251
+ width: 32px;
252
+ height: 32px;
253
+ background: linear-gradient(135deg, #6366f1, #06b6d4);
254
+ border-radius: 6px;
255
+ display: flex;
256
+ align-items: center;
257
+ justify-content: center;
258
+ font-size: 12pt;
259
+ font-weight: 700;
260
+ color: white;
261
+ margin-bottom: 8pt;
262
+ }
263
+
264
+ .card-title {
265
+ font-size: 10pt;
266
+ font-weight: 600;
267
+ color: #1a1a2e;
268
+ margin-bottom: 5pt;
269
+ }
270
+
271
+ .card-text {
272
+ font-size: 9pt;
273
+ color: #555;
274
+ line-height: 1.5;
275
+ }
276
+
277
+ /* Pipeline */
278
+ .pipeline {
279
+ display: flex;
280
+ gap: 8pt;
281
+ margin: 15pt 0;
282
+ padding: 12pt;
283
+ background: #f8f9fa;
284
+ border: 1px solid #e2e8f0;
285
+ border-radius: 6px;
286
+ }
287
+
288
+ .pipeline-step {
289
+ flex: 1;
290
+ text-align: center;
291
+ position: relative;
292
+ }
293
+
294
+ .pipeline-step:not(:last-child)::after {
295
+ content: '->';
296
+ position: absolute;
297
+ right: -10pt;
298
+ top: 50%;
299
+ transform: translateY(-50%);
300
+ color: #6366f1;
301
+ font-family: 'JetBrains Mono', monospace;
302
+ font-size: 10pt;
303
+ }
304
+
305
+ .pipeline-num {
306
+ width: 24pt;
307
+ height: 24pt;
308
+ background: linear-gradient(135deg, #6366f1, #06b6d4);
309
+ border-radius: 50%;
310
+ display: flex;
311
+ align-items: center;
312
+ justify-content: center;
313
+ font-family: 'JetBrains Mono', monospace;
314
+ font-size: 9pt;
315
+ font-weight: 700;
316
+ color: white;
317
+ margin: 0 auto 5pt;
318
+ }
319
+
320
+ .pipeline-label {
321
+ font-size: 8pt;
322
+ font-weight: 600;
323
+ color: #1a1a2e;
324
+ }
325
+
326
+ .pipeline-desc {
327
+ font-size: 7pt;
328
+ color: #64748b;
329
+ }
330
+
331
+ /* Comparison */
332
+ .comparison-grid {
333
+ display: grid;
334
+ grid-template-columns: 1fr 1fr;
335
+ gap: 12pt;
336
+ margin: 15pt 0;
337
+ }
338
+
339
+ .comparison-box {
340
+ background: #f8f9fa;
341
+ border: 1px solid #e2e8f0;
342
+ border-radius: 6px;
343
+ padding: 12pt;
344
+ page-break-inside: avoid;
345
+ }
346
+
347
+ .comparison-box h4 {
348
+ font-size: 10pt;
349
+ font-weight: 600;
350
+ color: #1a1a2e;
351
+ margin-bottom: 8pt;
352
+ padding-bottom: 5pt;
353
+ border-bottom: 1px solid #e2e8f0;
354
+ }
355
+
356
+ .comparison-box ul {
357
+ list-style: none;
358
+ padding: 0;
359
+ margin: 0;
360
+ }
361
+
362
+ .comparison-box li {
363
+ padding: 3pt 0;
364
+ font-size: 9pt;
365
+ color: #444;
366
+ }
367
+
368
+ .comparison-box li::before {
369
+ content: '>';
370
+ color: #6366f1;
371
+ margin-right: 6pt;
372
+ font-family: 'JetBrains Mono', monospace;
373
+ }
374
+
375
+ /* Metric cards */
376
+ .metric-row {
377
+ display: grid;
378
+ grid-template-columns: repeat(3, 1fr);
379
+ gap: 12pt;
380
+ margin: 15pt 0;
381
+ }
382
+
383
+ .metric-card {
384
+ background: #f8f9fa;
385
+ border: 1px solid #e2e8f0;
386
+ border-radius: 6px;
387
+ padding: 12pt;
388
+ text-align: center;
389
+ page-break-inside: avoid;
390
+ }
391
+
392
+ .metric-name {
393
+ font-family: 'JetBrains Mono', monospace;
394
+ font-size: 7pt;
395
+ color: #64748b;
396
+ text-transform: uppercase;
397
+ letter-spacing: 1px;
398
+ margin-bottom: 5pt;
399
+ }
400
+
401
+ .metric-formula {
402
+ font-family: 'JetBrains Mono', monospace;
403
+ font-size: 9pt;
404
+ color: #6366f1;
405
+ font-weight: 600;
406
+ margin-bottom: 3pt;
407
+ }
408
+
409
+ .metric-desc {
410
+ font-size: 7pt;
411
+ color: #64748b;
412
+ }
413
+
414
+ /* Table */
415
+ table {
416
+ width: 100%;
417
+ border-collapse: collapse;
418
+ margin: 15pt 0;
419
+ font-size: 9pt;
420
+ page-break-inside: avoid;
421
+ }
422
+
423
+ thead {
424
+ display: table-header-group;
425
+ }
426
+
427
+ th {
428
+ background: #f1f5f9;
429
+ color: #475569;
430
+ font-family: 'JetBrains Mono', monospace;
431
+ font-size: 8pt;
432
+ font-weight: 600;
433
+ text-transform: uppercase;
434
+ letter-spacing: 0.5px;
435
+ padding: 8pt 10pt;
436
+ text-align: left;
437
+ border-top: 2px solid #333;
438
+ border-bottom: 1px solid #333;
439
+ }
440
+
441
+ td {
442
+ padding: 8pt 10pt;
443
+ border-bottom: 1px solid #e2e8f0;
444
+ color: #333;
445
+ }
446
+
447
+ tbody tr:last-child td {
448
+ border-bottom: 2px solid #333;
449
+ }
450
+
451
+ /* Page break utilities */
452
+ .page-break {
453
+ page-break-after: always;
454
+ }
455
+
456
+ /* Prevent overflow */
457
+ pre, table, figure, img, svg, blockquote {
458
+ max-width: 100%;
459
+ box-sizing: border-box;
460
+ }
461
+
462
+ a { word-break: break-all; }
463
+
464
+ /* Author footer on each page */
465
+ .author-footer {
466
+ margin-top: 30pt;
467
+ padding-top: 15pt;
468
+ border-top: 1px solid #e2e8f0;
469
+ text-align: center;
470
+ }
471
+
472
+ .author-name {
473
+ font-size: 10pt;
474
+ font-weight: 600;
475
+ color: #6366f1;
476
+ }
477
+
478
+ .author-contact {
479
+ font-size: 8pt;
480
+ color: #64748b;
481
+ margin-top: 3pt;
482
+ }
483
+ </style>
484
+ </head>
485
+ <body>
486
+ <!-- Cover Page -->
487
+ <div class="cover">
488
+ <div class="cover-decoration">
489
+ <div class="cover-circle cover-circle-1"></div>
490
+ <div class="cover-circle cover-circle-2"></div>
491
+ <div class="cover-circle cover-circle-3"></div>
492
+ </div>
493
+ <div class="cover-content">
494
+ <div class="cover-badge">Formation 2025/2026</div>
495
+ <h1 class="cover-title">Cours de<br>Machine Learning</h1>
496
+ <p class="cover-subtitle">De la theorie a la pratique — Algorithmes fondamentaux et techniques avancees</p>
497
+ <p class="cover-author">Formateur : Imad Maalouf</p>
498
+ <p class="cover-info">ML Academy — GE-MCI 4A</p>
499
+ </div>
500
+ </div>
501
+
502
+ <!-- Content -->
503
+ <div class="content">
504
+ <h1>1. Introduction au Machine Learning</h1>
505
+
506
+ <p>
507
+ Le <strong>Machine Learning (ML)</strong> est une branche de l'intelligence artificielle
508
+ qui permet aux machines d'apprendre a partir de donnees <em>sans etre explicitement programmees</em>
509
+ pour chaque tache. Au lieu de coder des regles a la main, on montre des exemples au modele
510
+ et il decouvre lui-meme les patterns.
511
+ </p>
512
+
513
+ <div class="info-box">
514
+ <div class="info-box-title">Idee fondamentale</div>
515
+ <p>
516
+ On cherche a approximer une fonction inconnue $f$ telle que $\hat{y} = f(x_1, x_2, \ldots, x_n)$.
517
+ Le modele ML apprend cette fonction a partir d'exemples $(x, y)$ connus.
518
+ </p>
519
+ </div>
520
+
521
+ <h2>1.1 Types d'apprentissage</h2>
522
+
523
+ <div class="cards-grid">
524
+ <div class="card">
525
+ <div class="card-icon">S</div>
526
+ <div class="card-title">Supervise</div>
527
+ <div class="card-text">Donnees labellisees $(x, y)$ : regression et classification.</div>
528
+ </div>
529
+ <div class="card">
530
+ <div class="card-icon">N</div>
531
+ <div class="card-title">Non supervise</div>
532
+ <div class="card-text">Pas de labels : clustering, reduction de dimension.</div>
533
+ </div>
534
+ <div class="card">
535
+ <div class="card-icon">R</div>
536
+ <div class="card-title">Par renforcement</div>
537
+ <div class="card-text">Agent apprend via actions-recompenses.</div>
538
+ </div>
539
+ </div>
540
+
541
+ <h2>1.2 Pipeline ML typique</h2>
542
+
543
+ <div class="pipeline">
544
+ <div class="pipeline-step">
545
+ <div class="pipeline-num">1</div>
546
+ <div class="pipeline-label">Donnees</div>
547
+ <div class="pipeline-desc">Collecte & nettoyage</div>
548
+ </div>
549
+ <div class="pipeline-step">
550
+ <div class="pipeline-num">2</div>
551
+ <div class="pipeline-label">Features</div>
552
+ <div class="pipeline-desc">Engineering</div>
553
+ </div>
554
+ <div class="pipeline-step">
555
+ <div class="pipeline-num">3</div>
556
+ <div class="pipeline-label">Split</div>
557
+ <div class="pipeline-desc">Train / Test</div>
558
+ </div>
559
+ <div class="pipeline-step">
560
+ <div class="pipeline-num">4</div>
561
+ <div class="pipeline-label">Modele</div>
562
+ <div class="pipeline-desc">Entrainement</div>
563
+ </div>
564
+ <div class="pipeline-step">
565
+ <div class="pipeline-num">5</div>
566
+ <div class="pipeline-label">Evaluation</div>
567
+ <div class="pipeline-desc">Metriques</div>
568
+ </div>
569
+ <div class="pipeline-step">
570
+ <div class="pipeline-num">6</div>
571
+ <div class="pipeline-label">Production</div>
572
+ <div class="pipeline-desc">Deploiement</div>
573
+ </div>
574
+ </div>
575
+
576
+ <div class="page-break"></div>
577
+
578
+ <h1>2. Regression Lineaire</h1>
579
+
580
+ <p>
581
+ La <strong>regression lineaire</strong> modelise la relation entre les features et la cible
582
+ par une fonction affine. C'est l'algorithme le plus simple mais souvent tres efficace
583
+ comme baseline.
584
+ </p>
585
+
586
+ <div class="equation-block">
587
+ $$\hat{y} = w_0 + w_1 x_1 + w_2 x_2 + \cdots + w_n x_n = \mathbf{w}^T \mathbf{x}$$
588
+ <span class="equation-label">Modele lineaire avec coefficients $\mathbf{w}$</span>
589
+ </div>
590
+
591
+ <p>
592
+ L'objectif est de minimiser l'erreur quadratique moyenne (MSE) :
593
+ </p>
594
+
595
+ <div class="equation-block">
596
+ $$\text{MSE} = \frac{1}{m} \sum_{i=1}^{m} (y_i - \hat{y}_i)^2$$
597
+ <span class="equation-label">Fonction de cout : moyenne des erreurs quadratiques</span>
598
+ </div>
599
+
600
+ <div class="info-box">
601
+ <div class="info-box-title">Solution analytique</div>
602
+ <p>
603
+ La regression lineaire admet une solution fermee :
604
+ $\mathbf{w}^* = (X^T X)^{-1} X^T Y$. Pas besoin d'iterations !
605
+ </p>
606
+ </div>
607
+
608
+ <h2>2.1 Avantages et limitations</h2>
609
+
610
+ <div class="comparison-grid">
611
+ <div class="comparison-box">
612
+ <h4>[+] Avantages</h4>
613
+ <ul>
614
+ <li>Tres rapide a entrainer</li>
615
+ <li>Interpretable (coefficients)</li>
616
+ <li>Pas d'hyperparametres</li>
617
+ <li>Excellent baseline</li>
618
+ </ul>
619
+ </div>
620
+ <div class="comparison-box">
621
+ <h4>[-] Limitations</h4>
622
+ <ul>
623
+ <li>Relation lineaire uniquement</li>
624
+ <li>Sensible aux outliers</li>
625
+ <li>Performance decroit en haute dimension</li>
626
+ </ul>
627
+ </div>
628
+ </div>
629
+
630
+ <div class="page-break"></div>
631
+
632
+ <h1>3. Regression Logistique</h1>
633
+
634
+ <p>
635
+ Malgre son nom, la <strong>regression logistique</strong> est un algorithme de <em>classification</em>.
636
+ Elle predit la probabilite d'appartenance a une classe en utilisant la fonction sigmoide.
637
+ </p>
638
+
639
+ <div class="equation-block">
640
+ $$P(y=1|\mathbf{x}) = \sigma(\mathbf{w}^T \mathbf{x}) = \frac{1}{1 + e^{-\mathbf{w}^T \mathbf{x}}}$$
641
+ <span class="equation-label">Fonction sigmoide pour la classification binaire</span>
642
+ </div>
643
+
644
+ <div class="info-box">
645
+ <div class="info-box-title">Cas d'usage : Dataset Titanic</div>
646
+ <p>
647
+ Predire la survie des passagers du Titanic a partir de leur age, sexe,
648
+ classe de billet, etc. Un classique du ML pour debuter !
649
+ </p>
650
+ </div>
651
+
652
+ <div class="page-break"></div>
653
+
654
+ <h1>4. Random Forest</h1>
655
+
656
+ <p>
657
+ <strong>Random Forest</strong> est un ensemble d'arbres de decision qui votent pour predire.
658
+ C'est l'un des algorithmes les plus populaires en ML applique : performant, robuste,
659
+ peu sensible au tuning.
660
+ </p>
661
+
662
+ <h2>4.1 Algorithme : Bagging + Random Splits</h2>
663
+
664
+ <div class="pipeline">
665
+ <div class="pipeline-step">
666
+ <div class="pipeline-num">1</div>
667
+ <div class="pipeline-label">Bootstrap</div>
668
+ <div class="pipeline-desc">Echantillons aleatoires</div>
669
+ </div>
670
+ <div class="pipeline-step">
671
+ <div class="pipeline-num">2</div>
672
+ <div class="pipeline-label">Splits</div>
673
+ <div class="pipeline-desc">Features aleatoires</div>
674
+ </div>
675
+ <div class="pipeline-step">
676
+ <div class="pipeline-num">3</div>
677
+ <div class="pipeline-label">Arbres</div>
678
+ <div class="pipeline-desc">N arbres independants</div>
679
+ </div>
680
+ <div class="pipeline-step">
681
+ <div class="pipeline-num">4</div>
682
+ <div class="pipeline-label">Vote</div>
683
+ <div class="pipeline-desc">Moyenne ou mode</div>
684
+ </div>
685
+ </div>
686
+
687
+ <h2>4.2 Hyperparametres cles</h2>
688
+
689
+ <div class="metric-row">
690
+ <div class="metric-card">
691
+ <div class="metric-name">n_estimators</div>
692
+ <div class="metric-formula">100 - 500</div>
693
+ <div class="metric-desc">Nombre d'arbres</div>
694
+ </div>
695
+ <div class="metric-card">
696
+ <div class="metric-name">max_depth</div>
697
+ <div class="metric-formula">10 - 30</div>
698
+ <div class="metric-desc">Profondeur max</div>
699
+ </div>
700
+ <div class="metric-card">
701
+ <div class="metric-name">min_samples_split</div>
702
+ <div class="metric-formula">2 - 10</div>
703
+ <div class="metric-desc">Min pour splitter</div>
704
+ </div>
705
+ </div>
706
+
707
+ <div class="info-box">
708
+ <div class="info-box-title">Feature Importance</div>
709
+ <p>
710
+ Random Forest fournit automatiquement l'importance de chaque feature,
711
+ ce qui aide a comprendre quelles variables influencent le plus les predictions.
712
+ </p>
713
+ </div>
714
+
715
+ <div class="page-break"></div>
716
+
717
+ <h1>5. Reseaux de Neurones</h1>
718
+
719
+ <p>
720
+ Les <strong>reseaux de neurones</strong> sont inspires du cerveau humain : des couches de neurones
721
+ interconnectes executent des transformations non-lineaires. Ils excellent pour les patterns complexes.
722
+ </p>
723
+
724
+ <h2>5.1 Fonctionnement : Forward + Backprop</h2>
725
+
726
+ <div class="cards-grid">
727
+ <div class="card">
728
+ <div class="card-icon">F</div>
729
+ <div class="card-title">Forward Pass</div>
730
+ <div class="card-text">Donnees traversent les couches : $\mathbf{h}_1 = \sigma(W_1 \mathbf{x} + b_1)$</div>
731
+ </div>
732
+ <div class="card">
733
+ <div class="card-icon">L</div>
734
+ <div class="card-title">Loss Computation</div>
735
+ <div class="card-text">Compare prediction vs realite : $L = \frac{1}{m} \sum (y - \hat{y})^2$</div>
736
+ </div>
737
+ <div class="card">
738
+ <div class="card-icon">B</div>
739
+ <div class="card-title">Backpropagation</div>
740
+ <div class="card-text">Calcule les gradients via la chaine de derivation</div>
741
+ </div>
742
+ </div>
743
+
744
+ <h2>5.2 Fonctions d'activation</h2>
745
+
746
+ <div class="metric-row">
747
+ <div class="metric-card">
748
+ <div class="metric-name">ReLU</div>
749
+ <div class="metric-formula">$f(x) = \max(0, x)$</div>
750
+ <div class="metric-desc">Couches cachees</div>
751
+ </div>
752
+ <div class="metric-card">
753
+ <div class="metric-name">Sigmoid</div>
754
+ <div class="metric-formula">$f(x) = \frac{1}{1 + e^{-x}}$</div>
755
+ <div class="metric-desc">Classification binaire</div>
756
+ </div>
757
+ <div class="metric-card">
758
+ <div class="metric-name">Softmax</div>
759
+ <div class="metric-formula">$f(x_i) = \frac{e^{x_i}}{\sum_j e^{x_j}}$</div>
760
+ <div class="metric-desc">Classification multi-classe</div>
761
+ </div>
762
+ </div>
763
+
764
+ <div class="page-break"></div>
765
+
766
+ <h1>6. LSTM et Series Temporelles</h1>
767
+
768
+ <p>
769
+ <strong>LSTM (Long Short-Term Memory)</strong> est un type de reseau neuronal pour series temporelles.
770
+ Il peut "retenir" l'information sur de longues periodes — crucial pour les predictions temporelles.
771
+ </p>
772
+
773
+ <div class="info-box">
774
+ <div class="info-box-title">Probleme des RNN vanilla</div>
775
+ <p>
776
+ Les gradients disparaissent (vanishing) ou explosent (exploding) sur de longues sequences.
777
+ Le LSTM resout ce probleme avec son <strong>cell state</strong>.
778
+ </p>
779
+ </div>
780
+
781
+ <h2>6.1 Les trois portes du LSTM</h2>
782
+
783
+ <div class="metric-row">
784
+ <div class="metric-card">
785
+ <div class="metric-name">Forget Gate</div>
786
+ <div class="metric-formula">$f_t = \sigma(W_f [h_{t-1}, x_t] + b_f)$</div>
787
+ <div class="metric-desc">Quoi oublier ?</div>
788
+ </div>
789
+ <div class="metric-card">
790
+ <div class="metric-name">Input Gate</div>
791
+ <div class="metric-formula">$i_t = \sigma(W_i [h_{t-1}, x_t] + b_i)$</div>
792
+ <div class="metric-desc">Quoi ajouter ?</div>
793
+ </div>
794
+ <div class="metric-card">
795
+ <div class="metric-name">Output Gate</div>
796
+ <div class="metric-formula">$o_t = \sigma(W_o [h_{t-1}, x_t] + b_o)$</div>
797
+ <div class="metric-desc">Quoi exposer ?</div>
798
+ </div>
799
+ </div>
800
+
801
+ <div class="info-box">
802
+ <div class="info-box-title">Cas d'usage</div>
803
+ <p>
804
+ Prediction de prix boursiers, meteo, consommation energetique,
805
+ traitement du langage naturel (NLP)...
806
+ </p>
807
+ </div>
808
+
809
+ <div class="page-break"></div>
810
+
811
+ <h1>7. Metriques de Performance</h1>
812
+
813
+ <p>
814
+ Evaluer correctement un modele est crucial. Les bonnes metriques dependent du type de probleme
815
+ (regression vs classification) et des objectifs metier.
816
+ </p>
817
+
818
+ <h2>7.1 Regression</h2>
819
+
820
+ <div class="metric-row">
821
+ <div class="metric-card">
822
+ <div class="metric-name">MAE</div>
823
+ <div class="metric-formula">$\frac{1}{n}\sum|y_i - \hat{y}_i|$</div>
824
+ <div class="metric-desc">Robuste aux outliers</div>
825
+ </div>
826
+ <div class="metric-card">
827
+ <div class="metric-name">RMSE</div>
828
+ <div class="metric-formula">$\sqrt{\frac{1}{n}\sum(y_i - \hat{y}_i)^2}$</div>
829
+ <div class="metric-desc">Penalise les grandes erreurs</div>
830
+ </div>
831
+ <div class="metric-card">
832
+ <div class="metric-name">R2</div>
833
+ <div class="metric-formula">$1 - \frac{SS_{res}}{SS_{tot}}$</div>
834
+ <div class="metric-desc">% variance expliquee</div>
835
+ </div>
836
+ </div>
837
+
838
+ <h2>7.2 Classification</h2>
839
+
840
+ <table>
841
+ <thead>
842
+ <tr>
843
+ <th>Metrique</th>
844
+ <th>Formule</th>
845
+ <th>Usage</th>
846
+ </tr>
847
+ </thead>
848
+ <tbody>
849
+ <tr>
850
+ <td><strong>Accuracy</strong></td>
851
+ <td>$(TP + TN) / Total$</td>
852
+ <td>Classes equilibrees</td>
853
+ </tr>
854
+ <tr>
855
+ <td><strong>Precision</strong></td>
856
+ <td>$TP / (TP + FP)$</td>
857
+ <td>Minimiser faux positifs</td>
858
+ </tr>
859
+ <tr>
860
+ <td><strong>Recall</strong></td>
861
+ <td>$TP / (TP + FN)$</td>
862
+ <td>Minimiser faux negatifs</td>
863
+ </tr>
864
+ <tr>
865
+ <td><strong>F1-Score</strong></td>
866
+ <td>$2 \cdot \frac{P \cdot R}{P + R}$</td>
867
+ <td>Classes desequilibrees</td>
868
+ </tr>
869
+ </tbody>
870
+ </table>
871
+
872
+ <div class="page-break"></div>
873
+
874
+ <h1>8. Optimisation et Regularisation</h1>
875
+
876
+ <p>
877
+ Pour eviter le <strong>surapprentissage (overfitting)</strong> et ameliorer la generalisation,
878
+ plusieurs techniques existent.
879
+ </p>
880
+
881
+ <div class="cards-grid">
882
+ <div class="card">
883
+ <div class="card-icon">D</div>
884
+ <div class="card-title">Dropout</div>
885
+ <div class="card-text">Desactive aleatoirement des neurones pendant l'entrainement.</div>
886
+ </div>
887
+ <div class="card">
888
+ <div class="card-icon">E</div>
889
+ <div class="card-title">Early Stopping</div>
890
+ <div class="card-text">Arrete l'entrainement quand la validation stagne.</div>
891
+ </div>
892
+ <div class="card">
893
+ <div class="card-icon">L</div>
894
+ <div class="card-title">L2 Regularization</div>
895
+ <div class="card-text">Penalise les grands poids : $L_{total} = L_{data} + \lambda \sum w^2$</div>
896
+ </div>
897
+ </div>
898
+
899
+ <div class="info-box">
900
+ <div class="info-box-title">Regle d'or</div>
901
+ <p>
902
+ Toujours comparer les metriques sur <strong>train</strong> ET <strong>test</strong>.
903
+ Un grand ecart = overfitting. Objectif : R2 train ≈ R2 test.
904
+ </p>
905
+ </div>
906
+
907
+ <div class="author-footer">
908
+ <div class="author-name">Imad Maalouf</div>
909
+ <div class="author-contact">
910
+ imadmaalouf02@gmail.com | github.com/imadmaalouf02 | huggingface.co/spaces/MAALOOUF/ML_Training
911
+ </div>
912
+ </div>
913
+ </div>
914
+ </body>
915
+ </html>
cours.html ADDED
@@ -0,0 +1,1421 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="fr">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Cours — ML Academy</title>
7
+ <link rel="stylesheet" href="css/shared.css">
8
+ <script>
9
+ window.MathJax = {
10
+ tex: {
11
+ inlineMath: [['$', '$'], ['\\(', '\\)']],
12
+ displayMath: [['$$', '$$'], ['\\[', '\\]']]
13
+ },
14
+ options: { skipHtmlTags: ['script','noscript','style','textarea','pre'] }
15
+ };
16
+ </script>
17
+ <script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
18
+ <style>
19
+ /* LAYOUT WITH SIDEBAR */
20
+ .course-layout {
21
+ display: flex;
22
+ min-height: calc(100vh - var(--navbar-height));
23
+ }
24
+
25
+ /* SIDEBAR */
26
+ .sidebar {
27
+ width: var(--sidebar-width);
28
+ background: var(--bg-secondary);
29
+ border-right: 1px solid var(--border-color);
30
+ position: fixed;
31
+ top: var(--navbar-height);
32
+ left: 0;
33
+ bottom: 0;
34
+ overflow-y: auto;
35
+ z-index: 100;
36
+ animation: fadeInLeft 0.5s ease;
37
+ }
38
+
39
+ .sidebar-header {
40
+ padding: var(--space-xl);
41
+ border-bottom: 1px solid var(--border-color);
42
+ }
43
+
44
+ .sidebar-badge {
45
+ display: inline-block;
46
+ padding: var(--space-xs) var(--space-sm);
47
+ background: rgba(99, 102, 241, 0.1);
48
+ border: 1px solid rgba(99, 102, 241, 0.3);
49
+ border-radius: var(--radius-sm);
50
+ font-family: 'JetBrains Mono', monospace;
51
+ font-size: 0.65rem;
52
+ color: var(--primary-light);
53
+ text-transform: uppercase;
54
+ letter-spacing: 1px;
55
+ margin-bottom: var(--space-sm);
56
+ }
57
+
58
+ .sidebar-title {
59
+ font-size: 1.1rem;
60
+ font-weight: 700;
61
+ color: var(--text-primary);
62
+ margin-bottom: var(--space-xs);
63
+ }
64
+
65
+ .sidebar-subtitle {
66
+ font-size: 0.8rem;
67
+ color: var(--text-muted);
68
+ }
69
+
70
+ .sidebar-nav {
71
+ padding: var(--space-md) 0;
72
+ }
73
+
74
+ .nav-section {
75
+ margin-bottom: var(--space-md);
76
+ }
77
+
78
+ .nav-section-title {
79
+ padding: var(--space-sm) var(--space-xl);
80
+ font-family: 'JetBrains Mono', monospace;
81
+ font-size: 0.65rem;
82
+ color: var(--text-muted);
83
+ text-transform: uppercase;
84
+ letter-spacing: 1px;
85
+ }
86
+
87
+ .nav-item {
88
+ display: flex;
89
+ align-items: center;
90
+ gap: var(--space-sm);
91
+ padding: var(--space-sm) var(--space-xl);
92
+ color: var(--text-secondary);
93
+ text-decoration: none;
94
+ font-size: 0.9rem;
95
+ transition: all var(--transition-base);
96
+ border-left: 3px solid transparent;
97
+ }
98
+
99
+ .nav-item:hover {
100
+ background: var(--bg-hover);
101
+ color: var(--text-primary);
102
+ border-left-color: var(--primary);
103
+ }
104
+
105
+ .nav-item.active {
106
+ background: rgba(99, 102, 241, 0.1);
107
+ color: var(--primary-light);
108
+ border-left-color: var(--primary);
109
+ }
110
+
111
+ .nav-icon {
112
+ font-size: 1rem;
113
+ font-family: 'JetBrains Mono', monospace;
114
+ color: var(--text-muted);
115
+ }
116
+
117
+ .sidebar-footer {
118
+ padding: var(--space-lg) var(--space-xl);
119
+ border-top: 1px solid var(--border-color);
120
+ margin-top: auto;
121
+ }
122
+
123
+ .progress-label {
124
+ font-size: 0.75rem;
125
+ color: var(--text-muted);
126
+ margin-bottom: var(--space-sm);
127
+ display: flex;
128
+ justify-content: space-between;
129
+ }
130
+
131
+ .progress-bar {
132
+ height: 6px;
133
+ background: var(--bg-tertiary);
134
+ border-radius: 3px;
135
+ overflow: hidden;
136
+ }
137
+
138
+ .progress-fill {
139
+ height: 100%;
140
+ background: linear-gradient(90deg, var(--primary), var(--secondary));
141
+ border-radius: 3px;
142
+ transition: width 0.5s ease;
143
+ animation: progress 1s ease;
144
+ }
145
+
146
+ /* PDF DOWNLOAD BUTTON */
147
+ .pdf-download {
148
+ display: flex;
149
+ align-items: center;
150
+ gap: var(--space-sm);
151
+ padding: var(--space-sm) var(--space-md);
152
+ background: rgba(239, 68, 68, 0.1);
153
+ border: 1px solid rgba(239, 68, 68, 0.3);
154
+ border-radius: var(--radius-md);
155
+ color: #ef4444;
156
+ font-size: 0.8rem;
157
+ font-weight: 600;
158
+ text-decoration: none;
159
+ margin-top: var(--space-md);
160
+ transition: all var(--transition-base);
161
+ }
162
+
163
+ .pdf-download:hover {
164
+ background: rgba(239, 68, 68, 0.2);
165
+ transform: translateY(-2px);
166
+ }
167
+
168
+ /* MAIN CONTENT */
169
+ .main-content {
170
+ flex: 1;
171
+ margin-left: var(--sidebar-width);
172
+ padding: var(--space-2xl);
173
+ max-width: 900px;
174
+ }
175
+
176
+ /* COURSE HERO */
177
+ .course-hero {
178
+ text-align: center;
179
+ padding: var(--space-2xl) 0;
180
+ margin-bottom: var(--space-2xl);
181
+ border-bottom: 1px solid var(--border-color);
182
+ }
183
+
184
+ .course-hero-badge {
185
+ display: inline-flex;
186
+ align-items: center;
187
+ gap: var(--space-sm);
188
+ padding: var(--space-xs) var(--space-md);
189
+ background: rgba(16, 185, 129, 0.1);
190
+ border: 1px solid rgba(16, 185, 129, 0.3);
191
+ border-radius: 20px;
192
+ font-size: 0.75rem;
193
+ color: var(--success);
194
+ margin-bottom: var(--space-lg);
195
+ }
196
+
197
+ .course-hero-badge .dot {
198
+ width: 6px;
199
+ height: 6px;
200
+ background: var(--success);
201
+ border-radius: 50%;
202
+ animation: pulse 2s ease-in-out infinite;
203
+ }
204
+
205
+ .course-hero-title {
206
+ font-size: clamp(1.75rem, 4vw, 2.5rem);
207
+ font-weight: 700;
208
+ color: var(--text-primary);
209
+ margin-bottom: var(--space-md);
210
+ }
211
+
212
+ .course-hero-subtitle {
213
+ font-size: 1rem;
214
+ color: var(--text-secondary);
215
+ margin-bottom: var(--space-xl);
216
+ }
217
+
218
+ .course-hero-stats {
219
+ display: flex;
220
+ justify-content: center;
221
+ gap: var(--space-2xl);
222
+ flex-wrap: wrap;
223
+ }
224
+
225
+ .course-hero-stat {
226
+ text-align: center;
227
+ }
228
+
229
+ .course-hero-stat-value {
230
+ font-family: 'JetBrains Mono', monospace;
231
+ font-size: 2rem;
232
+ font-weight: 700;
233
+ color: var(--text-primary);
234
+ }
235
+
236
+ .course-hero-stat-label {
237
+ font-size: 0.7rem;
238
+ color: var(--text-muted);
239
+ text-transform: uppercase;
240
+ letter-spacing: 1px;
241
+ margin-top: var(--space-xs);
242
+ }
243
+
244
+ /* SECTIONS */
245
+ .section {
246
+ margin-bottom: var(--space-3xl);
247
+ scroll-margin-top: calc(var(--navbar-height) + var(--space-lg));
248
+ }
249
+
250
+ .section-header {
251
+ margin-bottom: var(--space-xl);
252
+ padding-bottom: var(--space-md);
253
+ border-bottom: 1px solid var(--border-color);
254
+ }
255
+
256
+ .section-badge {
257
+ display: inline-block;
258
+ padding: var(--space-xs) var(--space-sm);
259
+ background: rgba(99, 102, 241, 0.1);
260
+ border-radius: var(--radius-sm);
261
+ font-family: 'JetBrains Mono', monospace;
262
+ font-size: 0.65rem;
263
+ color: var(--primary-light);
264
+ text-transform: uppercase;
265
+ letter-spacing: 1px;
266
+ margin-bottom: var(--space-sm);
267
+ }
268
+
269
+ .section-title {
270
+ font-size: clamp(1.5rem, 3vw, 2rem);
271
+ font-weight: 700;
272
+ color: var(--text-primary);
273
+ margin-bottom: var(--space-sm);
274
+ }
275
+
276
+ .section-title small {
277
+ display: block;
278
+ font-size: 0.9rem;
279
+ color: var(--text-muted);
280
+ font-weight: 500;
281
+ margin-bottom: var(--space-xs);
282
+ }
283
+
284
+ .section-content p {
285
+ font-size: 1rem;
286
+ color: var(--text-secondary);
287
+ line-height: 1.8;
288
+ margin-bottom: var(--space-md);
289
+ }
290
+
291
+ .section-content strong {
292
+ color: var(--text-primary);
293
+ font-weight: 600;
294
+ }
295
+
296
+ /* CARDS GRID */
297
+ .cards-grid {
298
+ display: grid;
299
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
300
+ gap: var(--space-md);
301
+ margin: var(--space-lg) 0;
302
+ }
303
+
304
+ .info-card {
305
+ background: var(--bg-card);
306
+ border: 1px solid var(--border-color);
307
+ border-radius: var(--radius-md);
308
+ padding: var(--space-lg);
309
+ transition: all var(--transition-base);
310
+ }
311
+
312
+ .info-card:hover {
313
+ border-color: var(--primary);
314
+ transform: translateY(-3px);
315
+ }
316
+
317
+ .info-card-icon {
318
+ width: 40px;
319
+ height: 40px;
320
+ background: linear-gradient(135deg, var(--primary), var(--secondary));
321
+ border-radius: var(--radius-md);
322
+ display: flex;
323
+ align-items: center;
324
+ justify-content: center;
325
+ font-size: 1rem;
326
+ font-weight: 700;
327
+ color: white;
328
+ margin-bottom: var(--space-sm);
329
+ }
330
+
331
+ .info-card-title {
332
+ font-size: 1rem;
333
+ font-weight: 600;
334
+ color: var(--text-primary);
335
+ margin-bottom: var(--space-xs);
336
+ }
337
+
338
+ .info-card-text {
339
+ font-size: 0.85rem;
340
+ color: var(--text-secondary);
341
+ }
342
+
343
+ .info-card-tag {
344
+ display: inline-block;
345
+ margin-top: var(--space-sm);
346
+ padding: var(--space-xs) var(--space-sm);
347
+ background: var(--bg-tertiary);
348
+ border-radius: var(--radius-sm);
349
+ font-family: 'JetBrains Mono', monospace;
350
+ font-size: 0.65rem;
351
+ color: var(--text-muted);
352
+ }
353
+
354
+ /* PIPELINE */
355
+ .pipeline {
356
+ display: flex;
357
+ flex-wrap: wrap;
358
+ gap: var(--space-md);
359
+ margin: var(--space-xl) 0;
360
+ padding: var(--space-lg);
361
+ background: var(--bg-card);
362
+ border: 1px solid var(--border-color);
363
+ border-radius: var(--radius-lg);
364
+ }
365
+
366
+ .pipeline-step {
367
+ flex: 1;
368
+ min-width: 120px;
369
+ text-align: center;
370
+ padding: var(--space-md);
371
+ position: relative;
372
+ }
373
+
374
+ .pipeline-step:not(:last-child)::after {
375
+ content: '->';
376
+ position: absolute;
377
+ right: -15px;
378
+ top: 50%;
379
+ transform: translateY(-50%);
380
+ color: var(--primary);
381
+ font-family: 'JetBrains Mono', monospace;
382
+ font-size: 1rem;
383
+ }
384
+
385
+ .pipeline-num {
386
+ width: 36px;
387
+ height: 36px;
388
+ background: linear-gradient(135deg, var(--primary), var(--secondary));
389
+ border-radius: 50%;
390
+ display: flex;
391
+ align-items: center;
392
+ justify-content: center;
393
+ font-family: 'JetBrains Mono', monospace;
394
+ font-size: 0.9rem;
395
+ font-weight: 700;
396
+ color: white;
397
+ margin: 0 auto var(--space-sm);
398
+ }
399
+
400
+ .pipeline-label {
401
+ font-size: 0.85rem;
402
+ font-weight: 600;
403
+ color: var(--text-primary);
404
+ margin-bottom: var(--space-xs);
405
+ }
406
+
407
+ .pipeline-desc {
408
+ font-size: 0.75rem;
409
+ color: var(--text-muted);
410
+ }
411
+
412
+ /* CHECKLIST */
413
+ .checklist {
414
+ list-style: none;
415
+ padding: 0;
416
+ margin: var(--space-lg) 0;
417
+ }
418
+
419
+ .checklist li {
420
+ display: flex;
421
+ align-items: flex-start;
422
+ gap: var(--space-sm);
423
+ padding: var(--space-sm) 0;
424
+ font-size: 0.95rem;
425
+ color: var(--text-secondary);
426
+ }
427
+
428
+ .checklist li::before {
429
+ content: '[v]';
430
+ color: var(--success);
431
+ font-family: 'JetBrains Mono', monospace;
432
+ font-weight: 700;
433
+ flex-shrink: 0;
434
+ }
435
+
436
+ /* EQUATIONS */
437
+ .equation-block {
438
+ background: var(--bg-card);
439
+ border: 1px solid var(--border-color);
440
+ border-left: 3px solid var(--primary);
441
+ border-radius: var(--radius-md);
442
+ padding: var(--space-lg);
443
+ margin: var(--space-lg) 0;
444
+ text-align: center;
445
+ overflow-x: auto;
446
+ }
447
+
448
+ .equation-label {
449
+ display: block;
450
+ font-family: 'JetBrains Mono', monospace;
451
+ font-size: 0.7rem;
452
+ color: var(--text-muted);
453
+ text-align: right;
454
+ margin-top: var(--space-sm);
455
+ }
456
+
457
+ /* COMPARISON GRID */
458
+ .comparison-grid {
459
+ display: grid;
460
+ grid-template-columns: repeat(2, 1fr);
461
+ gap: var(--space-md);
462
+ margin: var(--space-lg) 0;
463
+ }
464
+
465
+ .comparison-box {
466
+ background: var(--bg-card);
467
+ border: 1px solid var(--border-color);
468
+ border-radius: var(--radius-md);
469
+ padding: var(--space-lg);
470
+ }
471
+
472
+ .comparison-box h4 {
473
+ font-size: 0.9rem;
474
+ font-weight: 600;
475
+ color: var(--text-primary);
476
+ margin-bottom: var(--space-md);
477
+ padding-bottom: var(--space-sm);
478
+ border-bottom: 1px solid var(--border-color);
479
+ }
480
+
481
+ .comparison-box ul {
482
+ list-style: none;
483
+ padding: 0;
484
+ margin: 0;
485
+ }
486
+
487
+ .comparison-box li {
488
+ padding: var(--space-xs) 0;
489
+ font-size: 0.85rem;
490
+ color: var(--text-secondary);
491
+ }
492
+
493
+ .comparison-box li::before {
494
+ content: '>';
495
+ color: var(--primary);
496
+ margin-right: var(--space-sm);
497
+ font-family: 'JetBrains Mono', monospace;
498
+ }
499
+
500
+ /* METRIC CARDS */
501
+ .metric-row {
502
+ display: grid;
503
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
504
+ gap: var(--space-md);
505
+ margin: var(--space-lg) 0;
506
+ }
507
+
508
+ .metric-card {
509
+ background: var(--bg-card);
510
+ border: 1px solid var(--border-color);
511
+ border-radius: var(--radius-md);
512
+ padding: var(--space-lg);
513
+ text-align: center;
514
+ transition: all var(--transition-base);
515
+ }
516
+
517
+ .metric-card:hover {
518
+ border-color: var(--primary);
519
+ transform: translateY(-3px);
520
+ }
521
+
522
+ .metric-name {
523
+ font-family: 'JetBrains Mono', monospace;
524
+ font-size: 0.75rem;
525
+ color: var(--text-muted);
526
+ text-transform: uppercase;
527
+ letter-spacing: 1px;
528
+ margin-bottom: var(--space-sm);
529
+ }
530
+
531
+ .metric-formula {
532
+ font-family: 'JetBrains Mono', monospace;
533
+ font-size: 1rem;
534
+ color: var(--primary-light);
535
+ font-weight: 600;
536
+ margin-bottom: var(--space-xs);
537
+ }
538
+
539
+ .metric-desc {
540
+ font-size: 0.75rem;
541
+ color: var(--text-muted);
542
+ }
543
+
544
+ /* RESPONSIVE */
545
+ @media (max-width: 768px) {
546
+ .sidebar {
547
+ transform: translateX(-100%);
548
+ transition: transform var(--transition-base);
549
+ }
550
+
551
+ .sidebar.open {
552
+ transform: translateX(0);
553
+ }
554
+
555
+ .main-content {
556
+ margin-left: 0;
557
+ padding: var(--space-lg);
558
+ }
559
+
560
+ .comparison-grid {
561
+ grid-template-columns: 1fr;
562
+ }
563
+
564
+ .pipeline-step:not(:last-child)::after {
565
+ display: none;
566
+ }
567
+ }
568
+
569
+ /* BACK TO TOP */
570
+ .back-to-top {
571
+ position: fixed;
572
+ bottom: var(--space-xl);
573
+ right: var(--space-xl);
574
+ width: 44px;
575
+ height: 44px;
576
+ background: var(--primary);
577
+ border: none;
578
+ border-radius: 50%;
579
+ color: white;
580
+ font-size: 1.2rem;
581
+ cursor: pointer;
582
+ opacity: 0;
583
+ visibility: hidden;
584
+ transition: all var(--transition-base);
585
+ z-index: 1000;
586
+ display: flex;
587
+ align-items: center;
588
+ justify-content: center;
589
+ }
590
+
591
+ .back-to-top.visible {
592
+ opacity: 1;
593
+ visibility: visible;
594
+ }
595
+
596
+ .back-to-top:hover {
597
+ background: var(--primary-light);
598
+ transform: translateY(-3px);
599
+ }
600
+
601
+ /* AUTHOR FOOTER */
602
+ .author-footer {
603
+ background: var(--bg-secondary);
604
+ border-top: 1px solid var(--border-color);
605
+ padding: var(--space-xl);
606
+ text-align: center;
607
+ }
608
+
609
+ .author-info {
610
+ display: flex;
611
+ justify-content: center;
612
+ gap: var(--space-xl);
613
+ flex-wrap: wrap;
614
+ margin-bottom: var(--space-md);
615
+ }
616
+
617
+ .author-link {
618
+ display: flex;
619
+ align-items: center;
620
+ gap: var(--space-sm);
621
+ color: var(--text-secondary);
622
+ text-decoration: none;
623
+ font-size: 0.9rem;
624
+ transition: color var(--transition-base);
625
+ }
626
+
627
+ .author-link:hover {
628
+ color: var(--primary-light);
629
+ }
630
+
631
+ .author-link svg {
632
+ width: 18px;
633
+ height: 18px;
634
+ fill: currentColor;
635
+ }
636
+ </style>
637
+ </head>
638
+ <body>
639
+ <!-- Particles Background -->
640
+ <div class="particles-container">
641
+ <div class="particle"></div>
642
+ <div class="particle"></div>
643
+ <div class="particle"></div>
644
+ <div class="particle"></div>
645
+ <div class="particle"></div>
646
+ </div>
647
+
648
+ <!-- Navigation -->
649
+ <nav class="navbar">
650
+ <a href="index.html" class="navbar-brand">
651
+ <div class="brand-logo">ML</div>
652
+ <span>ML Academy</span>
653
+ </a>
654
+ <div class="navbar-nav">
655
+ <a href="index.html" class="nav-link">
656
+ <span class="nav-icon">[H]</span>
657
+ <span>Accueil</span>
658
+ </a>
659
+ <a href="cours.html" class="nav-link active">
660
+ <span class="nav-icon">[C]</span>
661
+ <span>Cours</span>
662
+ </a>
663
+ <a href="tp.html" class="nav-link">
664
+ <span class="nav-icon">[T]</span>
665
+ <span>TPs</span>
666
+ </a>
667
+ <a href="feedback.html" class="nav-link">
668
+ <span class="nav-icon">[F]</span>
669
+ <span>Contact</span>
670
+ </a>
671
+ </div>
672
+ <div class="nav-badge">
673
+ <div class="dot"></div>
674
+ <span>Google Colab Ready</span>
675
+ </div>
676
+ </nav>
677
+
678
+ <!-- Course Layout -->
679
+ <div class="course-layout">
680
+ <!-- Sidebar -->
681
+ <aside class="sidebar">
682
+ <div class="sidebar-header">
683
+ <div class="sidebar-badge">Formation 2025/2026</div>
684
+ <h1 class="sidebar-title">Machine Learning</h1>
685
+ <p class="sidebar-subtitle">Cours theoriques complets</p>
686
+ <a href="cours.pdf" class="pdf-download" download>
687
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
688
+ <path d="M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z"/>
689
+ </svg>
690
+ Telecharger le PDF
691
+ </a>
692
+ </div>
693
+
694
+ <nav class="sidebar-nav">
695
+ <div class="nav-section">
696
+ <div class="nav-section-title">Introduction</div>
697
+ <a href="#intro" class="nav-item active">
698
+ <span class="nav-icon">[1]</span>
699
+ <span>Qu'est-ce que le ML ?</span>
700
+ </a>
701
+ </div>
702
+
703
+ <div class="nav-section">
704
+ <div class="nav-section-title">Algorithmes Supervises</div>
705
+ <a href="#regression" class="nav-item">
706
+ <span class="nav-icon">[2]</span>
707
+ <span>Regression Lineaire</span>
708
+ </a>
709
+ <a href="#logistic" class="nav-item">
710
+ <span class="nav-icon">[3]</span>
711
+ <span>Regression Logistique</span>
712
+ </a>
713
+ <a href="#randomforest" class="nav-item">
714
+ <span class="nav-icon">[4]</span>
715
+ <span>Random Forest</span>
716
+ </a>
717
+ </div>
718
+
719
+ <div class="nav-section">
720
+ <div class="nav-section-title">Deep Learning</div>
721
+ <a href="#neuralnets" class="nav-item">
722
+ <span class="nav-icon">[5]</span>
723
+ <span>Reseaux de Neurones</span>
724
+ </a>
725
+ <a href="#lstm" class="nav-item">
726
+ <span class="nav-icon">[6]</span>
727
+ <span>LSTM & Series Temp.</span>
728
+ </a>
729
+ </div>
730
+
731
+ <div class="nav-section">
732
+ <div class="nav-section-title">Evaluation</div>
733
+ <a href="#metrics" class="nav-item">
734
+ <span class="nav-icon">[7]</span>
735
+ <span>Metriques</span>
736
+ </a>
737
+ <a href="#optimization" class="nav-item">
738
+ <span class="nav-icon">[8]</span>
739
+ <span>Optimisation</span>
740
+ </a>
741
+ </div>
742
+
743
+ <div class="nav-section">
744
+ <div class="nav-section-title">Navigation</div>
745
+ <a href="index.html" class="nav-item">
746
+ <span class="nav-icon">[H]</span>
747
+ <span>Accueil</span>
748
+ </a>
749
+ <a href="tp.html" class="nav-item">
750
+ <span class="nav-icon">[T]</span>
751
+ <span>Travaux Pratiques</span>
752
+ </a>
753
+ <a href="feedback.html" class="nav-item">
754
+ <span class="nav-icon">[F]</span>
755
+ <span>Questions</span>
756
+ </a>
757
+ </div>
758
+ </nav>
759
+
760
+ <div class="sidebar-footer">
761
+ <div class="progress-label">
762
+ <span>Progression</span>
763
+ <span id="progress-text">0%</span>
764
+ </div>
765
+ <div class="progress-bar">
766
+ <div class="progress-fill" id="progress-fill" style="width: 0%"></div>
767
+ </div>
768
+ </div>
769
+ </aside>
770
+
771
+ <!-- Main Content -->
772
+ <main class="main-content">
773
+ <!-- Course Hero -->
774
+ <div class="course-hero scroll-animate">
775
+ <div class="course-hero-badge">
776
+ <div class="dot"></div>
777
+ <span>Pret a executer sur Google Colab</span>
778
+ </div>
779
+ <h1 class="course-hero-title">
780
+ Cours de <span class="gradient-text">Machine Learning</span>
781
+ </h1>
782
+ <p class="course-hero-subtitle">
783
+ Formation complete couvrant les algorithmes fondamentaux jusqu'aux techniques avancees.
784
+ </p>
785
+ <div class="course-hero-stats">
786
+ <div class="course-hero-stat">
787
+ <div class="course-hero-stat-value">8</div>
788
+ <div class="course-hero-stat-label">Chapitres</div>
789
+ </div>
790
+ <div class="course-hero-stat">
791
+ <div class="course-hero-stat-value">25+</div>
792
+ <div class="course-hero-stat-label">Equations</div>
793
+ </div>
794
+ <div class="course-hero-stat">
795
+ <div class="course-hero-stat-value">50+</div>
796
+ <div class="course-hero-stat-label">Exemples de code</div>
797
+ </div>
798
+ </div>
799
+ </div>
800
+
801
+ <!-- Section 1: Introduction -->
802
+ <section class="section" id="intro">
803
+ <div class="section-header scroll-animate">
804
+ <div class="section-badge">Partie 1 · 20 min</div>
805
+ <h2 class="section-title">
806
+ <small>Fondamentaux</small>
807
+ Qu'est-ce que le Machine Learning ?
808
+ </h2>
809
+ </div>
810
+
811
+ <div class="section-content scroll-animate">
812
+ <p>
813
+ Le <strong>Machine Learning (ML)</strong> est une branche de l'intelligence artificielle
814
+ qui permet aux machines d'apprendre a partir de donnees <em>sans etre explicitement programmees</em>
815
+ pour chaque tache. Au lieu de coder des regles a la main, on montre des exemples au modele
816
+ et il decouvre lui-meme les patterns.
817
+ </p>
818
+
819
+ <div class="callout callout-info scroll-animate">
820
+ <div class="callout-icon">[i]</div>
821
+ <div class="callout-content">
822
+ <div class="callout-title">Idee fondamentale</div>
823
+ <div class="callout-text">
824
+ On cherche a approximer une fonction inconnue $f$ telle que $\hat{y} = f(x_1, x_2, \ldots, x_n)$.
825
+ Le modele ML apprend cette fonction a partir d'exemples $(x, y)$ connus.
826
+ </div>
827
+ </div>
828
+ </div>
829
+
830
+ <h3 style="font-size: 1.2rem; font-weight: 600; color: var(--text-primary); margin: var(--space-xl) 0 var(--space-md);">
831
+ Types d'apprentissage
832
+ </h3>
833
+
834
+ <div class="cards-grid scroll-animate">
835
+ <div class="info-card">
836
+ <div class="info-card-icon">S</div>
837
+ <h4 class="info-card-title">Supervise</h4>
838
+ <p class="info-card-text">Donnees labellisees $(x, y)$ : regression et classification.</p>
839
+ <span class="info-card-tag">Predictions</span>
840
+ </div>
841
+ <div class="info-card">
842
+ <div class="info-card-icon">N</div>
843
+ <h4 class="info-card-title">Non supervise</h4>
844
+ <p class="info-card-text">Pas de labels : clustering, reduction de dimension.</p>
845
+ <span class="info-card-tag">Patterns</span>
846
+ </div>
847
+ <div class="info-card">
848
+ <div class="info-card-icon">R</div>
849
+ <h4 class="info-card-title">Par renforcement</h4>
850
+ <p class="info-card-text">Agent apprend via actions-recompenses.</p>
851
+ <span class="info-card-tag">Strategies</span>
852
+ </div>
853
+ </div>
854
+
855
+ <h3 style="font-size: 1.2rem; font-weight: 600; color: var(--text-primary); margin: var(--space-xl) 0 var(--space-md);">
856
+ Pipeline ML typique
857
+ </h3>
858
+
859
+ <div class="pipeline scroll-animate">
860
+ <div class="pipeline-step">
861
+ <div class="pipeline-num">1</div>
862
+ <div class="pipeline-label">Donnees</div>
863
+ <div class="pipeline-desc">Collecte & nettoyage</div>
864
+ </div>
865
+ <div class="pipeline-step">
866
+ <div class="pipeline-num">2</div>
867
+ <div class="pipeline-label">Features</div>
868
+ <div class="pipeline-desc">Engineering</div>
869
+ </div>
870
+ <div class="pipeline-step">
871
+ <div class="pipeline-num">3</div>
872
+ <div class="pipeline-label">Split</div>
873
+ <div class="pipeline-desc">Train / Test</div>
874
+ </div>
875
+ <div class="pipeline-step">
876
+ <div class="pipeline-num">4</div>
877
+ <div class="pipeline-label">Modele</div>
878
+ <div class="pipeline-desc">Entrainement</div>
879
+ </div>
880
+ <div class="pipeline-step">
881
+ <div class="pipeline-num">5</div>
882
+ <div class="pipeline-label">Evaluation</div>
883
+ <div class="pipeline-desc">Metriques</div>
884
+ </div>
885
+ <div class="pipeline-step">
886
+ <div class="pipeline-num">6</div>
887
+ <div class="pipeline-label">Production</div>
888
+ <div class="pipeline-desc">Deploiement</div>
889
+ </div>
890
+ </div>
891
+ </div>
892
+ </section>
893
+
894
+ <!-- Section 2: Regression Lineaire -->
895
+ <section class="section" id="regression">
896
+ <div class="section-header scroll-animate">
897
+ <div class="section-badge">Partie 2 · 25 min</div>
898
+ <h2 class="section-title">
899
+ <small>Algorithmes de base</small>
900
+ Regression Lineaire
901
+ </h2>
902
+ </div>
903
+
904
+ <div class="section-content scroll-animate">
905
+ <p>
906
+ La <strong>regression lineaire</strong> modelise la relation entre les features et la cible
907
+ par une fonction affine. C'est l'algorithme le plus simple mais souvent tres efficace
908
+ comme baseline.
909
+ </p>
910
+
911
+ <div class="equation-block">
912
+ $$\hat{y} = w_0 + w_1 x_1 + w_2 x_2 + \cdots + w_n x_n = \mathbf{w}^T \mathbf{x}$$
913
+ <span class="equation-label">Modele lineaire avec coefficients $\mathbf{w}$</span>
914
+ </div>
915
+
916
+ <p>
917
+ L'objectif est de minimiser l'erreur quadratique moyenne (MSE) :
918
+ </p>
919
+
920
+ <div class="equation-block">
921
+ $$\text{MSE} = \frac{1}{m} \sum_{i=1}^{m} (y_i - \hat{y}_i)^2$$
922
+ <span class="equation-label">Fonction de cout : moyenne des erreurs quadratiques</span>
923
+ </div>
924
+
925
+ <div class="callout callout-info scroll-animate">
926
+ <div class="callout-icon">[i]</div>
927
+ <div class="callout-content">
928
+ <div class="callout-title">Solution analytique</div>
929
+ <div class="callout-text">
930
+ La regression lineaire admet une solution fermee :
931
+ $\mathbf{w}^* = (X^T X)^{-1} X^T Y$. Pas besoin d'iterations !
932
+ </div>
933
+ </div>
934
+ </div>
935
+
936
+ <div class="comparison-grid scroll-animate">
937
+ <div class="comparison-box">
938
+ <h4>[+] Avantages</h4>
939
+ <ul>
940
+ <li>Tres rapide a entrainer</li>
941
+ <li>Interpretable (coefficients)</li>
942
+ <li>Pas d'hyperparametres</li>
943
+ <li>Excellent baseline</li>
944
+ </ul>
945
+ </div>
946
+ <div class="comparison-box">
947
+ <h4>[-] Limitations</h4>
948
+ <ul>
949
+ <li>Relation lineaire uniquement</li>
950
+ <li>Sensible aux outliers</li>
951
+ <li>Performance decroit en haute dimension</li>
952
+ </ul>
953
+ </div>
954
+ </div>
955
+ </div>
956
+ </section>
957
+
958
+ <!-- Section 3: Regression Logistique -->
959
+ <section class="section" id="logistic">
960
+ <div class="section-header scroll-animate">
961
+ <div class="section-badge">Partie 3 · 20 min</div>
962
+ <h2 class="section-title">
963
+ <small>Classification</small>
964
+ Regression Logistique
965
+ </h2>
966
+ </div>
967
+
968
+ <div class="section-content scroll-animate">
969
+ <p>
970
+ Malgre son nom, la <strong>regression logistique</strong> est un algorithme de <em>classification</em>.
971
+ Elle predit la probabilite d'appartenance a une classe en utilisant la fonction sigmoide.
972
+ </p>
973
+
974
+ <div class="equation-block">
975
+ $$P(y=1|\mathbf{x}) = \sigma(\mathbf{w}^T \mathbf{x}) = \frac{1}{1 + e^{-\mathbf{w}^T \mathbf{x}}}$$
976
+ <span class="equation-label">Fonction sigmoide pour la classification binaire</span>
977
+ </div>
978
+
979
+ <div class="callout callout-success scroll-animate">
980
+ <div class="callout-icon">[v]</div>
981
+ <div class="callout-content">
982
+ <div class="callout-title">Cas d'usage : Dataset Titanic</div>
983
+ <div class="callout-text">
984
+ Predire la survie des passagers du Titanic a partir de leur age, sexe,
985
+ classe de billet, etc. Un classique du ML pour debuter !
986
+ </div>
987
+ </div>
988
+ </div>
989
+ </div>
990
+ </section>
991
+
992
+ <!-- Section 4: Random Forest -->
993
+ <section class="section" id="randomforest">
994
+ <div class="section-header scroll-animate">
995
+ <div class="section-badge">Partie 4 · 30 min</div>
996
+ <h2 class="section-title">
997
+ <small>Ensemble Learning</small>
998
+ Random Forest
999
+ </h2>
1000
+ </div>
1001
+
1002
+ <div class="section-content scroll-animate">
1003
+ <p>
1004
+ <strong>Random Forest</strong> est un ensemble d'arbres de decision qui votent pour predire.
1005
+ C'est l'un des algorithmes les plus populaires en ML applique : performant, robuste,
1006
+ peu sensible au tuning.
1007
+ </p>
1008
+
1009
+ <h3 style="font-size: 1.2rem; font-weight: 600; color: var(--text-primary); margin: var(--space-xl) 0 var(--space-md);">
1010
+ Algorithm : Bagging + Random Splits
1011
+ </h3>
1012
+
1013
+ <div class="pipeline scroll-animate">
1014
+ <div class="pipeline-step">
1015
+ <div class="pipeline-num">1</div>
1016
+ <div class="pipeline-label">Bootstrap</div>
1017
+ <div class="pipeline-desc">Echantillons aleatoires</div>
1018
+ </div>
1019
+ <div class="pipeline-step">
1020
+ <div class="pipeline-num">2</div>
1021
+ <div class="pipeline-label">Splits</div>
1022
+ <div class="pipeline-desc">Features aleatoires</div>
1023
+ </div>
1024
+ <div class="pipeline-step">
1025
+ <div class="pipeline-num">3</div>
1026
+ <div class="pipeline-label">Arbres</div>
1027
+ <div class="pipeline-desc">N arbres independants</div>
1028
+ </div>
1029
+ <div class="pipeline-step">
1030
+ <div class="pipeline-num">4</div>
1031
+ <div class="pipeline-label">Vote</div>
1032
+ <div class="pipeline-desc">Moyenne ou mode</div>
1033
+ </div>
1034
+ </div>
1035
+
1036
+ <div class="metric-row scroll-animate">
1037
+ <div class="metric-card">
1038
+ <div class="metric-name">n_estimators</div>
1039
+ <div class="metric-formula">100 - 500</div>
1040
+ <div class="metric-desc">Nombre d'arbres</div>
1041
+ </div>
1042
+ <div class="metric-card">
1043
+ <div class="metric-name">max_depth</div>
1044
+ <div class="metric-formula">10 - 30</div>
1045
+ <div class="metric-desc">Profondeur max</div>
1046
+ </div>
1047
+ <div class="metric-card">
1048
+ <div class="metric-name">min_samples_split</div>
1049
+ <div class="metric-formula">2 - 10</div>
1050
+ <div class="metric-desc">Min pour splitter</div>
1051
+ </div>
1052
+ </div>
1053
+
1054
+ <div class="callout callout-success scroll-animate">
1055
+ <div class="callout-icon">[*]</div>
1056
+ <div class="callout-content">
1057
+ <div class="callout-title">Feature Importance</div>
1058
+ <div class="callout-text">
1059
+ Random Forest fournit automatiquement l'importance de chaque feature,
1060
+ ce qui aide a comprendre quelles variables influencent le plus les predictions.
1061
+ </div>
1062
+ </div>
1063
+ </div>
1064
+ </div>
1065
+ </section>
1066
+
1067
+ <!-- Section 5: Neural Networks -->
1068
+ <section class="section" id="neuralnets">
1069
+ <div class="section-header scroll-animate">
1070
+ <div class="section-badge">Partie 5 · 35 min</div>
1071
+ <h2 class="section-title">
1072
+ <small>Deep Learning</small>
1073
+ Reseaux de Neurones
1074
+ </h2>
1075
+ </div>
1076
+
1077
+ <div class="section-content scroll-animate">
1078
+ <p>
1079
+ Les <strong>reseaux de neurones</strong> sont inspires du cerveau humain : des couches de neurones
1080
+ interconnectes executent des transformations non-lineaires. Ils excellent pour les patterns complexes.
1081
+ </p>
1082
+
1083
+ <h3 style="font-size: 1.2rem; font-weight: 600; color: var(--text-primary); margin: var(--space-xl) 0 var(--space-md);">
1084
+ Fonctionnement : Forward + Backprop
1085
+ </h3>
1086
+
1087
+ <div class="cards-grid scroll-animate">
1088
+ <div class="info-card">
1089
+ <div class="info-card-icon">F</div>
1090
+ <h4 class="info-card-title">Forward Pass</h4>
1091
+ <p class="info-card-text">Donnees traversent les couches : $\mathbf{h}_1 = \sigma(W_1 \mathbf{x} + b_1)$</p>
1092
+ </div>
1093
+ <div class="info-card">
1094
+ <div class="info-card-icon">L</div>
1095
+ <h4 class="info-card-title">Loss Computation</h4>
1096
+ <p class="info-card-text">Compare prediction vs realite : $L = \frac{1}{m} \sum (y - \hat{y})^2$</p>
1097
+ </div>
1098
+ <div class="info-card">
1099
+ <div class="info-card-icon">B</div>
1100
+ <h4 class="info-card-title">Backpropagation</h4>
1101
+ <p class="info-card-text">Calcule les gradients via la chaine de derivation</p>
1102
+ </div>
1103
+ <div class="info-card">
1104
+ <div class="info-card-icon">G</div>
1105
+ <h4 class="info-card-title">Gradient Descent</h4>
1106
+ <p class="info-card-text">Met a jour les poids : $W \leftarrow W - \alpha \nabla_W L$</p>
1107
+ </div>
1108
+ </div>
1109
+
1110
+ <h3 style="font-size: 1.2rem; font-weight: 600; color: var(--text-primary); margin: var(--space-xl) 0 var(--space-md);">
1111
+ Fonctions d'activation
1112
+ </h3>
1113
+
1114
+ <div class="metric-row scroll-animate">
1115
+ <div class="metric-card">
1116
+ <div class="metric-name">ReLU</div>
1117
+ <div class="metric-formula">$f(x) = \max(0, x)$</div>
1118
+ <div class="metric-desc">Couches cachees</div>
1119
+ </div>
1120
+ <div class="metric-card">
1121
+ <div class="metric-name">Sigmoid</div>
1122
+ <div class="metric-formula">$f(x) = \frac{1}{1 + e^{-x}}$</div>
1123
+ <div class="metric-desc">Classification binaire</div>
1124
+ </div>
1125
+ <div class="metric-card">
1126
+ <div class="metric-name">Softmax</div>
1127
+ <div class="metric-formula">$f(x_i) = \frac{e^{x_i}}{\sum_j e^{x_j}}$</div>
1128
+ <div class="metric-desc">Classification multi-classe</div>
1129
+ </div>
1130
+ </div>
1131
+ </div>
1132
+ </section>
1133
+
1134
+ <!-- Section 6: LSTM -->
1135
+ <section class="section" id="lstm">
1136
+ <div class="section-header scroll-animate">
1137
+ <div class="section-badge">Partie 6 · 30 min</div>
1138
+ <h2 class="section-title">
1139
+ <small>Series Temporelles</small>
1140
+ LSTM & Reseaux Recurrents
1141
+ </h2>
1142
+ </div>
1143
+
1144
+ <div class="section-content scroll-animate">
1145
+ <p>
1146
+ <strong>LSTM (Long Short-Term Memory)</strong> est un type de reseau neuronal pour series temporelles.
1147
+ Il peut "retenir" l'information sur de longues periodes — crucial pour les predictions temporelles.
1148
+ </p>
1149
+
1150
+ <div class="callout callout-warning scroll-animate">
1151
+ <div class="callout-icon">[!]</div>
1152
+ <div class="callout-content">
1153
+ <div class="callout-title">Probleme des RNN vanilla</div>
1154
+ <div class="callout-text">
1155
+ Les gradients disparaissent (vanishing) ou explosent (exploding) sur de longues sequences.
1156
+ Le LSTM resout ce probleme avec son <strong>cell state</strong>.
1157
+ </div>
1158
+ </div>
1159
+ </div>
1160
+
1161
+ <h3 style="font-size: 1.2rem; font-weight: 600; color: var(--text-primary); margin: var(--space-xl) 0 var(--space-md);">
1162
+ Les trois portes du LSTM
1163
+ </h3>
1164
+
1165
+ <div class="metric-row scroll-animate">
1166
+ <div class="metric-card">
1167
+ <div class="metric-name">Forget Gate</div>
1168
+ <div class="metric-formula">$f_t = \sigma(W_f [h_{t-1}, x_t] + b_f)$</div>
1169
+ <div class="metric-desc">Quoi oublier ?</div>
1170
+ </div>
1171
+ <div class="metric-card">
1172
+ <div class="metric-name">Input Gate</div>
1173
+ <div class="metric-formula">$i_t = \sigma(W_i [h_{t-1}, x_t] + b_i)$</div>
1174
+ <div class="metric-desc">Quoi ajouter ?</div>
1175
+ </div>
1176
+ <div class="metric-card">
1177
+ <div class="metric-name">Output Gate</div>
1178
+ <div class="metric-formula">$o_t = \sigma(W_o [h_{t-1}, x_t] + b_o)$</div>
1179
+ <div class="metric-desc">Quoi exposer ?</div>
1180
+ </div>
1181
+ </div>
1182
+
1183
+ <div class="callout callout-info scroll-animate">
1184
+ <div class="callout-icon">[i]</div>
1185
+ <div class="callout-content">
1186
+ <div class="callout-title">Cas d'usage</div>
1187
+ <div class="callout-text">
1188
+ Prediction de prix boursiers, meteo, consommation energetique,
1189
+ traitement du langage naturel (NLP)...
1190
+ </div>
1191
+ </div>
1192
+ </div>
1193
+ </div>
1194
+ </section>
1195
+
1196
+ <!-- Section 7: Metriques -->
1197
+ <section class="section" id="metrics">
1198
+ <div class="section-header scroll-animate">
1199
+ <div class="section-badge">Partie 7 · 25 min</div>
1200
+ <h2 class="section-title">
1201
+ <small>Evaluation</small>
1202
+ Metriques de Performance
1203
+ </h2>
1204
+ </div>
1205
+
1206
+ <div class="section-content scroll-animate">
1207
+ <p>
1208
+ Evaluer correctement un modele est crucial. Les bonnes metriques dependent du type de probleme
1209
+ (regression vs classification) et des objectifs metier.
1210
+ </p>
1211
+
1212
+ <h3 style="font-size: 1.2rem; font-weight: 600; color: var(--text-primary); margin: var(--space-xl) 0 var(--space-md);">
1213
+ Regression
1214
+ </h3>
1215
+
1216
+ <div class="metric-row scroll-animate">
1217
+ <div class="metric-card">
1218
+ <div class="metric-name">MAE</div>
1219
+ <div class="metric-formula">$\frac{1}{n}\sum|y_i - \hat{y}_i|$</div>
1220
+ <div class="metric-desc">Robuste aux outliers</div>
1221
+ </div>
1222
+ <div class="metric-card">
1223
+ <div class="metric-name">RMSE</div>
1224
+ <div class="metric-formula">$\sqrt{\frac{1}{n}\sum(y_i - \hat{y}_i)^2}$</div>
1225
+ <div class="metric-desc">Penalise les grandes erreurs</div>
1226
+ </div>
1227
+ <div class="metric-card">
1228
+ <div class="metric-name">R2</div>
1229
+ <div class="metric-formula">$1 - \frac{SS_{res}}{SS_{tot}}$</div>
1230
+ <div class="metric-desc">% variance expliquee</div>
1231
+ </div>
1232
+ </div>
1233
+
1234
+ <h3 style="font-size: 1.2rem; font-weight: 600; color: var(--text-primary); margin: var(--space-xl) 0 var(--space-md);">
1235
+ Classification
1236
+ </h3>
1237
+
1238
+ <div class="table-container scroll-animate">
1239
+ <table>
1240
+ <thead>
1241
+ <tr>
1242
+ <th>Metrique</th>
1243
+ <th>Formule</th>
1244
+ <th>Usage</th>
1245
+ </tr>
1246
+ </thead>
1247
+ <tbody>
1248
+ <tr>
1249
+ <td><strong>Accuracy</strong></td>
1250
+ <td>$(TP + TN) / Total$</td>
1251
+ <td>Classes equilibrees</td>
1252
+ </tr>
1253
+ <tr>
1254
+ <td><strong>Precision</strong></td>
1255
+ <td>$TP / (TP + FP)$</td>
1256
+ <td>Minimiser faux positifs</td>
1257
+ </tr>
1258
+ <tr>
1259
+ <td><strong>Recall</strong></td>
1260
+ <td>$TP / (TP + FN)$</td>
1261
+ <td>Minimiser faux negatifs</td>
1262
+ </tr>
1263
+ <tr>
1264
+ <td><strong>F1-Score</strong></td>
1265
+ <td>$2 \cdot \frac{P \cdot R}{P + R}$</td>
1266
+ <td>Classes desequilibrees</td>
1267
+ </tr>
1268
+ </tbody>
1269
+ </table>
1270
+ </div>
1271
+ </div>
1272
+ </section>
1273
+
1274
+ <!-- Section 8: Optimisation -->
1275
+ <section class="section" id="optimization">
1276
+ <div class="section-header scroll-animate">
1277
+ <div class="section-badge">Partie 8 · 20 min</div>
1278
+ <h2 class="section-title">
1279
+ <small>Amelioration</small>
1280
+ Optimisation & Regularisation
1281
+ </h2>
1282
+ </div>
1283
+
1284
+ <div class="section-content scroll-animate">
1285
+ <p>
1286
+ Pour eviter le <strong>surapprentissage (overfitting)</strong> et ameliorer la generalisation,
1287
+ plusieurs techniques existent.
1288
+ </p>
1289
+
1290
+ <div class="cards-grid scroll-animate">
1291
+ <div class="info-card">
1292
+ <div class="info-card-icon">D</div>
1293
+ <h4 class="info-card-title">Dropout</h4>
1294
+ <p class="info-card-text">Desactive aleatoirement des neurones pendant l'entrainement.</p>
1295
+ </div>
1296
+ <div class="info-card">
1297
+ <div class="info-card-icon">E</div>
1298
+ <h4 class="info-card-title">Early Stopping</h4>
1299
+ <p class="info-card-text">Arrete l'entrainement quand la validation stagne.</p>
1300
+ </div>
1301
+ <div class="info-card">
1302
+ <div class="info-card-icon">L</div>
1303
+ <h4 class="info-card-title">L2 Regularization</h4>
1304
+ <p class="info-card-text">Penalise les grands poids : $L_{total} = L_{data} + \lambda \sum w^2$</p>
1305
+ </div>
1306
+ <div class="info-card">
1307
+ <div class="info-card-icon">C</div>
1308
+ <h4 class="info-card-title">Cross-Validation</h4>
1309
+ <p class="info-card-text">K-fold pour une evaluation plus robuste.</p>
1310
+ </div>
1311
+ </div>
1312
+
1313
+ <div class="callout callout-tip scroll-animate">
1314
+ <div class="callout-icon">[*]</div>
1315
+ <div class="callout-content">
1316
+ <div class="callout-title">Regle d'or</div>
1317
+ <div class="callout-text">
1318
+ Toujours comparer les metriques sur <strong>train</strong> ET <strong>test</strong>.
1319
+ Un grand ecart = overfitting. Objectif : R2 train ≈ R2 test.
1320
+ </div>
1321
+ </div>
1322
+ </div>
1323
+ </div>
1324
+ </section>
1325
+
1326
+ <!-- Author Footer -->
1327
+ <footer class="author-footer" style="margin-top: var(--space-3xl);">
1328
+ <div class="author-info">
1329
+ <a href="mailto:imadmaalouf02@gmail.com" class="author-link">
1330
+ <svg viewBox="0 0 24 24"><path d="M20 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 4l-8 5-8-5V6l8 5 8-5v2z"/></svg>
1331
+ imadmaalouf02@gmail.com
1332
+ </a>
1333
+ <a href="https://github.com/imadmaalouf02" target="_blank" class="author-link">
1334
+ <svg viewBox="0 0 24 24"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/></svg>
1335
+ GitHub
1336
+ </a>
1337
+ <a href="https://huggingface.co/spaces/MAALOOUF/ML_Training" target="_blank" class="author-link">
1338
+ <svg viewBox="0 0 24 24"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 17.93c-3.95-.49-7-3.85-7-7.93 0-.62.08-1.21.21-1.79L9 15v1c0 1.1.9 2 2 2v1.93zm6.9-2.54c-.26-.81-1-1.39-1.9-1.39h-1v-3c0-.55-.45-1-1-1H8v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41c2.93 1.19 5 4.06 5 7.41 0 2.08-.8 3.97-2.1 5.39z"/></svg>
1339
+ Hugging Face Space
1340
+ </a>
1341
+ </div>
1342
+ </footer>
1343
+
1344
+ <!-- Footer -->
1345
+ <footer class="footer" style="margin-top: 0;">
1346
+ <p class="footer-text">
1347
+ ML Academy — Cours de Machine Learning —
1348
+ <span class="footer-brand">GE-MCI 4A</span> — 2025/2026
1349
+ </p>
1350
+ <p class="footer-text" style="margin-top: var(--space-sm); font-size: 0.75rem; color: var(--text-muted);">
1351
+ Formateur : Imad Maalouf
1352
+ </p>
1353
+ </footer>
1354
+ </main>
1355
+ </div>
1356
+
1357
+ <!-- Back to Top -->
1358
+ <button class="back-to-top" id="backToTop" onclick="scrollToTop()">^</button>
1359
+
1360
+ <!-- Scripts -->
1361
+ <script src="js/shared.js"></script>
1362
+ <script>
1363
+ // Scroll animations
1364
+ const observerOptions = {
1365
+ threshold: 0.1,
1366
+ rootMargin: '0px 0px -50px 0px'
1367
+ };
1368
+
1369
+ const observer = new IntersectionObserver((entries) => {
1370
+ entries.forEach(entry => {
1371
+ if (entry.isIntersecting) {
1372
+ entry.target.classList.add('visible');
1373
+ }
1374
+ });
1375
+ }, observerOptions);
1376
+
1377
+ document.querySelectorAll('.scroll-animate').forEach(el => {
1378
+ observer.observe(el);
1379
+ });
1380
+
1381
+ // Active nav item on scroll
1382
+ const sections = document.querySelectorAll('.section');
1383
+ const navItems = document.querySelectorAll('.nav-item');
1384
+
1385
+ window.addEventListener('scroll', () => {
1386
+ let current = '';
1387
+ sections.forEach(section => {
1388
+ const sectionTop = section.offsetTop;
1389
+ const sectionHeight = section.clientHeight;
1390
+ if (scrollY >= sectionTop - 200) {
1391
+ current = section.getAttribute('id');
1392
+ }
1393
+ });
1394
+
1395
+ navItems.forEach(item => {
1396
+ item.classList.remove('active');
1397
+ if (item.getAttribute('href') === `#${current}`) {
1398
+ item.classList.add('active');
1399
+ }
1400
+ });
1401
+
1402
+ // Update progress
1403
+ const progress = Math.min(100, Math.round((scrollY / (document.body.scrollHeight - window.innerHeight)) * 100));
1404
+ document.getElementById('progress-fill').style.width = `${progress}%`;
1405
+ document.getElementById('progress-text').textContent = `${progress}%`;
1406
+
1407
+ // Back to top button
1408
+ const backToTop = document.getElementById('backToTop');
1409
+ if (scrollY > 500) {
1410
+ backToTop.classList.add('visible');
1411
+ } else {
1412
+ backToTop.classList.remove('visible');
1413
+ }
1414
+ });
1415
+
1416
+ function scrollToTop() {
1417
+ window.scrollTo({ top: 0, behavior: 'smooth' });
1418
+ }
1419
+ </script>
1420
+ </body>
1421
+ </html>
cours.pdf ADDED
Binary file (14.2 kB). View file
 
css/shared.css ADDED
@@ -0,0 +1,944 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* ═══════════════════════════════════════════════════════════════════════════
2
+ ML PLATFORM — SHARED STYLES
3
+ Formation Machine Learning Professionnelle
4
+ Design: Dark Modern avec animations CSS
5
+ ═══════════════════════════════════════════════════════════════════════════ */
6
+
7
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap');
8
+
9
+ /* ═══════════════════════════════════════════════════════════════════════════
10
+ VARIABLES CSS
11
+ ═══════════════════════════════════════════════════════════════════════════ */
12
+ :root {
13
+ /* Couleurs principales */
14
+ --primary: #6366f1;
15
+ --primary-light: #818cf8;
16
+ --primary-dark: #4f46e5;
17
+ --secondary: #06b6d4;
18
+ --accent: #f59e0b;
19
+ --success: #10b981;
20
+ --warning: #f97316;
21
+ --danger: #ef4444;
22
+
23
+ /* Couleurs de fond */
24
+ --bg-primary: #0f0f1a;
25
+ --bg-secondary: #1a1a2e;
26
+ --bg-tertiary: #252542;
27
+ --bg-card: #16162a;
28
+ --bg-hover: #1e1e3a;
29
+
30
+ /* Couleurs de texte */
31
+ --text-primary: #f8fafc;
32
+ --text-secondary: #94a3b8;
33
+ --text-muted: #64748b;
34
+ --text-accent: #818cf8;
35
+
36
+ /* Bordures */
37
+ --border-color: #2d2d4a;
38
+ --border-light: #3d3d5c;
39
+
40
+ /* Ombres */
41
+ --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3);
42
+ --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.4), 0 2px 4px -1px rgba(0, 0, 0, 0.2);
43
+ --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.5), 0 4px 6px -2px rgba(0, 0, 0, 0.3);
44
+ --shadow-glow: 0 0 20px rgba(99, 102, 241, 0.3);
45
+ --shadow-glow-strong: 0 0 40px rgba(99, 102, 241, 0.5);
46
+
47
+ /* Rayons */
48
+ --radius-sm: 6px;
49
+ --radius-md: 10px;
50
+ --radius-lg: 16px;
51
+ --radius-xl: 24px;
52
+
53
+ /* Transitions */
54
+ --transition-fast: 0.15s ease;
55
+ --transition-base: 0.25s ease;
56
+ --transition-slow: 0.4s ease;
57
+
58
+ /* Espacements */
59
+ --space-xs: 0.25rem;
60
+ --space-sm: 0.5rem;
61
+ --space-md: 1rem;
62
+ --space-lg: 1.5rem;
63
+ --space-xl: 2rem;
64
+ --space-2xl: 3rem;
65
+ --space-3xl: 4rem;
66
+
67
+ /* Sidebar */
68
+ --sidebar-width: 280px;
69
+ --navbar-height: 64px;
70
+ }
71
+
72
+ /* ═══════════════════════════════════════════════════════════════════════════
73
+ RESET & BASE
74
+ ═══════════════════════════════════════════════════════════════════════════ */
75
+ *, *::before, *::after {
76
+ box-sizing: border-box;
77
+ margin: 0;
78
+ padding: 0;
79
+ }
80
+
81
+ html {
82
+ scroll-behavior: smooth;
83
+ font-size: 16px;
84
+ }
85
+
86
+ body {
87
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
88
+ background: var(--bg-primary);
89
+ color: var(--text-primary);
90
+ line-height: 1.6;
91
+ min-height: 100vh;
92
+ overflow-x: hidden;
93
+ }
94
+
95
+ /* ═══════════════════════════════════════════════════════════════════════════
96
+ ANIMATIONS KEYFRAMES
97
+ ═══════════════════════════════════════════════════════════════════════════ */
98
+ @keyframes fadeIn {
99
+ from { opacity: 0; }
100
+ to { opacity: 1; }
101
+ }
102
+
103
+ @keyframes fadeInUp {
104
+ from {
105
+ opacity: 0;
106
+ transform: translateY(30px);
107
+ }
108
+ to {
109
+ opacity: 1;
110
+ transform: translateY(0);
111
+ }
112
+ }
113
+
114
+ @keyframes fadeInDown {
115
+ from {
116
+ opacity: 0;
117
+ transform: translateY(-20px);
118
+ }
119
+ to {
120
+ opacity: 1;
121
+ transform: translateY(0);
122
+ }
123
+ }
124
+
125
+ @keyframes fadeInLeft {
126
+ from {
127
+ opacity: 0;
128
+ transform: translateX(-30px);
129
+ }
130
+ to {
131
+ opacity: 1;
132
+ transform: translateX(0);
133
+ }
134
+ }
135
+
136
+ @keyframes fadeInRight {
137
+ from {
138
+ opacity: 0;
139
+ transform: translateX(30px);
140
+ }
141
+ to {
142
+ opacity: 1;
143
+ transform: translateX(0);
144
+ }
145
+ }
146
+
147
+ @keyframes scaleIn {
148
+ from {
149
+ opacity: 0;
150
+ transform: scale(0.9);
151
+ }
152
+ to {
153
+ opacity: 1;
154
+ transform: scale(1);
155
+ }
156
+ }
157
+
158
+ @keyframes slideInUp {
159
+ from {
160
+ transform: translateY(100%);
161
+ }
162
+ to {
163
+ transform: translateY(0);
164
+ }
165
+ }
166
+
167
+ @keyframes pulse {
168
+ 0%, 100% {
169
+ opacity: 1;
170
+ transform: scale(1);
171
+ }
172
+ 50% {
173
+ opacity: 0.7;
174
+ transform: scale(1.05);
175
+ }
176
+ }
177
+
178
+ @keyframes glow {
179
+ 0%, 100% {
180
+ box-shadow: 0 0 5px var(--primary), 0 0 10px var(--primary), 0 0 15px var(--primary);
181
+ }
182
+ 50% {
183
+ box-shadow: 0 0 10px var(--primary), 0 0 20px var(--primary), 0 0 30px var(--primary);
184
+ }
185
+ }
186
+
187
+ @keyframes shimmer {
188
+ 0% { background-position: -200% 0; }
189
+ 100% { background-position: 200% 0; }
190
+ }
191
+
192
+ @keyframes float {
193
+ 0%, 100% { transform: translateY(0); }
194
+ 50% { transform: translateY(-10px); }
195
+ }
196
+
197
+ @keyframes rotate {
198
+ from { transform: rotate(0deg); }
199
+ to { transform: rotate(360deg); }
200
+ }
201
+
202
+ @keyframes bounce {
203
+ 0%, 100% { transform: translateY(0); }
204
+ 50% { transform: translateY(-5px); }
205
+ }
206
+
207
+ @keyframes typing {
208
+ from { width: 0; }
209
+ to { width: 100%; }
210
+ }
211
+
212
+ @keyframes blink {
213
+ 0%, 100% { opacity: 1; }
214
+ 50% { opacity: 0; }
215
+ }
216
+
217
+ @keyframes gradientShift {
218
+ 0% { background-position: 0% 50%; }
219
+ 50% { background-position: 100% 50%; }
220
+ 100% { background-position: 0% 50%; }
221
+ }
222
+
223
+ @keyframes particle {
224
+ 0% {
225
+ transform: translateY(100vh) rotate(0deg);
226
+ opacity: 0;
227
+ }
228
+ 10% { opacity: 1; }
229
+ 90% { opacity: 1; }
230
+ 100% {
231
+ transform: translateY(-100vh) rotate(720deg);
232
+ opacity: 0;
233
+ }
234
+ }
235
+
236
+ @keyframes wave {
237
+ 0%, 100% { transform: translateY(0); }
238
+ 25% { transform: translateY(-5px); }
239
+ 75% { transform: translateY(5px); }
240
+ }
241
+
242
+ @keyframes progress {
243
+ from { width: 0; }
244
+ to { width: var(--progress, 100%); }
245
+ }
246
+
247
+ /* ═══════════════════════════════════════════════════════════════════════════
248
+ UTILITAIRES D'ANIMATION
249
+ ═══════════════════════════════════════════════════════════════════════════ */
250
+ .animate-fade-in { animation: fadeIn 0.6s ease forwards; }
251
+ .animate-fade-in-up { animation: fadeInUp 0.6s ease forwards; }
252
+ .animate-fade-in-down { animation: fadeInDown 0.5s ease forwards; }
253
+ .animate-fade-in-left { animation: fadeInLeft 0.5s ease forwards; }
254
+ .animate-fade-in-right { animation: fadeInRight 0.5s ease forwards; }
255
+ .animate-scale-in { animation: scaleIn 0.5s ease forwards; }
256
+ .animate-float { animation: float 3s ease-in-out infinite; }
257
+ .animate-pulse { animation: pulse 2s ease-in-out infinite; }
258
+ .animate-glow { animation: glow 2s ease-in-out infinite; }
259
+ .animate-bounce { animation: bounce 1s ease-in-out infinite; }
260
+ .animate-rotate { animation: rotate 2s linear infinite; }
261
+
262
+ /* Delays */
263
+ .delay-100 { animation-delay: 0.1s; }
264
+ .delay-200 { animation-delay: 0.2s; }
265
+ .delay-300 { animation-delay: 0.3s; }
266
+ .delay-400 { animation-delay: 0.4s; }
267
+ .delay-500 { animation-delay: 0.5s; }
268
+ .delay-600 { animation-delay: 0.6s; }
269
+ .delay-700 { animation-delay: 0.7s; }
270
+ .delay-800 { animation-delay: 0.8s; }
271
+
272
+ /* Initial states for scroll animations */
273
+ .scroll-animate {
274
+ opacity: 0;
275
+ transform: translateY(30px);
276
+ transition: opacity 0.6s ease, transform 0.6s ease;
277
+ }
278
+
279
+ .scroll-animate.visible {
280
+ opacity: 1;
281
+ transform: translateY(0);
282
+ }
283
+
284
+ /* ═══════════════════════════════════════════════════════════════════════════
285
+ NAVIGATION
286
+ ═══════════════════════════════════════════════════════════════════════════ */
287
+ .navbar {
288
+ position: fixed;
289
+ top: 0;
290
+ left: 0;
291
+ right: 0;
292
+ height: var(--navbar-height);
293
+ background: rgba(15, 15, 26, 0.85);
294
+ backdrop-filter: blur(20px);
295
+ border-bottom: 1px solid var(--border-color);
296
+ z-index: 1000;
297
+ display: flex;
298
+ align-items: center;
299
+ justify-content: space-between;
300
+ padding: 0 var(--space-xl);
301
+ animation: fadeInDown 0.5s ease;
302
+ }
303
+
304
+ .navbar-brand {
305
+ display: flex;
306
+ align-items: center;
307
+ gap: var(--space-sm);
308
+ text-decoration: none;
309
+ color: var(--text-primary);
310
+ font-weight: 700;
311
+ font-size: 1.1rem;
312
+ transition: var(--transition-base);
313
+ }
314
+
315
+ .navbar-brand:hover {
316
+ color: var(--primary-light);
317
+ }
318
+
319
+ .brand-logo {
320
+ width: 36px;
321
+ height: 36px;
322
+ background: linear-gradient(135deg, var(--primary), var(--secondary));
323
+ border-radius: var(--radius-md);
324
+ display: flex;
325
+ align-items: center;
326
+ justify-content: center;
327
+ font-size: 1.2rem;
328
+ animation: float 3s ease-in-out infinite;
329
+ }
330
+
331
+ .navbar-nav {
332
+ display: flex;
333
+ align-items: center;
334
+ gap: var(--space-xs);
335
+ }
336
+
337
+ .nav-link {
338
+ display: flex;
339
+ align-items: center;
340
+ gap: var(--space-sm);
341
+ padding: var(--space-sm) var(--space-md);
342
+ color: var(--text-secondary);
343
+ text-decoration: none;
344
+ font-size: 0.9rem;
345
+ font-weight: 500;
346
+ border-radius: var(--radius-md);
347
+ transition: all var(--transition-base);
348
+ position: relative;
349
+ overflow: hidden;
350
+ }
351
+
352
+ .nav-link::before {
353
+ content: '';
354
+ position: absolute;
355
+ bottom: 0;
356
+ left: 50%;
357
+ width: 0;
358
+ height: 2px;
359
+ background: linear-gradient(90deg, var(--primary), var(--secondary));
360
+ transition: all var(--transition-base);
361
+ transform: translateX(-50%);
362
+ }
363
+
364
+ .nav-link:hover {
365
+ color: var(--text-primary);
366
+ background: var(--bg-hover);
367
+ }
368
+
369
+ .nav-link:hover::before {
370
+ width: 60%;
371
+ }
372
+
373
+ .nav-link.active {
374
+ color: var(--primary-light);
375
+ background: rgba(99, 102, 241, 0.1);
376
+ }
377
+
378
+ .nav-link.active::before {
379
+ width: 60%;
380
+ }
381
+
382
+ .nav-badge {
383
+ display: flex;
384
+ align-items: center;
385
+ gap: var(--space-sm);
386
+ padding: var(--space-xs) var(--space-md);
387
+ background: rgba(16, 185, 129, 0.1);
388
+ border: 1px solid rgba(16, 185, 129, 0.3);
389
+ border-radius: 20px;
390
+ font-size: 0.75rem;
391
+ font-weight: 600;
392
+ color: var(--success);
393
+ font-family: 'JetBrains Mono', monospace;
394
+ }
395
+
396
+ .nav-badge .dot {
397
+ width: 6px;
398
+ height: 6px;
399
+ background: var(--success);
400
+ border-radius: 50%;
401
+ animation: pulse 2s ease-in-out infinite;
402
+ }
403
+
404
+ /* ═══════════════════════════════════════════════════════════════════════════
405
+ BOUTONS
406
+ ═══════════════════════════════════════════════════════════════════════════ */
407
+ .btn {
408
+ display: inline-flex;
409
+ align-items: center;
410
+ justify-content: center;
411
+ gap: var(--space-sm);
412
+ padding: var(--space-sm) var(--space-lg);
413
+ font-family: 'Inter', sans-serif;
414
+ font-size: 0.9rem;
415
+ font-weight: 600;
416
+ text-decoration: none;
417
+ border: none;
418
+ border-radius: var(--radius-md);
419
+ cursor: pointer;
420
+ transition: all var(--transition-base);
421
+ position: relative;
422
+ overflow: hidden;
423
+ }
424
+
425
+ .btn::before {
426
+ content: '';
427
+ position: absolute;
428
+ top: 50%;
429
+ left: 50%;
430
+ width: 0;
431
+ height: 0;
432
+ background: rgba(255, 255, 255, 0.1);
433
+ border-radius: 50%;
434
+ transform: translate(-50%, -50%);
435
+ transition: width 0.4s ease, height 0.4s ease;
436
+ }
437
+
438
+ .btn:hover::before {
439
+ width: 200%;
440
+ height: 200%;
441
+ }
442
+
443
+ .btn-primary {
444
+ background: linear-gradient(135deg, var(--primary), var(--primary-dark));
445
+ color: white;
446
+ box-shadow: 0 4px 15px rgba(99, 102, 241, 0.4);
447
+ }
448
+
449
+ .btn-primary:hover {
450
+ transform: translateY(-2px);
451
+ box-shadow: 0 6px 25px rgba(99, 102, 241, 0.5);
452
+ }
453
+
454
+ .btn-secondary {
455
+ background: var(--bg-tertiary);
456
+ color: var(--text-primary);
457
+ border: 1px solid var(--border-color);
458
+ }
459
+
460
+ .btn-secondary:hover {
461
+ background: var(--bg-hover);
462
+ border-color: var(--border-light);
463
+ transform: translateY(-2px);
464
+ }
465
+
466
+ .btn-outline {
467
+ background: transparent;
468
+ color: var(--primary-light);
469
+ border: 1px solid var(--primary);
470
+ }
471
+
472
+ .btn-outline:hover {
473
+ background: rgba(99, 102, 241, 0.1);
474
+ transform: translateY(-2px);
475
+ }
476
+
477
+ .btn-success {
478
+ background: linear-gradient(135deg, var(--success), #059669);
479
+ color: white;
480
+ box-shadow: 0 4px 15px rgba(16, 185, 129, 0.4);
481
+ }
482
+
483
+ .btn-success:hover {
484
+ transform: translateY(-2px);
485
+ box-shadow: 0 6px 25px rgba(16, 185, 129, 0.5);
486
+ }
487
+
488
+ .btn-lg {
489
+ padding: var(--space-md) var(--space-xl);
490
+ font-size: 1rem;
491
+ }
492
+
493
+ .btn-sm {
494
+ padding: var(--space-xs) var(--space-md);
495
+ font-size: 0.8rem;
496
+ }
497
+
498
+ /* ═══════════════════════════════════════════════════════════════════════════
499
+ BADGES
500
+ ═══════════════════════════════════════════════════════════════════════════ */
501
+ .badge {
502
+ display: inline-flex;
503
+ align-items: center;
504
+ gap: var(--space-xs);
505
+ padding: var(--space-xs) var(--space-sm);
506
+ font-size: 0.7rem;
507
+ font-weight: 600;
508
+ text-transform: uppercase;
509
+ letter-spacing: 0.5px;
510
+ border-radius: var(--radius-sm);
511
+ font-family: 'JetBrains Mono', monospace;
512
+ }
513
+
514
+ .badge-primary {
515
+ background: rgba(99, 102, 241, 0.15);
516
+ color: var(--primary-light);
517
+ border: 1px solid rgba(99, 102, 241, 0.3);
518
+ }
519
+
520
+ .badge-secondary {
521
+ background: rgba(6, 182, 212, 0.15);
522
+ color: var(--secondary);
523
+ border: 1px solid rgba(6, 182, 212, 0.3);
524
+ }
525
+
526
+ .badge-success {
527
+ background: rgba(16, 185, 129, 0.15);
528
+ color: var(--success);
529
+ border: 1px solid rgba(16, 185, 129, 0.3);
530
+ }
531
+
532
+ .badge-warning {
533
+ background: rgba(249, 115, 22, 0.15);
534
+ color: var(--warning);
535
+ border: 1px solid rgba(249, 115, 22, 0.3);
536
+ }
537
+
538
+ .badge-accent {
539
+ background: rgba(245, 158, 11, 0.15);
540
+ color: var(--accent);
541
+ border: 1px solid rgba(245, 158, 11, 0.3);
542
+ }
543
+
544
+ /* ════════════════════════════════════════════��══════════════════════════════
545
+ CARDS
546
+ ═══════════════════════════════════════════════════════════════════════════ */
547
+ .card {
548
+ background: var(--bg-card);
549
+ border: 1px solid var(--border-color);
550
+ border-radius: var(--radius-lg);
551
+ padding: var(--space-xl);
552
+ transition: all var(--transition-base);
553
+ position: relative;
554
+ overflow: hidden;
555
+ }
556
+
557
+ .card::before {
558
+ content: '';
559
+ position: absolute;
560
+ top: 0;
561
+ left: 0;
562
+ right: 0;
563
+ height: 3px;
564
+ background: linear-gradient(90deg, var(--primary), var(--secondary));
565
+ transform: scaleX(0);
566
+ transition: transform var(--transition-base);
567
+ }
568
+
569
+ .card:hover {
570
+ transform: translateY(-5px);
571
+ border-color: var(--border-light);
572
+ box-shadow: var(--shadow-lg), var(--shadow-glow);
573
+ }
574
+
575
+ .card:hover::before {
576
+ transform: scaleX(1);
577
+ }
578
+
579
+ .card-icon {
580
+ width: 50px;
581
+ height: 50px;
582
+ background: linear-gradient(135deg, var(--primary), var(--secondary));
583
+ border-radius: var(--radius-md);
584
+ display: flex;
585
+ align-items: center;
586
+ justify-content: center;
587
+ font-size: 1.5rem;
588
+ margin-bottom: var(--space-md);
589
+ animation: float 3s ease-in-out infinite;
590
+ }
591
+
592
+ .card-title {
593
+ font-size: 1.1rem;
594
+ font-weight: 700;
595
+ color: var(--text-primary);
596
+ margin-bottom: var(--space-sm);
597
+ }
598
+
599
+ .card-text {
600
+ font-size: 0.9rem;
601
+ color: var(--text-secondary);
602
+ line-height: 1.6;
603
+ }
604
+
605
+ /* ═══════════════════════════════════════════════════════════════════════════
606
+ CALLOUTS / ALERTS
607
+ ═══════════════════════════════════════════════════════════════════════════ */
608
+ .callout {
609
+ display: flex;
610
+ gap: var(--space-md);
611
+ padding: var(--space-lg);
612
+ border-radius: var(--radius-md);
613
+ margin: var(--space-lg) 0;
614
+ animation: fadeInUp 0.5s ease;
615
+ }
616
+
617
+ .callout-icon {
618
+ font-size: 1.5rem;
619
+ flex-shrink: 0;
620
+ }
621
+
622
+ .callout-content {
623
+ flex: 1;
624
+ }
625
+
626
+ .callout-title {
627
+ font-weight: 600;
628
+ color: var(--text-primary);
629
+ margin-bottom: var(--space-xs);
630
+ }
631
+
632
+ .callout-text {
633
+ font-size: 0.9rem;
634
+ color: var(--text-secondary);
635
+ }
636
+
637
+ .callout-info {
638
+ background: rgba(99, 102, 241, 0.1);
639
+ border: 1px solid rgba(99, 102, 241, 0.3);
640
+ }
641
+
642
+ .callout-success {
643
+ background: rgba(16, 185, 129, 0.1);
644
+ border: 1px solid rgba(16, 185, 129, 0.3);
645
+ }
646
+
647
+ .callout-warning {
648
+ background: rgba(249, 115, 22, 0.1);
649
+ border: 1px solid rgba(249, 115, 22, 0.3);
650
+ }
651
+
652
+ .callout-tip {
653
+ background: rgba(245, 158, 11, 0.1);
654
+ border: 1px solid rgba(245, 158, 11, 0.3);
655
+ }
656
+
657
+ /* ═══════════════════════════════════════════════════════════════════════════
658
+ CODE BLOCKS
659
+ ═══════════════════════════════════════════════════════════════════════════ */
660
+ .code-block {
661
+ background: #0d0d15;
662
+ border: 1px solid var(--border-color);
663
+ border-radius: var(--radius-md);
664
+ overflow: hidden;
665
+ margin: var(--space-md) 0;
666
+ animation: fadeInUp 0.5s ease;
667
+ }
668
+
669
+ .code-header {
670
+ display: flex;
671
+ align-items: center;
672
+ justify-content: space-between;
673
+ padding: var(--space-sm) var(--space-md);
674
+ background: var(--bg-tertiary);
675
+ border-bottom: 1px solid var(--border-color);
676
+ }
677
+
678
+ .code-dots {
679
+ display: flex;
680
+ gap: 6px;
681
+ }
682
+
683
+ .code-dot {
684
+ width: 10px;
685
+ height: 10px;
686
+ border-radius: 50%;
687
+ }
688
+
689
+ .code-dot.red { background: #ff5f56; }
690
+ .code-dot.yellow { background: #ffbd2e; }
691
+ .code-dot.green { background: #27c93f; }
692
+
693
+ .code-lang {
694
+ font-family: 'JetBrains Mono', monospace;
695
+ font-size: 0.7rem;
696
+ color: var(--text-muted);
697
+ text-transform: uppercase;
698
+ letter-spacing: 1px;
699
+ }
700
+
701
+ .code-block pre {
702
+ padding: var(--space-md);
703
+ overflow-x: auto;
704
+ font-family: 'JetBrains Mono', monospace;
705
+ font-size: 0.85rem;
706
+ line-height: 1.7;
707
+ color: #cdd6f4;
708
+ margin: 0;
709
+ }
710
+
711
+ /* Syntax highlighting colors */
712
+ .code-keyword { color: #cba6f7; }
713
+ .code-function { color: #89b4fa; }
714
+ .code-string { color: #a6e3a1; }
715
+ .code-comment { color: #6c7086; font-style: italic; }
716
+ .code-number { color: #fab387; }
717
+ .code-class { color: #f38ba8; }
718
+
719
+ /* ═══════════════════════════════════════════════════════════════════════════
720
+ TABLES
721
+ ════════════════════════════════���══════════════════════════════════════════ */
722
+ .table-container {
723
+ overflow-x: auto;
724
+ border-radius: var(--radius-md);
725
+ border: 1px solid var(--border-color);
726
+ margin: var(--space-lg) 0;
727
+ }
728
+
729
+ table {
730
+ width: 100%;
731
+ border-collapse: collapse;
732
+ font-size: 0.9rem;
733
+ }
734
+
735
+ th {
736
+ background: var(--bg-tertiary);
737
+ color: var(--text-secondary);
738
+ font-family: 'JetBrains Mono', monospace;
739
+ font-size: 0.75rem;
740
+ font-weight: 600;
741
+ text-transform: uppercase;
742
+ letter-spacing: 0.5px;
743
+ padding: var(--space-md);
744
+ text-align: left;
745
+ border-bottom: 1px solid var(--border-color);
746
+ }
747
+
748
+ td {
749
+ padding: var(--space-md);
750
+ border-bottom: 1px solid var(--border-color);
751
+ color: var(--text-primary);
752
+ }
753
+
754
+ tr:hover td {
755
+ background: var(--bg-hover);
756
+ }
757
+
758
+ tr:last-child td {
759
+ border-bottom: none;
760
+ }
761
+
762
+ /* ═══════════════════════════════════════════════════════════════════════════
763
+ FORMS
764
+ ═══════════════════════════════════════════════════════════════════════════ */
765
+ .form-group {
766
+ margin-bottom: var(--space-lg);
767
+ }
768
+
769
+ .form-label {
770
+ display: block;
771
+ font-size: 0.8rem;
772
+ font-weight: 600;
773
+ color: var(--text-secondary);
774
+ text-transform: uppercase;
775
+ letter-spacing: 0.5px;
776
+ margin-bottom: var(--space-sm);
777
+ font-family: 'JetBrains Mono', monospace;
778
+ }
779
+
780
+ .form-input,
781
+ .form-select,
782
+ .form-textarea {
783
+ width: 100%;
784
+ background: var(--bg-tertiary);
785
+ border: 1px solid var(--border-color);
786
+ border-radius: var(--radius-md);
787
+ color: var(--text-primary);
788
+ font-family: 'Inter', sans-serif;
789
+ font-size: 0.95rem;
790
+ padding: var(--space-sm) var(--space-md);
791
+ transition: all var(--transition-base);
792
+ }
793
+
794
+ .form-input:focus,
795
+ .form-select:focus,
796
+ .form-textarea:focus {
797
+ outline: none;
798
+ border-color: var(--primary);
799
+ box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.2);
800
+ }
801
+
802
+ .form-input::placeholder,
803
+ .form-textarea::placeholder {
804
+ color: var(--text-muted);
805
+ }
806
+
807
+ .form-textarea {
808
+ min-height: 120px;
809
+ resize: vertical;
810
+ }
811
+
812
+ /* ═══════════════════════════════════════════════════════════════════════════
813
+ FOOTER
814
+ ═══════════════════════════════════════════════════════════════════════════ */
815
+ .footer {
816
+ background: var(--bg-secondary);
817
+ border-top: 1px solid var(--border-color);
818
+ padding: var(--space-2xl) var(--space-xl);
819
+ text-align: center;
820
+ margin-top: auto;
821
+ }
822
+
823
+ .footer-text {
824
+ font-size: 0.85rem;
825
+ color: var(--text-muted);
826
+ font-family: 'JetBrains Mono', monospace;
827
+ }
828
+
829
+ .footer-brand {
830
+ color: var(--primary-light);
831
+ font-weight: 600;
832
+ }
833
+
834
+ /* ═══════════════════════════════════════════════════════════════════════════
835
+ PARTICLES BACKGROUND (CSS only)
836
+ ═══════════════════════════════════════════════════════════════════════════ */
837
+ .particles-container {
838
+ position: fixed;
839
+ top: 0;
840
+ left: 0;
841
+ width: 100%;
842
+ height: 100%;
843
+ pointer-events: none;
844
+ overflow: hidden;
845
+ z-index: 0;
846
+ }
847
+
848
+ .particle {
849
+ position: absolute;
850
+ width: 4px;
851
+ height: 4px;
852
+ background: var(--primary);
853
+ border-radius: 50%;
854
+ opacity: 0.3;
855
+ animation: particle 15s linear infinite;
856
+ }
857
+
858
+ .particle:nth-child(1) { left: 10%; animation-duration: 12s; animation-delay: 0s; }
859
+ .particle:nth-child(2) { left: 20%; animation-duration: 18s; animation-delay: 2s; background: var(--secondary); }
860
+ .particle:nth-child(3) { left: 30%; animation-duration: 14s; animation-delay: 4s; }
861
+ .particle:nth-child(4) { left: 40%; animation-duration: 20s; animation-delay: 1s; background: var(--accent); }
862
+ .particle:nth-child(5) { left: 50%; animation-duration: 16s; animation-delay: 3s; }
863
+ .particle:nth-child(6) { left: 60%; animation-duration: 13s; animation-delay: 5s; background: var(--success); }
864
+ .particle:nth-child(7) { left: 70%; animation-duration: 19s; animation-delay: 2s; }
865
+ .particle:nth-child(8) { left: 80%; animation-duration: 15s; animation-delay: 4s; background: var(--secondary); }
866
+ .particle:nth-child(9) { left: 90%; animation-duration: 17s; animation-delay: 1s; }
867
+
868
+ /* ═══════════════════════════════════════════════════════════════════════════
869
+ GRADIENT TEXT
870
+ ═══════════════════════════════════════════════════════════════════════════ */
871
+ .gradient-text {
872
+ background: linear-gradient(135deg, var(--primary-light), var(--secondary), var(--accent));
873
+ background-size: 200% 200%;
874
+ -webkit-background-clip: text;
875
+ -webkit-text-fill-color: transparent;
876
+ background-clip: text;
877
+ animation: gradientShift 4s ease infinite;
878
+ }
879
+
880
+ /* ═══════════════════════════════════════════════════════════════════════════
881
+ PAGE WRAPPER
882
+ ═══════════════════════════════════════════════════════════════════════════ */
883
+ .page-wrapper {
884
+ padding-top: var(--navbar-height);
885
+ min-height: 100vh;
886
+ display: flex;
887
+ flex-direction: column;
888
+ position: relative;
889
+ z-index: 1;
890
+ }
891
+
892
+ /* ═══════════════════════════════════════════════════════════════════════════
893
+ RESPONSIVE
894
+ ═══════════════════════════════════════════════════════════════════════════ */
895
+ @media (max-width: 768px) {
896
+ .navbar {
897
+ padding: 0 var(--space-md);
898
+ }
899
+
900
+ .nav-link span:not(.nav-icon) {
901
+ display: none;
902
+ }
903
+
904
+ .navbar-brand span {
905
+ display: none;
906
+ }
907
+
908
+ .nav-badge {
909
+ display: none;
910
+ }
911
+
912
+ :root {
913
+ --sidebar-width: 0;
914
+ }
915
+ }
916
+
917
+ /* ═══════════════════════════════════════════════════════════════════════════
918
+ SCROLLBAR STYLING
919
+ ═══════════════════════════════════════════════════════════════════════════ */
920
+ ::-webkit-scrollbar {
921
+ width: 8px;
922
+ height: 8px;
923
+ }
924
+
925
+ ::-webkit-scrollbar-track {
926
+ background: var(--bg-secondary);
927
+ }
928
+
929
+ ::-webkit-scrollbar-thumb {
930
+ background: var(--border-light);
931
+ border-radius: 4px;
932
+ }
933
+
934
+ ::-webkit-scrollbar-thumb:hover {
935
+ background: var(--primary);
936
+ }
937
+
938
+ /* ═══════════════════════════════════════════════════════════════════════════
939
+ SELECTION
940
+ ═══════════════════════════════════════════════════════════════════════════ */
941
+ ::selection {
942
+ background: rgba(99, 102, 241, 0.3);
943
+ color: var(--text-primary);
944
+ }
feedback.html ADDED
@@ -0,0 +1,1149 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="fr">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Questions & Feedback — ML Academy</title>
7
+ <link rel="stylesheet" href="css/shared.css">
8
+ <style>
9
+ /* PAGE HERO */
10
+ .feedback-hero {
11
+ background: linear-gradient(135deg, var(--bg-secondary) 0%, var(--bg-tertiary) 100%);
12
+ border-bottom: 1px solid var(--border-color);
13
+ padding: var(--space-3xl) var(--space-xl);
14
+ text-align: center;
15
+ }
16
+
17
+ .feedback-hero-label {
18
+ font-family: 'JetBrains Mono', monospace;
19
+ font-size: 0.75rem;
20
+ color: var(--secondary);
21
+ text-transform: uppercase;
22
+ letter-spacing: 2px;
23
+ margin-bottom: var(--space-md);
24
+ }
25
+
26
+ .feedback-hero-title {
27
+ font-size: clamp(2rem, 5vw, 3rem);
28
+ font-weight: 700;
29
+ color: var(--text-primary);
30
+ margin-bottom: var(--space-md);
31
+ }
32
+
33
+ .feedback-hero-subtitle {
34
+ font-size: 1.1rem;
35
+ color: var(--text-secondary);
36
+ max-width: 600px;
37
+ margin: 0 auto;
38
+ }
39
+
40
+ /* FEEDBACK CONTAINER */
41
+ .feedback-container {
42
+ max-width: 800px;
43
+ margin: 0 auto;
44
+ padding: var(--space-2xl) var(--space-xl);
45
+ }
46
+
47
+ /* FORM PROGRESS */
48
+ .form-progress {
49
+ display: flex;
50
+ gap: var(--space-sm);
51
+ margin-bottom: var(--space-xl);
52
+ }
53
+
54
+ .progress-step {
55
+ flex: 1;
56
+ height: 4px;
57
+ background: var(--bg-tertiary);
58
+ border-radius: 2px;
59
+ transition: background var(--transition-base);
60
+ }
61
+
62
+ .progress-step.active {
63
+ background: linear-gradient(90deg, var(--primary), var(--secondary));
64
+ }
65
+
66
+ /* FORM CARDS */
67
+ .form-card {
68
+ background: var(--bg-card);
69
+ border: 1px solid var(--border-color);
70
+ border-radius: var(--radius-lg);
71
+ overflow: hidden;
72
+ margin-bottom: var(--space-lg);
73
+ transition: all var(--transition-base);
74
+ }
75
+
76
+ .form-card:hover {
77
+ border-color: var(--border-light);
78
+ }
79
+
80
+ .form-card-header {
81
+ display: flex;
82
+ align-items: center;
83
+ gap: var(--space-md);
84
+ padding: var(--space-lg) var(--space-xl);
85
+ background: var(--bg-tertiary);
86
+ border-bottom: 1px solid var(--border-color);
87
+ }
88
+
89
+ .form-card-icon {
90
+ width: 36px;
91
+ height: 36px;
92
+ background: linear-gradient(135deg, var(--primary), var(--secondary));
93
+ border-radius: var(--radius-md);
94
+ display: flex;
95
+ align-items: center;
96
+ justify-content: center;
97
+ font-size: 1rem;
98
+ font-weight: 700;
99
+ color: white;
100
+ }
101
+
102
+ .form-card-title {
103
+ font-size: 1.1rem;
104
+ font-weight: 600;
105
+ color: var(--text-primary);
106
+ }
107
+
108
+ .form-card-body {
109
+ padding: var(--space-xl);
110
+ }
111
+
112
+ /* FORM ELEMENTS */
113
+ .form-row {
114
+ margin-bottom: var(--space-lg);
115
+ }
116
+
117
+ .form-row:last-child {
118
+ margin-bottom: 0;
119
+ }
120
+
121
+ .form-label {
122
+ display: block;
123
+ font-size: 0.85rem;
124
+ font-weight: 500;
125
+ color: var(--text-primary);
126
+ margin-bottom: var(--space-sm);
127
+ }
128
+
129
+ .form-label .required {
130
+ color: var(--danger);
131
+ margin-left: var(--space-xs);
132
+ }
133
+
134
+ .form-label .hint {
135
+ font-size: 0.75rem;
136
+ color: var(--text-muted);
137
+ font-weight: 400;
138
+ margin-left: var(--space-sm);
139
+ }
140
+
141
+ /* STAR RATING */
142
+ .star-rating {
143
+ display: flex;
144
+ gap: var(--space-sm);
145
+ }
146
+
147
+ .star {
148
+ font-size: 2rem;
149
+ cursor: pointer;
150
+ transition: all var(--transition-fast);
151
+ filter: grayscale(1);
152
+ opacity: 0.4;
153
+ }
154
+
155
+ .star:hover,
156
+ .star.active {
157
+ filter: grayscale(0);
158
+ opacity: 1;
159
+ transform: scale(1.2);
160
+ }
161
+
162
+ .star-rating-text {
163
+ font-size: 0.85rem;
164
+ color: var(--text-muted);
165
+ margin-left: var(--space-md);
166
+ align-self: center;
167
+ }
168
+
169
+ /* DIFFICULTY BUTTONS */
170
+ .difficulty-buttons {
171
+ display: flex;
172
+ gap: var(--space-sm);
173
+ flex-wrap: wrap;
174
+ }
175
+
176
+ .difficulty-btn {
177
+ padding: var(--space-sm) var(--space-md);
178
+ background: var(--bg-tertiary);
179
+ border: 1px solid var(--border-color);
180
+ border-radius: var(--radius-md);
181
+ color: var(--text-secondary);
182
+ font-size: 0.9rem;
183
+ cursor: pointer;
184
+ transition: all var(--transition-base);
185
+ }
186
+
187
+ .difficulty-btn:hover {
188
+ border-color: var(--primary);
189
+ color: var(--text-primary);
190
+ }
191
+
192
+ .difficulty-btn.selected {
193
+ background: rgba(99, 102, 241, 0.2);
194
+ border-color: var(--primary);
195
+ color: var(--primary-light);
196
+ }
197
+
198
+ /* RADIO & CHECKBOX GROUPS */
199
+ .radio-group,
200
+ .checkbox-group {
201
+ display: flex;
202
+ flex-direction: column;
203
+ gap: var(--space-sm);
204
+ }
205
+
206
+ .radio-option,
207
+ .checkbox-option {
208
+ display: flex;
209
+ align-items: flex-start;
210
+ gap: var(--space-md);
211
+ padding: var(--space-md);
212
+ background: var(--bg-tertiary);
213
+ border: 1px solid var(--border-color);
214
+ border-radius: var(--radius-md);
215
+ cursor: pointer;
216
+ transition: all var(--transition-base);
217
+ }
218
+
219
+ .radio-option:hover,
220
+ .checkbox-option:hover {
221
+ border-color: var(--primary);
222
+ background: var(--bg-hover);
223
+ }
224
+
225
+ .radio-option input,
226
+ .checkbox-option input {
227
+ margin-top: 2px;
228
+ accent-color: var(--primary);
229
+ width: 18px;
230
+ }
231
+
232
+ .radio-label,
233
+ .checkbox-label {
234
+ font-size: 0.9rem;
235
+ color: var(--text-secondary);
236
+ }
237
+
238
+ /* SUBMIT BUTTON */
239
+ .submit-btn {
240
+ width: 100%;
241
+ padding: var(--space-md);
242
+ background: linear-gradient(135deg, var(--primary), var(--primary-dark));
243
+ color: white;
244
+ border: none;
245
+ border-radius: var(--radius-md);
246
+ font-family: 'Inter', sans-serif;
247
+ font-size: 1rem;
248
+ font-weight: 600;
249
+ cursor: pointer;
250
+ transition: all var(--transition-base);
251
+ display: flex;
252
+ align-items: center;
253
+ justify-content: center;
254
+ gap: var(--space-sm);
255
+ }
256
+
257
+ .submit-btn:hover {
258
+ transform: translateY(-2px);
259
+ box-shadow: var(--shadow-glow);
260
+ }
261
+
262
+ .submit-btn:disabled {
263
+ opacity: 0.6;
264
+ cursor: not-allowed;
265
+ transform: none;
266
+ }
267
+
268
+ /* SUCCESS MESSAGE */
269
+ .success-message {
270
+ display: none;
271
+ background: rgba(16, 185, 129, 0.1);
272
+ border: 1px solid rgba(16, 185, 129, 0.3);
273
+ border-radius: var(--radius-lg);
274
+ padding: var(--space-3xl);
275
+ text-align: center;
276
+ animation: scaleIn 0.5s ease;
277
+ }
278
+
279
+ .success-message.show {
280
+ display: block;
281
+ }
282
+
283
+ .success-icon {
284
+ width: 60px;
285
+ height: 60px;
286
+ background: linear-gradient(135deg, var(--success), #059669);
287
+ border-radius: 50%;
288
+ display: flex;
289
+ align-items: center;
290
+ justify-content: center;
291
+ font-size: 1.5rem;
292
+ font-weight: 700;
293
+ color: white;
294
+ margin: 0 auto var(--space-md);
295
+ animation: bounce 1s ease infinite;
296
+ }
297
+
298
+ .success-title {
299
+ font-size: 1.5rem;
300
+ font-weight: 700;
301
+ color: var(--success);
302
+ margin-bottom: var(--space-sm);
303
+ }
304
+
305
+ .success-text {
306
+ font-size: 1rem;
307
+ color: var(--text-secondary);
308
+ margin-bottom: var(--space-xl);
309
+ }
310
+
311
+ /* DATA EXPORT SECTION */
312
+ .export-section {
313
+ background: var(--bg-card);
314
+ border: 1px solid var(--border-color);
315
+ border-radius: var(--radius-lg);
316
+ padding: var(--space-xl);
317
+ margin-top: var(--space-xl);
318
+ }
319
+
320
+ .export-title {
321
+ font-size: 1rem;
322
+ font-weight: 600;
323
+ color: var(--text-primary);
324
+ margin-bottom: var(--space-md);
325
+ }
326
+
327
+ .export-buttons {
328
+ display: flex;
329
+ gap: var(--space-md);
330
+ flex-wrap: wrap;
331
+ }
332
+
333
+ .export-btn {
334
+ display: flex;
335
+ align-items: center;
336
+ gap: var(--space-sm);
337
+ padding: var(--space-sm) var(--space-md);
338
+ background: var(--bg-tertiary);
339
+ border: 1px solid var(--border-color);
340
+ border-radius: var(--radius-md);
341
+ color: var(--text-secondary);
342
+ font-size: 0.85rem;
343
+ cursor: pointer;
344
+ transition: all var(--transition-base);
345
+ text-decoration: none;
346
+ }
347
+
348
+ .export-btn:hover {
349
+ border-color: var(--primary);
350
+ color: var(--text-primary);
351
+ }
352
+
353
+ /* FAQ SECTION */
354
+ .faq-section {
355
+ margin-top: var(--space-3xl);
356
+ }
357
+
358
+ .faq-header {
359
+ text-align: center;
360
+ margin-bottom: var(--space-xl);
361
+ }
362
+
363
+ .faq-title {
364
+ font-size: 1.5rem;
365
+ font-weight: 700;
366
+ color: var(--text-primary);
367
+ margin-bottom: var(--space-sm);
368
+ }
369
+
370
+ .faq-subtitle {
371
+ font-size: 0.95rem;
372
+ color: var(--text-secondary);
373
+ }
374
+
375
+ .faq-item {
376
+ background: var(--bg-card);
377
+ border: 1px solid var(--border-color);
378
+ border-radius: var(--radius-md);
379
+ margin-bottom: var(--space-md);
380
+ overflow: hidden;
381
+ transition: all var(--transition-base);
382
+ }
383
+
384
+ .faq-item:hover {
385
+ border-color: var(--border-light);
386
+ }
387
+
388
+ .faq-question {
389
+ display: flex;
390
+ justify-content: space-between;
391
+ align-items: center;
392
+ padding: var(--space-lg) var(--space-xl);
393
+ cursor: pointer;
394
+ background: var(--bg-tertiary);
395
+ transition: background var(--transition-base);
396
+ }
397
+
398
+ .faq-question:hover {
399
+ background: var(--bg-hover);
400
+ }
401
+
402
+ .faq-question-text {
403
+ font-size: 0.95rem;
404
+ font-weight: 500;
405
+ color: var(--text-primary);
406
+ }
407
+
408
+ .faq-arrow {
409
+ color: var(--primary);
410
+ transition: transform var(--transition-base);
411
+ }
412
+
413
+ .faq-item.open .faq-arrow {
414
+ transform: rotate(180deg);
415
+ }
416
+
417
+ .faq-answer {
418
+ max-height: 0;
419
+ overflow: hidden;
420
+ transition: max-height var(--transition-slow);
421
+ }
422
+
423
+ .faq-item.open .faq-answer {
424
+ max-height: 500px;
425
+ }
426
+
427
+ .faq-answer-content {
428
+ padding: var(--space-lg) var(--space-xl);
429
+ font-size: 0.9rem;
430
+ color: var(--text-secondary);
431
+ line-height: 1.7;
432
+ border-top: 1px solid var(--border-color);
433
+ }
434
+
435
+ .faq-answer-content code {
436
+ background: rgba(99, 102, 241, 0.1);
437
+ padding: 2px 6px;
438
+ border-radius: 4px;
439
+ font-family: 'JetBrains Mono', monospace;
440
+ font-size: 0.8rem;
441
+ color: var(--primary-light);
442
+ }
443
+
444
+ /* CONTACT INFO */
445
+ .contact-info {
446
+ display: grid;
447
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
448
+ gap: var(--space-lg);
449
+ margin-top: var(--space-2xl);
450
+ padding-top: var(--space-2xl);
451
+ border-top: 1px solid var(--border-color);
452
+ }
453
+
454
+ .contact-item {
455
+ text-align: center;
456
+ padding: var(--space-lg);
457
+ background: var(--bg-card);
458
+ border: 1px solid var(--border-color);
459
+ border-radius: var(--radius-md);
460
+ transition: all var(--transition-base);
461
+ }
462
+
463
+ .contact-item:hover {
464
+ border-color: var(--primary);
465
+ transform: translateY(-3px);
466
+ }
467
+
468
+ .contact-icon {
469
+ width: 40px;
470
+ height: 40px;
471
+ background: linear-gradient(135deg, var(--primary), var(--secondary));
472
+ border-radius: var(--radius-md);
473
+ display: flex;
474
+ align-items: center;
475
+ justify-content: center;
476
+ font-size: 1rem;
477
+ font-weight: 700;
478
+ color: white;
479
+ margin: 0 auto var(--space-sm);
480
+ }
481
+
482
+ .contact-label {
483
+ font-size: 0.85rem;
484
+ font-weight: 600;
485
+ color: var(--text-primary);
486
+ margin-bottom: var(--space-xs);
487
+ }
488
+
489
+ .contact-value {
490
+ font-size: 0.8rem;
491
+ color: var(--text-muted);
492
+ }
493
+
494
+ .contact-link {
495
+ color: var(--primary-light);
496
+ text-decoration: none;
497
+ }
498
+
499
+ .contact-link:hover {
500
+ text-decoration: underline;
501
+ }
502
+
503
+ /* AUTHOR FOOTER */
504
+ .author-footer {
505
+ background: var(--bg-secondary);
506
+ border-top: 1px solid var(--border-color);
507
+ padding: var(--space-xl);
508
+ text-align: center;
509
+ }
510
+
511
+ .author-info {
512
+ display: flex;
513
+ justify-content: center;
514
+ gap: var(--space-xl);
515
+ flex-wrap: wrap;
516
+ margin-bottom: var(--space-md);
517
+ }
518
+
519
+ .author-link {
520
+ display: flex;
521
+ align-items: center;
522
+ gap: var(--space-sm);
523
+ color: var(--text-secondary);
524
+ text-decoration: none;
525
+ font-size: 0.9rem;
526
+ transition: color var(--transition-base);
527
+ }
528
+
529
+ .author-link:hover {
530
+ color: var(--primary-light);
531
+ }
532
+
533
+ .author-link svg {
534
+ width: 18px;
535
+ height: 18px;
536
+ fill: currentColor;
537
+ }
538
+ </style>
539
+ </head>
540
+ <body>
541
+ <!-- Particles Background -->
542
+ <div class="particles-container">
543
+ <div class="particle"></div>
544
+ <div class="particle"></div>
545
+ <div class="particle"></div>
546
+ <div class="particle"></div>
547
+ <div class="particle"></div>
548
+ </div>
549
+
550
+ <!-- Navigation -->
551
+ <nav class="navbar">
552
+ <a href="index.html" class="navbar-brand">
553
+ <div class="brand-logo">ML</div>
554
+ <span>ML Academy</span>
555
+ </a>
556
+ <div class="navbar-nav">
557
+ <a href="index.html" class="nav-link">
558
+ <span class="nav-icon">[H]</span>
559
+ <span>Accueil</span>
560
+ </a>
561
+ <a href="cours.html" class="nav-link">
562
+ <span class="nav-icon">[C]</span>
563
+ <span>Cours</span>
564
+ </a>
565
+ <a href="tp.html" class="nav-link">
566
+ <span class="nav-icon">[T]</span>
567
+ <span>TPs</span>
568
+ </a>
569
+ <a href="feedback.html" class="nav-link active">
570
+ <span class="nav-icon">[F]</span>
571
+ <span>Contact</span>
572
+ </a>
573
+ </div>
574
+ <div class="nav-badge">
575
+ <div class="dot"></div>
576
+ <span>Google Colab Ready</span>
577
+ </div>
578
+ </nav>
579
+
580
+ <!-- Page Wrapper -->
581
+ <div class="page-wrapper">
582
+ <!-- Hero -->
583
+ <section class="feedback-hero">
584
+ <div class="feedback-hero-label">Retours & Questions</div>
585
+ <h1 class="feedback-hero-title">Questions & Feedback</h1>
586
+ <p class="feedback-hero-subtitle">
587
+ Un point pas clair ? Une suggestion d'amelioration ?
588
+ Nous sommes la pour vous aider et ameliorer la formation.
589
+ </p>
590
+ </section>
591
+
592
+ <!-- Feedback Container -->
593
+ <div class="feedback-container">
594
+
595
+ <!-- Success Message -->
596
+ <div class="success-message" id="successMessage">
597
+ <div class="success-icon">OK</div>
598
+ <h2 class="success-title">Merci pour votre retour !</h2>
599
+ <p class="success-text">
600
+ Vos reponses ont ete enregistrees. Nous les analyserons et vous repondrons
601
+ dans les plus brefs delais.
602
+ </p>
603
+ <a href="index.html" class="btn btn-outline">Retour a l'accueil</a>
604
+ </div>
605
+
606
+ <!-- Form -->
607
+ <form id="feedbackForm">
608
+ <!-- Progress -->
609
+ <div class="form-progress">
610
+ <div class="progress-step active"></div>
611
+ <div class="progress-step"></div>
612
+ <div class="progress-step"></div>
613
+ </div>
614
+
615
+ <!-- Card 1: Identification -->
616
+ <div class="form-card scroll-animate">
617
+ <div class="form-card-header">
618
+ <div class="form-card-icon">I</div>
619
+ <h2 class="form-card-title">Identification <span style="font-size: 0.8rem; color: var(--text-muted); font-weight: 400;">(optionnel)</span></h2>
620
+ </div>
621
+ <div class="form-card-body">
622
+ <div style="display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-md);">
623
+ <div class="form-row">
624
+ <label class="form-label">Prenom / Nom</label>
625
+ <input type="text" class="form-input" placeholder="Ex: Jean Dupont" id="name">
626
+ </div>
627
+ <div class="form-row">
628
+ <label class="form-label">Email</label>
629
+ <input type="email" class="form-input" placeholder="jean@example.com" id="email">
630
+ </div>
631
+ </div>
632
+ <div class="form-row" style="margin-bottom: 0;">
633
+ <label class="form-label">Sujet de projet</label>
634
+ <select class="form-select" id="project">
635
+ <option value="">— Selectionner —</option>
636
+ <option value="classification">Classification</option>
637
+ <option value="regression">Regression</option>
638
+ <option value="nlp">NLP / Texte</option>
639
+ <option value="computer-vision">Computer Vision</option>
640
+ <option value="time-series">Series Temporelles</option>
641
+ <option value="other">Autre</option>
642
+ </select>
643
+ </div>
644
+ </div>
645
+ </div>
646
+
647
+ <!-- Card 2: Evaluation -->
648
+ <div class="form-card scroll-animate">
649
+ <div class="form-card-header">
650
+ <div class="form-card-icon">E</div>
651
+ <h2 class="form-card-title">Evaluation de la formation</h2>
652
+ </div>
653
+ <div class="form-card-body">
654
+ <div class="form-row">
655
+ <label class="form-label">Note globale <span class="required">*</span></label>
656
+ <div style="display: flex; align-items: center;">
657
+ <div class="star-rating" id="starRating">
658
+ <span class="star" data-value="1">*</span>
659
+ <span class="star" data-value="2">*</span>
660
+ <span class="star" data-value="3">*</span>
661
+ <span class="star" data-value="4">*</span>
662
+ <span class="star" data-value="5">*</span>
663
+ </div>
664
+ <span class="star-rating-text" id="ratingText">Cliquez pour noter</span>
665
+ </div>
666
+ <input type="hidden" id="ratingValue" value="0">
667
+ </div>
668
+
669
+ <div class="form-row">
670
+ <label class="form-label">Niveau de difficulte <span class="required">*</span></label>
671
+ <div class="difficulty-buttons" id="difficultyButtons">
672
+ <button type="button" class="difficulty-btn" data-value="tres-facile">Tres facile</button>
673
+ <button type="button" class="difficulty-btn" data-value="facile">Facile</button>
674
+ <button type="button" class="difficulty-btn" data-value="adapte">Adapte</button>
675
+ <button type="button" class="difficulty-btn" data-value="difficile">Difficile</button>
676
+ <button type="button" class="difficulty-btn" data-value="tres-difficile">Trop difficile</button>
677
+ </div>
678
+ <input type="hidden" id="difficultyValue" value="">
679
+ </div>
680
+
681
+ <div class="form-row" style="margin-bottom: 0;">
682
+ <label class="form-label">Rythme de la formation</label>
683
+ <div class="radio-group">
684
+ <label class="radio-option">
685
+ <input type="radio" name="rythme" value="trop-lent">
686
+ <span class="radio-label">Trop lent — on aurait pu aller plus vite</span>
687
+ </label>
688
+ <label class="radio-option">
689
+ <input type="radio" name="rythme" value="bien" checked>
690
+ <span class="radio-label">Bien rythme — equilibre parfait</span>
691
+ </label>
692
+ <label class="radio-option">
693
+ <input type="radio" name="rythme" value="trop-rapide">
694
+ <span class="radio-label">Trop rapide — difficile a suivre</span>
695
+ </label>
696
+ </div>
697
+ </div>
698
+ </div>
699
+ </div>
700
+
701
+ <!-- Card 3: Content -->
702
+ <div class="form-card scroll-animate">
703
+ <div class="form-card-header">
704
+ <div class="form-card-icon">C</div>
705
+ <h2 class="form-card-title">Contenu de la formation</h2>
706
+ </div>
707
+ <div class="form-card-body">
708
+ <div class="form-row">
709
+ <label class="form-label">Parties les plus utiles <span class="hint">(plusieurs choix possibles)</span></label>
710
+ <div class="checkbox-group">
711
+ <label class="checkbox-option">
712
+ <input type="checkbox" name="utile" value="preprocessing">
713
+ <span class="checkbox-label">Pretraitement des donnees</span>
714
+ </label>
715
+ <label class="checkbox-option">
716
+ <input type="checkbox" name="utile" value="regression">
717
+ <span class="checkbox-label">Regression Lineaire & Logistique</span>
718
+ </label>
719
+ <label class="checkbox-option">
720
+ <input type="checkbox" name="utile" value="randomforest">
721
+ <span class="checkbox-label">Random Forest & XGBoost</span>
722
+ </label>
723
+ <label class="checkbox-option">
724
+ <input type="checkbox" name="utile" value="neuralnets">
725
+ <span class="checkbox-label">Reseaux de Neurones (Keras)</span>
726
+ </label>
727
+ <label class="checkbox-option">
728
+ <input type="checkbox" name="utile" value="lstm">
729
+ <span class="checkbox-label">LSTM & Series Temporelles</span>
730
+ </label>
731
+ <label class="checkbox-option">
732
+ <input type="checkbox" name="utile" value="cnn">
733
+ <span class="checkbox-label">CNN & Computer Vision</span>
734
+ </label>
735
+ <label class="checkbox-option">
736
+ <input type="checkbox" name="utile" value="nlp">
737
+ <span class="checkbox-label">NLP & Transformers</span>
738
+ </label>
739
+ <label class="checkbox-option">
740
+ <input type="checkbox" name="utile" value="tps">
741
+ <span class="checkbox-label">Travaux Pratiques (TPs)</span>
742
+ </label>
743
+ </div>
744
+ </div>
745
+
746
+ <div class="form-row" style="margin-bottom: 0;">
747
+ <label class="form-label">Points difficiles a comprendre</label>
748
+ <div class="checkbox-group">
749
+ <label class="checkbox-option">
750
+ <input type="checkbox" name="difficile" value="overfitting">
751
+ <span class="checkbox-label">Overfitting / Underfitting</span>
752
+ </label>
753
+ <label class="checkbox-option">
754
+ <input type="checkbox" name="difficile" value="normalisation">
755
+ <span class="checkbox-label">Normalisation et Data Leakage</span>
756
+ </label>
757
+ <label class="checkbox-option">
758
+ <input type="checkbox" name="difficile" value="hyperparameters">
759
+ <span class="checkbox-label">Choix des hyperparametres</span>
760
+ </label>
761
+ <label class="checkbox-option">
762
+ <input type="checkbox" name="difficile" value="lstm-gates">
763
+ <span class="checkbox-label">Les portes du LSTM</span>
764
+ </label>
765
+ <label class="checkbox-option">
766
+ <input type="checkbox" name="difficile" value="backprop">
767
+ <span class="checkbox-label">Backpropagation</span>
768
+ </label>
769
+ <label class="checkbox-option">
770
+ <input type="checkbox" name="difficile" value="metrics">
771
+ <span class="checkbox-label">Choix des metriques d'evaluation</span>
772
+ </label>
773
+ </div>
774
+ </div>
775
+ </div>
776
+ </div>
777
+
778
+ <!-- Card 4: Questions -->
779
+ <div class="form-card scroll-animate">
780
+ <div class="form-card-header">
781
+ <div class="form-card-icon">Q</div>
782
+ <h2 class="form-card-title">Vos questions</h2>
783
+ </div>
784
+ <div class="form-card-body">
785
+ <div class="form-row">
786
+ <label class="form-label">Question principale <span class="required">*</span></label>
787
+ <textarea class="form-textarea" placeholder="Decrivez votre question ou le point qui n'est pas clair..." id="mainQuestion" required></textarea>
788
+ </div>
789
+
790
+ <div class="form-row">
791
+ <label class="form-label">Question sur le code / les TPs <span class="hint">(optionnel)</span></label>
792
+ <textarea class="form-textarea" placeholder="Si vous avez une question specifique sur un notebook ou du code..." id="codeQuestion"></textarea>
793
+ </div>
794
+
795
+ <div class="form-row" style="margin-bottom: 0;">
796
+ <label class="form-label">Lien avec votre projet <span class="hint">(optionnel)</span></label>
797
+ <textarea class="form-textarea" placeholder="Comment cette formation peut-elle vous aider dans votre projet personnel ?" id="projectLink"></textarea>
798
+ </div>
799
+ </div>
800
+ </div>
801
+
802
+ <!-- Card 5: Suggestions -->
803
+ <div class="form-card scroll-animate">
804
+ <div class="form-card-header">
805
+ <div class="form-card-icon">S</div>
806
+ <h2 class="form-card-title">Suggestions d'amelioration</h2>
807
+ </div>
808
+ <div class="form-card-body">
809
+ <div class="form-row">
810
+ <label class="form-label">Ce que vous auriez aime voir de plus</label>
811
+ <div class="checkbox-group">
812
+ <label class="checkbox-option">
813
+ <input type="checkbox" name="suggestion" value="plus-tp">
814
+ <span class="checkbox-label">Plus de temps sur les TPs</span>
815
+ </label>
816
+ <label class="checkbox-option">
817
+ <input type="checkbox" name="suggestion" value="plus-theorie">
818
+ <span class="checkbox-label">Plus de theorie et d'equations</span>
819
+ </label>
820
+ <label class="checkbox-option">
821
+ <input type="checkbox" name="suggestion" value="plus-datasets">
822
+ <span class="checkbox-label">Plus de datasets differents</span>
823
+ </label>
824
+ <label class="checkbox-option">
825
+ <input type="checkbox" name="suggestion" value="deployment">
826
+ <span class="checkbox-label">Deploiement de modeles (API, Streamlit)</span>
827
+ </label>
828
+ <label class="checkbox-option">
829
+ <input type="checkbox" name="suggestion" value="mLOps">
830
+ <span class="checkbox-label">MLOps et gestion de modeles</span>
831
+ </label>
832
+ <label class="checkbox-option">
833
+ <input type="checkbox" name="suggestion" value="viz">
834
+ <span class="checkbox-label">Plus de visualisations interactives</span>
835
+ </label>
836
+ </div>
837
+ </div>
838
+
839
+ <div class="form-row" style="margin-bottom: 0;">
840
+ <label class="form-label">Commentaire libre</label>
841
+ <textarea class="form-textarea" placeholder="Toute suggestion ou remarque est la bienvenue..." id="freeComment"></textarea>
842
+ </div>
843
+ </div>
844
+ </div>
845
+
846
+ <!-- Submit -->
847
+ <button type="submit" class="submit-btn" id="submitBtn">
848
+ Envoyer mon feedback
849
+ </button>
850
+ <p style="text-align: center; font-size: 0.8rem; color: var(--text-muted); margin-top: var(--space-md);">
851
+ Vos reponses nous aident a ameliorer la formation pour les promotions futures.
852
+ </p>
853
+ </form>
854
+
855
+ <!-- Data Export Section -->
856
+ <div class="export-section scroll-animate" id="exportSection" style="display: none;">
857
+ <h3 class="export-title">Exporter les donnees</h3>
858
+ <p style="font-size: 0.85rem; color: var(--text-secondary); margin-bottom: var(--space-md);">
859
+ Telechargez les feedbacks collectes pour analyse.
860
+ </p>
861
+ <div class="export-buttons">
862
+ <button class="export-btn" onclick="feedbackStorage.downloadFeedbacks()">
863
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
864
+ <path d="M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z"/>
865
+ </svg>
866
+ JSON
867
+ </button>
868
+ <button class="export-btn" onclick="feedbackStorage.exportToCSV()">
869
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
870
+ <path d="M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z"/>
871
+ </svg>
872
+ CSV (Excel)
873
+ </button>
874
+ <button class="export-btn" onclick="showFeedbackStats()">
875
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
876
+ <path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 17H7v-7h2v7zm4 0h-2V7h2v10zm4 0h-2v-4h2v4z"/>
877
+ </svg>
878
+ Statistiques
879
+ </button>
880
+ </div>
881
+ </div>
882
+
883
+ <!-- FAQ Section -->
884
+ <section class="faq-section">
885
+ <div class="faq-header scroll-animate">
886
+ <h2 class="faq-title">Questions frequentes</h2>
887
+ <p class="faq-subtitle">Consultez d'abord ces reponses avant de soumettre votre question.</p>
888
+ </div>
889
+
890
+ <div class="faq-item scroll-animate">
891
+ <div class="faq-question" onclick="toggleFaq(this)">
892
+ <span class="faq-question-text">Pourquoi normaliser APRES le split et pas avant ?</span>
893
+ <span class="faq-arrow">v</span>
894
+ </div>
895
+ <div class="faq-answer">
896
+ <div class="faq-answer-content">
897
+ Si vous normalisez avant le split, vous calculez le min/max sur l'ensemble des donnees (train + test).
898
+ Votre modele "voit" donc indirectement les donnees de test pendant l'entrainement — c'est le
899
+ <strong>data leakage</strong>. La regle : <strong>fit sur train seulement, transform sur train ET test</strong>.
900
+ </div>
901
+ </div>
902
+ </div>
903
+
904
+ <div class="faq-item scroll-animate">
905
+ <div class="faq-question" onclick="toggleFaq(this)">
906
+ <span class="faq-question-text">Quelle est la difference entre MAE et RMSE ?</span>
907
+ <span class="faq-arrow">v</span>
908
+ </div>
909
+ <div class="faq-answer">
910
+ <div class="faq-answer-content">
911
+ <strong>MAE</strong> (Mean Absolute Error) = moyenne des erreurs absolues.
912
+ <strong>RMSE</strong> (Root Mean Squared Error) = racine de la moyenne des erreurs au carre.
913
+ La difference cle : RMSE <strong>penalise davantage les grandes erreurs</strong> car on eleve au carre.
914
+ En ingenierie, RMSE >= MAE toujours.
915
+ </div>
916
+ </div>
917
+ </div>
918
+
919
+ <div class="faq-item scroll-animate">
920
+ <div class="faq-question" onclick="toggleFaq(this)">
921
+ <span class="faq-question-text">Comment savoir si mon modele fait de l'overfitting ?</span>
922
+ <span class="faq-arrow">v</span>
923
+ </div>
924
+ <div class="faq-answer">
925
+ <div class="faq-answer-content">
926
+ Comparez les metriques sur <strong>train</strong> ET <strong>test</strong>.
927
+ <strong>Overfitting</strong> = R2 train tres eleve (0.99) mais R2 test beaucoup plus bas (0.65).
928
+ <strong>Bonne generalisation</strong> = R2 train ≈ R2 test (ex: 0.96 vs 0.94).
929
+ Solution : Dropout, Early Stopping, regularisation L2.
930
+ </div>
931
+ </div>
932
+ </div>
933
+
934
+ <div class="faq-item scroll-animate">
935
+ <div class="faq-question" onclick="toggleFaq(this)">
936
+ <span class="faq-question-text">Quand utiliser Random Forest vs Neural Networks ?</span>
937
+ <span class="faq-arrow">v</span>
938
+ </div>
939
+ <div class="faq-answer">
940
+ <div class="faq-answer-content">
941
+ <strong>Random Forest</strong> : donnees tabulaires, besoin d'interpretabilite,
942
+ peu de temps de tuning. <strong>Neural Networks</strong> : donnees complexes (images, texte),
943
+ beaucoup de donnees disponibles, ressources computationnelles importantes.
944
+ </div>
945
+ </div>
946
+ </div>
947
+
948
+ <div class="faq-item scroll-animate">
949
+ <div class="faq-question" onclick="toggleFaq(this)">
950
+ <span class="faq-question-text">Comment adapter le code a mes propres donnees ?</span>
951
+ <span class="faq-arrow">v</span>
952
+ </div>
953
+ <div class="faq-answer">
954
+ <div class="faq-answer-content">
955
+ Remplacez <code>df = pd.read_csv("vos_donnees.csv")</code>. Verifiez avec
956
+ <code>df.head()</code> et <code>df.describe()</code>. Adaptez la liste des features
957
+ et la variable cible. Ajoutez <code>df.dropna()</code> pour supprimer les NaN.
958
+ Le reste du pipeline reste identique !
959
+ </div>
960
+ </div>
961
+ </div>
962
+ </section>
963
+
964
+ <!-- Contact Info -->
965
+ <div class="contact-info">
966
+ <div class="contact-item scroll-animate">
967
+ <div class="contact-icon">@</div>
968
+ <div class="contact-label">Email</div>
969
+ <div class="contact-value">
970
+ <a href="mailto:imadmaalouf02@gmail.com" class="contact-link">imadmaalouf02@gmail.com</a>
971
+ </div>
972
+ </div>
973
+ <div class="contact-item scroll-animate">
974
+ <div class="contact-icon">GH</div>
975
+ <div class="contact-label">GitHub</div>
976
+ <div class="contact-value">
977
+ <a href="https://github.com/imadmaalouf02" target="_blank" class="contact-link">github.com/imadmaalouf02</a>
978
+ </div>
979
+ </div>
980
+ <div class="contact-item scroll-animate">
981
+ <div class="contact-icon">HF</div>
982
+ <div class="contact-label">Hugging Face</div>
983
+ <div class="contact-value">
984
+ <a href="https://huggingface.co/spaces/MAALOOUF/ML_Training" target="_blank" class="contact-link">ML Training Space</a>
985
+ </div>
986
+ </div>
987
+ </div>
988
+
989
+ </div>
990
+
991
+ <!-- Author Footer -->
992
+ <footer class="author-footer">
993
+ <div class="author-info">
994
+ <a href="mailto:imadmaalouf02@gmail.com" class="author-link">
995
+ <svg viewBox="0 0 24 24"><path d="M20 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 4l-8 5-8-5V6l8 5 8-5v2z"/></svg>
996
+ imadmaalouf02@gmail.com
997
+ </a>
998
+ <a href="https://github.com/imadmaalouf02" target="_blank" class="author-link">
999
+ <svg viewBox="0 0 24 24"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/></svg>
1000
+ GitHub
1001
+ </a>
1002
+ <a href="https://huggingface.co/spaces/MAALOOUF/ML_Training" target="_blank" class="author-link">
1003
+ <svg viewBox="0 0 24 24"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 17.93c-3.95-.49-7-3.85-7-7.93 0-.62.08-1.21.21-1.79L9 15v1c0 1.1.9 2 2 2v1.93zm6.9-2.54c-.26-.81-1-1.39-1.9-1.39h-1v-3c0-.55-.45-1-1-1H8v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41c2.93 1.19 5 4.06 5 7.41 0 2.08-.8 3.97-2.1 5.39z"/></svg>
1004
+ Hugging Face Space
1005
+ </a>
1006
+ </div>
1007
+ </footer>
1008
+
1009
+ <!-- Footer -->
1010
+ <footer class="footer">
1011
+ <p class="footer-text">
1012
+ ML Academy — Questions & Feedback —
1013
+ <span class="footer-brand">GE-MCI 4A</span> — 2025/2026
1014
+ </p>
1015
+ <p class="footer-text" style="margin-top: var(--space-sm); font-size: 0.75rem; color: var(--text-muted);">
1016
+ Formateur : Imad Maalouf
1017
+ </p>
1018
+ </footer>
1019
+ </div>
1020
+
1021
+ <!-- Scripts -->
1022
+ <script src="js/shared.js"></script>
1023
+ <script src="js/feedback-storage.js"></script>
1024
+ <script>
1025
+ // Scroll animations
1026
+ const observerOptions = {
1027
+ threshold: 0.1,
1028
+ rootMargin: '0px 0px -50px 0px'
1029
+ };
1030
+
1031
+ const observer = new IntersectionObserver((entries) => {
1032
+ entries.forEach(entry => {
1033
+ if (entry.isIntersecting) {
1034
+ entry.target.classList.add('visible');
1035
+ }
1036
+ });
1037
+ }, observerOptions);
1038
+
1039
+ document.querySelectorAll('.scroll-animate').forEach(el => {
1040
+ observer.observe(el);
1041
+ });
1042
+
1043
+ // Star rating
1044
+ const stars = document.querySelectorAll('.star');
1045
+ const ratingValue = document.getElementById('ratingValue');
1046
+ const ratingText = document.getElementById('ratingText');
1047
+ const ratingLabels = ['', 'Insuffisant', 'Passable', 'Bien', 'Tres bien', 'Excellent !'];
1048
+
1049
+ stars.forEach(star => {
1050
+ star.addEventListener('click', () => {
1051
+ const value = parseInt(star.dataset.value);
1052
+ ratingValue.value = value;
1053
+ ratingText.textContent = ratingLabels[value];
1054
+
1055
+ stars.forEach((s, i) => {
1056
+ s.classList.toggle('active', i < value);
1057
+ });
1058
+
1059
+ // Update progress
1060
+ document.querySelectorAll('.progress-step')[1].classList.add('active');
1061
+ });
1062
+ });
1063
+
1064
+ // Difficulty buttons
1065
+ const diffButtons = document.querySelectorAll('.difficulty-btn');
1066
+ const difficultyValue = document.getElementById('difficultyValue');
1067
+
1068
+ diffButtons.forEach(btn => {
1069
+ btn.addEventListener('click', () => {
1070
+ diffButtons.forEach(b => b.classList.remove('selected'));
1071
+ btn.classList.add('selected');
1072
+ difficultyValue.value = btn.dataset.value;
1073
+ });
1074
+ });
1075
+
1076
+ // FAQ toggle
1077
+ function toggleFaq(element) {
1078
+ const faqItem = element.parentElement;
1079
+ faqItem.classList.toggle('open');
1080
+ }
1081
+
1082
+ // Form submission
1083
+ const form = document.getElementById('feedbackForm');
1084
+ const successMessage = document.getElementById('successMessage');
1085
+ const submitBtn = document.getElementById('submitBtn');
1086
+ const exportSection = document.getElementById('exportSection');
1087
+
1088
+ form.addEventListener('submit', (e) => {
1089
+ e.preventDefault();
1090
+
1091
+ // Validation
1092
+ const rating = ratingValue.value;
1093
+ const difficulty = difficultyValue.value;
1094
+ const mainQuestion = document.getElementById('mainQuestion').value.trim();
1095
+
1096
+ if (rating === '0') {
1097
+ alert('Veuillez donner une note a la formation.');
1098
+ return;
1099
+ }
1100
+
1101
+ if (!difficulty) {
1102
+ alert('Veuillez indiquer le niveau de difficulte percu.');
1103
+ return;
1104
+ }
1105
+
1106
+ if (!mainQuestion) {
1107
+ alert('Veuillez poser au moins une question principale.');
1108
+ return;
1109
+ }
1110
+
1111
+ // Collect data
1112
+ const formData = {
1113
+ name: document.getElementById('name').value,
1114
+ email: document.getElementById('email').value,
1115
+ project: document.getElementById('project').value,
1116
+ rating: rating,
1117
+ difficulty: difficulty,
1118
+ rythme: document.querySelector('input[name="rythme"]:checked')?.value,
1119
+ utiles: [...document.querySelectorAll('input[name="utile"]:checked')].map(cb => cb.value),
1120
+ difficiles: [...document.querySelectorAll('input[name="difficile"]:checked')].map(cb => cb.value),
1121
+ mainQuestion: mainQuestion,
1122
+ codeQuestion: document.getElementById('codeQuestion').value,
1123
+ projectLink: document.getElementById('projectLink').value,
1124
+ suggestions: [...document.querySelectorAll('input[name="suggestion"]:checked')].map(cb => cb.value),
1125
+ freeComment: document.getElementById('freeComment').value,
1126
+ timestamp: new Date().toISOString()
1127
+ };
1128
+
1129
+ // Submit to storage
1130
+ submitFeedback(formData);
1131
+
1132
+ // Show success
1133
+ form.style.display = 'none';
1134
+ successMessage.classList.add('show');
1135
+ exportSection.style.display = 'block';
1136
+ document.querySelectorAll('.progress-step')[2].classList.add('active');
1137
+ window.scrollTo({ top: 0, behavior: 'smooth' });
1138
+ });
1139
+
1140
+ // Update progress on scroll
1141
+ window.addEventListener('scroll', () => {
1142
+ const mainQuestion = document.getElementById('mainQuestion')?.value.trim();
1143
+ if (mainQuestion) {
1144
+ document.querySelectorAll('.progress-step')[2].classList.add('active');
1145
+ }
1146
+ });
1147
+ </script>
1148
+ </body>
1149
+ </html>
index.html CHANGED
@@ -1,19 +1,1010 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  </html>
 
1
+ <!DOCTYPE html>
2
+ <html lang="fr">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>ML Academy — Plateforme de Formation Machine Learning</title>
7
+ <link rel="stylesheet" href="css/shared.css">
8
+ <style>
9
+ /* HERO SECTION */
10
+ .hero {
11
+ min-height: calc(100vh - var(--navbar-height));
12
+ display: flex;
13
+ flex-direction: column;
14
+ justify-content: center;
15
+ align-items: center;
16
+ text-align: center;
17
+ padding: var(--space-3xl) var(--space-xl);
18
+ position: relative;
19
+ overflow: hidden;
20
+ }
21
+
22
+ .hero-bg {
23
+ position: absolute;
24
+ top: 0;
25
+ left: 0;
26
+ right: 0;
27
+ bottom: 0;
28
+ background:
29
+ radial-gradient(ellipse at 20% 20%, rgba(99, 102, 241, 0.15) 0%, transparent 50%),
30
+ radial-gradient(ellipse at 80% 80%, rgba(6, 182, 212, 0.1) 0%, transparent 50%),
31
+ radial-gradient(ellipse at 50% 50%, rgba(245, 158, 11, 0.05) 0%, transparent 70%);
32
+ animation: pulse 8s ease-in-out infinite;
33
+ }
34
+
35
+ .hero-eyebrow {
36
+ display: inline-flex;
37
+ align-items: center;
38
+ gap: var(--space-sm);
39
+ padding: var(--space-xs) var(--space-md);
40
+ background: rgba(99, 102, 241, 0.1);
41
+ border: 1px solid rgba(99, 102, 241, 0.3);
42
+ border-radius: 20px;
43
+ font-family: 'JetBrains Mono', monospace;
44
+ font-size: 0.75rem;
45
+ color: var(--primary-light);
46
+ text-transform: uppercase;
47
+ letter-spacing: 1px;
48
+ margin-bottom: var(--space-lg);
49
+ animation: fadeInDown 0.6s ease 0.2s both;
50
+ }
51
+
52
+ .hero-eyebrow .pulse {
53
+ width: 6px;
54
+ height: 6px;
55
+ background: var(--success);
56
+ border-radius: 50%;
57
+ animation: pulse 2s ease-in-out infinite;
58
+ }
59
+
60
+ .hero-title {
61
+ font-size: clamp(2.5rem, 6vw, 4.5rem);
62
+ font-weight: 800;
63
+ line-height: 1.1;
64
+ margin-bottom: var(--space-md);
65
+ animation: fadeInUp 0.6s ease 0.3s both;
66
+ }
67
+
68
+ .hero-subtitle {
69
+ font-size: clamp(1rem, 2vw, 1.25rem);
70
+ color: var(--text-secondary);
71
+ max-width: 600px;
72
+ margin-bottom: var(--space-xl);
73
+ line-height: 1.7;
74
+ animation: fadeInUp 0.6s ease 0.4s both;
75
+ }
76
+
77
+ .hero-cta {
78
+ display: flex;
79
+ gap: var(--space-md);
80
+ flex-wrap: wrap;
81
+ justify-content: center;
82
+ margin-bottom: var(--space-2xl);
83
+ animation: fadeInUp 0.6s ease 0.5s both;
84
+ }
85
+
86
+ .hero-stats {
87
+ display: flex;
88
+ gap: var(--space-2xl);
89
+ flex-wrap: wrap;
90
+ justify-content: center;
91
+ padding-top: var(--space-xl);
92
+ border-top: 1px solid var(--border-color);
93
+ animation: fadeInUp 0.6s ease 0.6s both;
94
+ }
95
+
96
+ .hero-stat {
97
+ text-align: center;
98
+ }
99
+
100
+ .hero-stat-value {
101
+ font-family: 'JetBrains Mono', monospace;
102
+ font-size: 2.5rem;
103
+ font-weight: 700;
104
+ color: var(--text-primary);
105
+ line-height: 1;
106
+ }
107
+
108
+ .hero-stat-value span {
109
+ font-size: 1rem;
110
+ color: var(--primary-light);
111
+ }
112
+
113
+ .hero-stat-label {
114
+ font-size: 0.75rem;
115
+ color: var(--text-muted);
116
+ text-transform: uppercase;
117
+ letter-spacing: 1px;
118
+ margin-top: var(--space-xs);
119
+ }
120
+
121
+ /* FEATURES SECTION */
122
+ .features {
123
+ padding: var(--space-3xl) var(--space-xl);
124
+ background: var(--bg-secondary);
125
+ border-top: 1px solid var(--border-color);
126
+ }
127
+
128
+ .section-header {
129
+ text-align: center;
130
+ margin-bottom: var(--space-2xl);
131
+ }
132
+
133
+ .section-eyebrow {
134
+ font-family: 'JetBrains Mono', monospace;
135
+ font-size: 0.75rem;
136
+ color: var(--primary-light);
137
+ text-transform: uppercase;
138
+ letter-spacing: 2px;
139
+ margin-bottom: var(--space-sm);
140
+ }
141
+
142
+ .section-title {
143
+ font-size: clamp(1.75rem, 4vw, 2.5rem);
144
+ font-weight: 700;
145
+ color: var(--text-primary);
146
+ margin-bottom: var(--space-sm);
147
+ }
148
+
149
+ .section-subtitle {
150
+ font-size: 1rem;
151
+ color: var(--text-secondary);
152
+ max-width: 600px;
153
+ margin: 0 auto;
154
+ }
155
+
156
+ .features-grid {
157
+ display: grid;
158
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
159
+ gap: var(--space-lg);
160
+ max-width: 1200px;
161
+ margin: 0 auto;
162
+ }
163
+
164
+ .feature-card {
165
+ background: var(--bg-card);
166
+ border: 1px solid var(--border-color);
167
+ border-radius: var(--radius-lg);
168
+ padding: var(--space-xl);
169
+ transition: all var(--transition-base);
170
+ position: relative;
171
+ overflow: hidden;
172
+ }
173
+
174
+ .feature-card::before {
175
+ content: '';
176
+ position: absolute;
177
+ top: 0;
178
+ left: 0;
179
+ right: 0;
180
+ height: 3px;
181
+ background: linear-gradient(90deg, var(--primary), var(--secondary));
182
+ transform: scaleX(0);
183
+ transition: transform var(--transition-base);
184
+ }
185
+
186
+ .feature-card:hover {
187
+ transform: translateY(-8px);
188
+ border-color: var(--border-light);
189
+ box-shadow: var(--shadow-lg), var(--shadow-glow);
190
+ }
191
+
192
+ .feature-card:hover::before {
193
+ transform: scaleX(1);
194
+ }
195
+
196
+ .feature-icon {
197
+ width: 60px;
198
+ height: 60px;
199
+ background: linear-gradient(135deg, var(--primary), var(--secondary));
200
+ border-radius: var(--radius-md);
201
+ display: flex;
202
+ align-items: center;
203
+ justify-content: center;
204
+ font-size: 1.5rem;
205
+ font-weight: 700;
206
+ color: white;
207
+ margin-bottom: var(--space-md);
208
+ animation: float 3s ease-in-out infinite;
209
+ }
210
+
211
+ .feature-title {
212
+ font-size: 1.2rem;
213
+ font-weight: 700;
214
+ color: var(--text-primary);
215
+ margin-bottom: var(--space-sm);
216
+ }
217
+
218
+ .feature-text {
219
+ font-size: 0.9rem;
220
+ color: var(--text-secondary);
221
+ line-height: 1.6;
222
+ margin-bottom: var(--space-md);
223
+ }
224
+
225
+ .feature-tags {
226
+ display: flex;
227
+ flex-wrap: wrap;
228
+ gap: var(--space-xs);
229
+ }
230
+
231
+ /* MODULES SECTION */
232
+ .modules {
233
+ padding: var(--space-3xl) var(--space-xl);
234
+ }
235
+
236
+ .modules-grid {
237
+ display: grid;
238
+ grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
239
+ gap: var(--space-lg);
240
+ max-width: 1200px;
241
+ margin: 0 auto;
242
+ }
243
+
244
+ .module-card {
245
+ background: var(--bg-card);
246
+ border: 1px solid var(--border-color);
247
+ border-radius: var(--radius-lg);
248
+ overflow: hidden;
249
+ transition: all var(--transition-base);
250
+ text-decoration: none;
251
+ color: inherit;
252
+ display: flex;
253
+ flex-direction: column;
254
+ }
255
+
256
+ .module-card:hover {
257
+ transform: translateY(-5px);
258
+ border-color: var(--primary);
259
+ box-shadow: var(--shadow-lg), var(--shadow-glow);
260
+ }
261
+
262
+ .module-header {
263
+ padding: var(--space-lg);
264
+ display: flex;
265
+ align-items: flex-start;
266
+ gap: var(--space-md);
267
+ border-bottom: 1px solid var(--border-color);
268
+ }
269
+
270
+ .module-icon {
271
+ width: 50px;
272
+ height: 50px;
273
+ border-radius: var(--radius-md);
274
+ display: flex;
275
+ align-items: center;
276
+ justify-content: center;
277
+ font-size: 1.25rem;
278
+ font-weight: 700;
279
+ flex-shrink: 0;
280
+ }
281
+
282
+ .module-icon.blue { background: rgba(99, 102, 241, 0.2); color: var(--primary-light); }
283
+ .module-icon.green { background: rgba(16, 185, 129, 0.2); color: var(--success); }
284
+ .module-icon.orange { background: rgba(249, 115, 22, 0.2); color: var(--warning); }
285
+
286
+ .module-info {
287
+ flex: 1;
288
+ }
289
+
290
+ .module-label {
291
+ font-family: 'JetBrains Mono', monospace;
292
+ font-size: 0.65rem;
293
+ color: var(--text-muted);
294
+ text-transform: uppercase;
295
+ letter-spacing: 1px;
296
+ margin-bottom: var(--space-xs);
297
+ }
298
+
299
+ .module-title {
300
+ font-size: 1.1rem;
301
+ font-weight: 700;
302
+ color: var(--text-primary);
303
+ }
304
+
305
+ .module-body {
306
+ padding: var(--space-lg);
307
+ flex: 1;
308
+ }
309
+
310
+ .module-desc {
311
+ font-size: 0.9rem;
312
+ color: var(--text-secondary);
313
+ line-height: 1.6;
314
+ margin-bottom: var(--space-md);
315
+ }
316
+
317
+ .module-meta {
318
+ display: flex;
319
+ flex-wrap: wrap;
320
+ gap: var(--space-xs);
321
+ }
322
+
323
+ .module-footer {
324
+ padding: var(--space-md) var(--space-lg);
325
+ background: var(--bg-tertiary);
326
+ display: flex;
327
+ align-items: center;
328
+ justify-content: space-between;
329
+ }
330
+
331
+ .module-arrow {
332
+ color: var(--primary-light);
333
+ transition: transform var(--transition-base);
334
+ }
335
+
336
+ .module-card:hover .module-arrow {
337
+ transform: translateX(5px);
338
+ }
339
+
340
+ /* TIMELINE SECTION */
341
+ .timeline {
342
+ padding: var(--space-3xl) var(--space-xl);
343
+ background: var(--bg-secondary);
344
+ border-top: 1px solid var(--border-color);
345
+ }
346
+
347
+ .timeline-container {
348
+ max-width: 800px;
349
+ margin: 0 auto;
350
+ }
351
+
352
+ .timeline-item {
353
+ display: flex;
354
+ gap: var(--space-lg);
355
+ padding: var(--space-md) 0;
356
+ position: relative;
357
+ }
358
+
359
+ .timeline-item:not(:last-child)::before {
360
+ content: '';
361
+ position: absolute;
362
+ left: 15px;
363
+ top: 45px;
364
+ bottom: 0;
365
+ width: 2px;
366
+ background: linear-gradient(180deg, var(--primary), var(--secondary));
367
+ }
368
+
369
+ .timeline-dot {
370
+ width: 32px;
371
+ height: 32px;
372
+ background: var(--bg-card);
373
+ border: 2px solid var(--primary);
374
+ border-radius: 50%;
375
+ display: flex;
376
+ align-items: center;
377
+ justify-content: center;
378
+ font-size: 0.75rem;
379
+ font-weight: 700;
380
+ color: var(--primary-light);
381
+ flex-shrink: 0;
382
+ z-index: 1;
383
+ }
384
+
385
+ .timeline-content {
386
+ flex: 1;
387
+ padding-bottom: var(--space-lg);
388
+ }
389
+
390
+ .timeline-time {
391
+ font-family: 'JetBrains Mono', monospace;
392
+ font-size: 0.75rem;
393
+ color: var(--primary-light);
394
+ margin-bottom: var(--space-xs);
395
+ }
396
+
397
+ .timeline-title {
398
+ font-size: 1rem;
399
+ font-weight: 600;
400
+ color: var(--text-primary);
401
+ margin-bottom: var(--space-xs);
402
+ }
403
+
404
+ .timeline-text {
405
+ font-size: 0.85rem;
406
+ color: var(--text-secondary);
407
+ }
408
+
409
+ /* CTA SECTION */
410
+ .cta {
411
+ padding: var(--space-3xl) var(--space-xl);
412
+ text-align: center;
413
+ }
414
+
415
+ .cta-box {
416
+ max-width: 700px;
417
+ margin: 0 auto;
418
+ padding: var(--space-3xl);
419
+ background: linear-gradient(135deg, var(--bg-card), var(--bg-tertiary));
420
+ border: 1px solid var(--border-color);
421
+ border-radius: var(--radius-xl);
422
+ position: relative;
423
+ overflow: hidden;
424
+ }
425
+
426
+ .cta-box::before {
427
+ content: '';
428
+ position: absolute;
429
+ top: -50%;
430
+ left: -50%;
431
+ width: 200%;
432
+ height: 200%;
433
+ background: radial-gradient(circle, rgba(99, 102, 241, 0.1) 0%, transparent 70%);
434
+ animation: rotate 20s linear infinite;
435
+ }
436
+
437
+ .cta-content {
438
+ position: relative;
439
+ z-index: 1;
440
+ }
441
+
442
+ .cta-title {
443
+ font-size: 2rem;
444
+ font-weight: 700;
445
+ color: var(--text-primary);
446
+ margin-bottom: var(--space-md);
447
+ }
448
+
449
+ .cta-text {
450
+ font-size: 1rem;
451
+ color: var(--text-secondary);
452
+ margin-bottom: var(--space-xl);
453
+ }
454
+
455
+ .cta-buttons {
456
+ display: flex;
457
+ gap: var(--space-md);
458
+ justify-content: center;
459
+ flex-wrap: wrap;
460
+ }
461
+
462
+ /* FLOATING SHAPES */
463
+ .floating-shape {
464
+ position: absolute;
465
+ border-radius: 50%;
466
+ opacity: 0.1;
467
+ animation: float 6s ease-in-out infinite;
468
+ }
469
+
470
+ .shape-1 {
471
+ width: 300px;
472
+ height: 300px;
473
+ background: var(--primary);
474
+ top: 10%;
475
+ right: -100px;
476
+ animation-delay: 0s;
477
+ }
478
+
479
+ .shape-2 {
480
+ width: 200px;
481
+ height: 200px;
482
+ background: var(--secondary);
483
+ bottom: 20%;
484
+ left: -50px;
485
+ animation-delay: 2s;
486
+ }
487
+
488
+ .shape-3 {
489
+ width: 150px;
490
+ height: 150px;
491
+ background: var(--accent);
492
+ top: 50%;
493
+ right: 10%;
494
+ animation-delay: 4s;
495
+ }
496
+
497
+ /* AUTHOR FOOTER */
498
+ .author-footer {
499
+ background: var(--bg-secondary);
500
+ border-top: 1px solid var(--border-color);
501
+ padding: var(--space-xl);
502
+ text-align: center;
503
+ }
504
+
505
+ .author-info {
506
+ display: flex;
507
+ justify-content: center;
508
+ gap: var(--space-xl);
509
+ flex-wrap: wrap;
510
+ margin-bottom: var(--space-md);
511
+ }
512
+
513
+ .author-link {
514
+ display: flex;
515
+ align-items: center;
516
+ gap: var(--space-sm);
517
+ color: var(--text-secondary);
518
+ text-decoration: none;
519
+ font-size: 0.9rem;
520
+ transition: color var(--transition-base);
521
+ }
522
+
523
+ .author-link:hover {
524
+ color: var(--primary-light);
525
+ }
526
+
527
+ .author-link svg {
528
+ width: 18px;
529
+ height: 18px;
530
+ fill: currentColor;
531
+ }
532
+ </style>
533
+ </head>
534
+ <body>
535
+ <!-- Particles Background -->
536
+ <div class="particles-container">
537
+ <div class="particle"></div>
538
+ <div class="particle"></div>
539
+ <div class="particle"></div>
540
+ <div class="particle"></div>
541
+ <div class="particle"></div>
542
+ <div class="particle"></div>
543
+ <div class="particle"></div>
544
+ <div class="particle"></div>
545
+ <div class="particle"></div>
546
+ </div>
547
+
548
+ <!-- Navigation -->
549
+ <nav class="navbar">
550
+ <a href="index.html" class="navbar-brand">
551
+ <div class="brand-logo">ML</div>
552
+ <span>ML Academy</span>
553
+ </a>
554
+ <div class="navbar-nav">
555
+ <a href="index.html" class="nav-link active">
556
+ <span class="nav-icon">[H]</span>
557
+ <span>Accueil</span>
558
+ </a>
559
+ <a href="cours.html" class="nav-link">
560
+ <span class="nav-icon">[C]</span>
561
+ <span>Cours</span>
562
+ </a>
563
+ <a href="tp.html" class="nav-link">
564
+ <span class="nav-icon">[T]</span>
565
+ <span>TPs</span>
566
+ </a>
567
+ <a href="feedback.html" class="nav-link">
568
+ <span class="nav-icon">[F]</span>
569
+ <span>Contact</span>
570
+ </a>
571
+ </div>
572
+ <div class="nav-badge">
573
+ <div class="dot"></div>
574
+ <span>Google Colab Ready</span>
575
+ </div>
576
+ </nav>
577
+
578
+ <!-- Page Wrapper -->
579
+ <div class="page-wrapper">
580
+ <!-- Hero Section -->
581
+ <section class="hero">
582
+ <div class="hero-bg"></div>
583
+ <div class="floating-shape shape-1"></div>
584
+ <div class="floating-shape shape-2"></div>
585
+ <div class="floating-shape shape-3"></div>
586
+
587
+ <div class="hero-eyebrow">
588
+ <div class="pulse"></div>
589
+ <span>Formation 2025/2026 — 100% Pratique</span>
590
+ </div>
591
+
592
+ <h1 class="hero-title">
593
+ Maitrisez le <span class="gradient-text">Machine Learning</span><br>
594
+ par la pratique
595
+ </h1>
596
+
597
+ <p class="hero-subtitle">
598
+ Apprenez les algorithmes ML essentiels a travers des projets concrets
599
+ avec des datasets reels de Kaggle. De zero a heros en quelques seances.
600
+ </p>
601
+
602
+ <div class="hero-cta">
603
+ <a href="cours.html" class="btn btn-primary btn-lg">
604
+ Commencer les cours
605
+ </a>
606
+ <a href="tp.html" class="btn btn-secondary btn-lg">
607
+ Voir les TPs
608
+ </a>
609
+ </div>
610
+
611
+ <div class="hero-stats">
612
+ <div class="hero-stat">
613
+ <div class="hero-stat-value">8<span>+</span></div>
614
+ <div class="hero-stat-label">Algorithmes</div>
615
+ </div>
616
+ <div class="hero-stat">
617
+ <div class="hero-stat-value">6<span></span></div>
618
+ <div class="hero-stat-label">TPs Complets</div>
619
+ </div>
620
+ <div class="hero-stat">
621
+ <div class="hero-stat-value">4<span></span></div>
622
+ <div class="hero-stat-label">Datasets Reels</div>
623
+ </div>
624
+ <div class="hero-stat">
625
+ <div class="hero-stat-value">0<span></span></div>
626
+ <div class="hero-stat-label">Installation</div>
627
+ </div>
628
+ </div>
629
+ </section>
630
+
631
+ <!-- Features Section -->
632
+ <section class="features">
633
+ <div class="section-header scroll-animate">
634
+ <div class="section-eyebrow">Pourquoi cette formation</div>
635
+ <h2 class="section-title">Ce que vous allez apprendre</h2>
636
+ <p class="section-subtitle">
637
+ Une approche progressive alliant theorie solide et pratique intensive
638
+ sur des problemes reels du monde de la data science.
639
+ </p>
640
+ </div>
641
+
642
+ <div class="features-grid">
643
+ <div class="feature-card scroll-animate">
644
+ <div class="feature-icon">D</div>
645
+ <h3 class="feature-title">Pretraitement des Donnees</h3>
646
+ <p class="feature-text">
647
+ Maitrisez le nettoyage, la normalisation et l'ingenierie des features
648
+ pour preparer vos donnees a l'entrainement.
649
+ </p>
650
+ <div class="feature-tags">
651
+ <span class="badge badge-primary">Pandas</span>
652
+ <span class="badge badge-secondary">NumPy</span>
653
+ <span class="badge badge-success">Scikit-learn</span>
654
+ </div>
655
+ </div>
656
+
657
+ <div class="feature-card scroll-animate">
658
+ <div class="feature-icon">A</div>
659
+ <h3 class="feature-title">Algorithmes de ML</h3>
660
+ <p class="feature-text">
661
+ Comprendre et implementer les algorithmes fondamentaux :
662
+ Regression, Classification, Clustering et Deep Learning.
663
+ </p>
664
+ <div class="feature-tags">
665
+ <span class="badge badge-primary">Regression</span>
666
+ <span class="badge badge-secondary">Random Forest</span>
667
+ <span class="badge badge-accent">Neural Networks</span>
668
+ </div>
669
+ </div>
670
+
671
+ <div class="feature-card scroll-animate">
672
+ <div class="feature-icon">E</div>
673
+ <h3 class="feature-title">Evaluation & Optimisation</h3>
674
+ <p class="feature-text">
675
+ Apprenez a mesurer la performance de vos modeles et a les optimiser
676
+ avec les bonnes metriques et techniques.
677
+ </p>
678
+ <div class="feature-tags">
679
+ <span class="badge badge-success">Cross-validation</span>
680
+ <span class="badge badge-warning">Grid Search</span>
681
+ <span class="badge badge-primary">Metriques</span>
682
+ </div>
683
+ </div>
684
+
685
+ <div class="feature-card scroll-animate">
686
+ <div class="feature-icon">P</div>
687
+ <h3 class="feature-title">Projets Concrets</h3>
688
+ <p class="feature-text">
689
+ Travaillez sur des datasets reels de Kaggle : Titanic, Housing,
690
+ Iris et bien d'autres pour construire votre portfolio.
691
+ </p>
692
+ <div class="feature-tags">
693
+ <span class="badge badge-success">Kaggle</span>
694
+ <span class="badge badge-accent">Portfolio</span>
695
+ <span class="badge badge-secondary">GitHub</span>
696
+ </div>
697
+ </div>
698
+
699
+ <div class="feature-card scroll-animate">
700
+ <div class="feature-icon">T</div>
701
+ <h3 class="feature-title">Series Temporelles</h3>
702
+ <p class="feature-text">
703
+ Decouvrez les techniques specifiques pour predire des donnees
704
+ temporelles avec LSTM et les modeles ARIMA.
705
+ </p>
706
+ <div class="feature-tags">
707
+ <span class="badge badge-primary">LSTM</span>
708
+ <span class="badge badge-secondary">TensorFlow</span>
709
+ <span class="badge badge-warning">Time Series</span>
710
+ </div>
711
+ </div>
712
+
713
+ <div class="feature-card scroll-animate">
714
+ <div class="feature-icon">X</div>
715
+ <h3 class="feature-title">Deploiement</h3>
716
+ <p class="feature-text">
717
+ Apprenez a mettre vos modeles en production avec des API
718
+ et des interfaces web interactives.
719
+ </p>
720
+ <div class="feature-tags">
721
+ <span class="badge badge-success">FastAPI</span>
722
+ <span class="badge badge-primary">Streamlit</span>
723
+ <span class="badge badge-secondary">Docker</span>
724
+ </div>
725
+ </div>
726
+ </div>
727
+ </section>
728
+
729
+ <!-- Modules Section -->
730
+ <section class="modules">
731
+ <div class="section-header scroll-animate">
732
+ <div class="section-eyebrow">Parcours de formation</div>
733
+ <h2 class="section-title">Accedez aux modules</h2>
734
+ <p class="section-subtitle">
735
+ Trois espaces dedies pour une progression optimale dans votre apprentissage.
736
+ </p>
737
+ </div>
738
+
739
+ <div class="modules-grid">
740
+ <a href="cours.html" class="module-card scroll-animate">
741
+ <div class="module-header">
742
+ <div class="module-icon blue">C</div>
743
+ <div class="module-info">
744
+ <div class="module-label">Module 1</div>
745
+ <h3 class="module-title">Cours Theoriques</h3>
746
+ </div>
747
+ </div>
748
+ <div class="module-body">
749
+ <p class="module-desc">
750
+ Contenu theorique complet avec equations mathematiques,
751
+ explications detaillees et exemples de code Python annote.
752
+ </p>
753
+ <div class="module-meta">
754
+ <span class="badge badge-primary">Theorie</span>
755
+ <span class="badge badge-secondary">Mathematiques</span>
756
+ <span class="badge badge-success">Python</span>
757
+ </div>
758
+ </div>
759
+ <div class="module-footer">
760
+ <span style="font-size: 0.8rem; color: var(--text-muted);">8 chapitres</span>
761
+ <span class="module-arrow">→</span>
762
+ </div>
763
+ </a>
764
+
765
+ <a href="tp.html" class="module-card scroll-animate">
766
+ <div class="module-header">
767
+ <div class="module-icon green">T</div>
768
+ <div class="module-info">
769
+ <div class="module-label">Module 2</div>
770
+ <h3 class="module-title">Travaux Pratiques</h3>
771
+ </div>
772
+ </div>
773
+ <div class="module-body">
774
+ <p class="module-desc">
775
+ 6 notebooks Google Colab guides etape par etape sur des datasets
776
+ reels de Kaggle. Pret a executer sans installation.
777
+ </p>
778
+ <div class="module-meta">
779
+ <span class="badge badge-success">Google Colab</span>
780
+ <span class="badge badge-accent">Guide</span>
781
+ <span class="badge badge-warning">Kaggle</span>
782
+ </div>
783
+ </div>
784
+ <div class="module-footer">
785
+ <span style="font-size: 0.8rem; color: var(--text-muted);">6 notebooks</span>
786
+ <span class="module-arrow">→</span>
787
+ </div>
788
+ </a>
789
+
790
+ <a href="feedback.html" class="module-card scroll-animate">
791
+ <div class="module-header">
792
+ <div class="module-icon orange">F</div>
793
+ <div class="module-info">
794
+ <div class="module-label">Module 3</div>
795
+ <h3 class="module-title">Questions & Feedback</h3>
796
+ </div>
797
+ </div>
798
+ <div class="module-body">
799
+ <p class="module-desc">
800
+ Posez vos questions, evaluez la formation et accedez a la FAQ
801
+ pour resoudre vos doutes rapidement.
802
+ </p>
803
+ <div class="module-meta">
804
+ <span class="badge badge-primary">FAQ</span>
805
+ <span class="badge badge-secondary">Support</span>
806
+ <span class="badge badge-success">Feedback</span>
807
+ </div>
808
+ </div>
809
+ <div class="module-footer">
810
+ <span style="font-size: 0.8rem; color: var(--text-muted);">Reponses 24h</span>
811
+ <span class="module-arrow">→</span>
812
+ </div>
813
+ </a>
814
+ </div>
815
+ </section>
816
+
817
+ <!-- Timeline Section -->
818
+ <section class="timeline">
819
+ <div class="section-header scroll-animate">
820
+ <div class="section-eyebrow">Organisation</div>
821
+ <h2 class="section-title">Plan de la formation</h2>
822
+ <p class="section-subtitle">
823
+ Un parcours progressif de 8 seances pour maitriser le Machine Learning.
824
+ </p>
825
+ </div>
826
+
827
+ <div class="timeline-container">
828
+ <div class="timeline-item scroll-animate">
829
+ <div class="timeline-dot">1</div>
830
+ <div class="timeline-content">
831
+ <div class="timeline-time">Seance 1 — 2h</div>
832
+ <h3 class="timeline-title">Introduction au ML & Python</h3>
833
+ <p class="timeline-text">
834
+ Fondamentaux du Machine Learning, environnement Python,
835
+ NumPy et Pandas pour la manipulation de donnees.
836
+ </p>
837
+ </div>
838
+ </div>
839
+
840
+ <div class="timeline-item scroll-animate">
841
+ <div class="timeline-dot">2</div>
842
+ <div class="timeline-content">
843
+ <div class="timeline-time">Seance 2 — 2h</div>
844
+ <h3 class="timeline-title">Pretraitement des Donnees</h3>
845
+ <p class="timeline-text">
846
+ Nettoyage, normalisation, encodage des variables categorielles
847
+ et feature engineering.
848
+ </p>
849
+ </div>
850
+ </div>
851
+
852
+ <div class="timeline-item scroll-animate">
853
+ <div class="timeline-dot">3</div>
854
+ <div class="timeline-content">
855
+ <div class="timeline-time">Seance 3 — 2h</div>
856
+ <h3 class="timeline-title">Regression Lineaire & Logistique</h3>
857
+ <p class="timeline-text">
858
+ Algorithmes de base, equations mathematiques,
859
+ implementation avec scikit-learn.
860
+ </p>
861
+ </div>
862
+ </div>
863
+
864
+ <div class="timeline-item scroll-animate">
865
+ <div class="timeline-dot">4</div>
866
+ <div class="timeline-content">
867
+ <div class="timeline-time">Seance 4 — 2h</div>
868
+ <h3 class="timeline-title">Arbres de Decision & Random Forest</h3>
869
+ <p class="timeline-text">
870
+ Classification avec arbres, bagging, boosting et
871
+ importance des features.
872
+ </p>
873
+ </div>
874
+ </div>
875
+
876
+ <div class="timeline-item scroll-animate">
877
+ <div class="timeline-dot">5</div>
878
+ <div class="timeline-content">
879
+ <div class="timeline-time">Seance 5 — 2h</div>
880
+ <h3 class="timeline-title">Reseaux de Neurones avec Keras</h3>
881
+ <p class="timeline-text">
882
+ Introduction au Deep Learning, perceptron multicouche,
883
+ activation et backpropagation.
884
+ </p>
885
+ </div>
886
+ </div>
887
+
888
+ <div class="timeline-item scroll-animate">
889
+ <div class="timeline-dot">6</div>
890
+ <div class="timeline-content">
891
+ <div class="timeline-time">Seance 6 — 2h</div>
892
+ <h3 class="timeline-title">Series Temporelles & LSTM</h3>
893
+ <p class="timeline-text">
894
+ Prediction de donnees temporelles, reseaux recurrents
895
+ et modeles LSTM avec TensorFlow.
896
+ </p>
897
+ </div>
898
+ </div>
899
+
900
+ <div class="timeline-item scroll-animate">
901
+ <div class="timeline-dot">7</div>
902
+ <div class="timeline-content">
903
+ <div class="timeline-time">Seance 7 — 2h</div>
904
+ <h3 class="timeline-title">Evaluation & Optimisation</h3>
905
+ <p class="timeline-text">
906
+ Metriques de performance, cross-validation,
907
+ grid search et eviter l'overfitting.
908
+ </p>
909
+ </div>
910
+ </div>
911
+
912
+ <div class="timeline-item scroll-animate">
913
+ <div class="timeline-dot">8</div>
914
+ <div class="timeline-content">
915
+ <div class="timeline-time">Seance 8 — 2h</div>
916
+ <h3 class="timeline-title">Projet Final & Deploiement</h3>
917
+ <p class="timeline-text">
918
+ Realisation d'un projet complet et mise en production
919
+ avec une API simple.
920
+ </p>
921
+ </div>
922
+ </div>
923
+ </div>
924
+ </section>
925
+
926
+ <!-- CTA Section -->
927
+ <section class="cta">
928
+ <div class="cta-box scroll-animate">
929
+ <div class="cta-content">
930
+ <h2 class="cta-title">Pret a commencer ?</h2>
931
+ <p class="cta-text">
932
+ Rejoignez des centaines d'etudiants qui ont deja maitrise
933
+ le Machine Learning avec notre formation.
934
+ </p>
935
+ <div class="cta-buttons">
936
+ <a href="cours.html" class="btn btn-primary btn-lg">
937
+ Commencer maintenant
938
+ </a>
939
+ <a href="tp.html" class="btn btn-outline btn-lg">
940
+ Voir les notebooks
941
+ </a>
942
+ </div>
943
+ </div>
944
+ </div>
945
+ </section>
946
+
947
+ <!-- Author Footer -->
948
+ <footer class="author-footer">
949
+ <div class="author-info">
950
+ <a href="mailto:imadmaalouf02@gmail.com" class="author-link">
951
+ <svg viewBox="0 0 24 24"><path d="M20 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 4l-8 5-8-5V6l8 5 8-5v2z"/></svg>
952
+ imadmaalouf02@gmail.com
953
+ </a>
954
+ <a href="https://github.com/imadmaalouf02" target="_blank" class="author-link">
955
+ <svg viewBox="0 0 24 24"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/></svg>
956
+ GitHub
957
+ </a>
958
+ <a href="https://huggingface.co/spaces/MAALOOUF/ML_Training" target="_blank" class="author-link">
959
+ <svg viewBox="0 0 24 24"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 17.93c-3.95-.49-7-3.85-7-7.93 0-.62.08-1.21.21-1.79L9 15v1c0 1.1.9 2 2 2v1.93zm6.9-2.54c-.26-.81-1-1.39-1.9-1.39h-1v-3c0-.55-.45-1-1-1H8v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41c2.93 1.19 5 4.06 5 7.41 0 2.08-.8 3.97-2.1 5.39z"/></svg>
960
+ Hugging Face Space
961
+ </a>
962
+ </div>
963
+ </footer>
964
+
965
+ <!-- Footer -->
966
+ <footer class="footer">
967
+ <p class="footer-text">
968
+ ML Academy — Formation Machine Learning —
969
+ <span class="footer-brand">GE-MCI 4A</span> — Promotion 2025/2026
970
+ </p>
971
+ <p class="footer-text" style="margin-top: var(--space-sm);">
972
+ Google Colab · Python · Scikit-learn · TensorFlow · Kaggle
973
+ </p>
974
+ <p class="footer-text" style="margin-top: var(--space-sm); font-size: 0.75rem; color: var(--text-muted);">
975
+ Formateur : Imad Maalouf
976
+ </p>
977
+ </footer>
978
+ </div>
979
+
980
+ <!-- Scripts -->
981
+ <script src="js/shared.js"></script>
982
+ <script>
983
+ // Scroll animations
984
+ const observerOptions = {
985
+ threshold: 0.1,
986
+ rootMargin: '0px 0px -50px 0px'
987
+ };
988
+
989
+ const observer = new IntersectionObserver((entries) => {
990
+ entries.forEach(entry => {
991
+ if (entry.isIntersecting) {
992
+ entry.target.classList.add('visible');
993
+ }
994
+ });
995
+ }, observerOptions);
996
+
997
+ document.querySelectorAll('.scroll-animate').forEach(el => {
998
+ observer.observe(el);
999
+ });
1000
+
1001
+ // Stagger animation for cards
1002
+ document.querySelectorAll('.features-grid, .modules-grid').forEach(grid => {
1003
+ const cards = grid.querySelectorAll('.feature-card, .module-card');
1004
+ cards.forEach((card, index) => {
1005
+ card.style.animationDelay = `${index * 0.1}s`;
1006
+ });
1007
+ });
1008
+ </script>
1009
+ </body>
1010
  </html>
js/feedback-storage.js ADDED
@@ -0,0 +1,236 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* ═══════════════════════════════════════════════════════════════════════════
2
+ ML ACADEMY — FEEDBACK STORAGE SYSTEM
3
+ Stocke les feedbacks au format JSON pour traitement ulterieur
4
+ ═══════════════════════════════════════════════════════════════════════════ */
5
+
6
+ class FeedbackStorage {
7
+ constructor() {
8
+ this.storageKey = 'ml_academy_feedbacks';
9
+ this.feedbacks = this.loadFeedbacks();
10
+ }
11
+
12
+ // Charge tous les feedbacks depuis le stockage
13
+ loadFeedbacks() {
14
+ try {
15
+ const stored = localStorage.getItem(this.storageKey);
16
+ return stored ? JSON.parse(stored) : [];
17
+ } catch (e) {
18
+ console.error('Erreur lors du chargement des feedbacks:', e);
19
+ return [];
20
+ }
21
+ }
22
+
23
+ // Sauvegarde tous les feedbacks
24
+ saveFeedbacks() {
25
+ try {
26
+ localStorage.setItem(this.storageKey, JSON.stringify(this.feedbacks));
27
+ return true;
28
+ } catch (e) {
29
+ console.error('Erreur lors de la sauvegarde des feedbacks:', e);
30
+ return false;
31
+ }
32
+ }
33
+
34
+ // Ajoute un nouveau feedback
35
+ addFeedback(feedbackData) {
36
+ const feedback = {
37
+ id: this.generateId(),
38
+ timestamp: new Date().toISOString(),
39
+ ...feedbackData
40
+ };
41
+
42
+ this.feedbacks.push(feedback);
43
+ this.saveFeedbacks();
44
+
45
+ // Exporte automatiquement vers un fichier JSON telechargeable
46
+ this.exportToFile();
47
+
48
+ return feedback;
49
+ }
50
+
51
+ // Genere un ID unique
52
+ generateId() {
53
+ return 'fb_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
54
+ }
55
+
56
+ // Recupere tous les feedbacks
57
+ getAllFeedbacks() {
58
+ return this.feedbacks;
59
+ }
60
+
61
+ // Recupere les feedbacks par date
62
+ getFeedbacksByDateRange(startDate, endDate) {
63
+ return this.feedbacks.filter(fb => {
64
+ const fbDate = new Date(fb.timestamp);
65
+ return fbDate >= startDate && fbDate <= endDate;
66
+ });
67
+ }
68
+
69
+ // Recupere les statistiques
70
+ getStatistics() {
71
+ if (this.feedbacks.length === 0) {
72
+ return {
73
+ total: 0,
74
+ averageRating: 0,
75
+ difficultyDistribution: {},
76
+ commonDifficulties: [],
77
+ commonSuggestions: []
78
+ };
79
+ }
80
+
81
+ const ratings = this.feedbacks.map(fb => parseInt(fb.rating) || 0);
82
+ const averageRating = ratings.reduce((a, b) => a + b, 0) / ratings.length;
83
+
84
+ // Distribution des difficultes
85
+ const difficultyDistribution = {};
86
+ this.feedbacks.forEach(fb => {
87
+ const diff = fb.difficulty || 'non-specifie';
88
+ difficultyDistribution[diff] = (difficultyDistribution[diff] || 0) + 1;
89
+ });
90
+
91
+ // Points difficiles communs
92
+ const difficultyCount = {};
93
+ this.feedbacks.forEach(fb => {
94
+ if (fb.difficiles && Array.isArray(fb.difficiles)) {
95
+ fb.difficiles.forEach(d => {
96
+ difficultyCount[d] = (difficultyCount[d] || 0) + 1;
97
+ });
98
+ }
99
+ });
100
+ const commonDifficulties = Object.entries(difficultyCount)
101
+ .sort((a, b) => b[1] - a[1])
102
+ .slice(0, 5);
103
+
104
+ // Suggestions communes
105
+ const suggestionCount = {};
106
+ this.feedbacks.forEach(fb => {
107
+ if (fb.suggestions && Array.isArray(fb.suggestions)) {
108
+ fb.suggestions.forEach(s => {
109
+ suggestionCount[s] = (suggestionCount[s] || 0) + 1;
110
+ });
111
+ }
112
+ });
113
+ const commonSuggestions = Object.entries(suggestionCount)
114
+ .sort((a, b) => b[1] - a[1])
115
+ .slice(0, 5);
116
+
117
+ return {
118
+ total: this.feedbacks.length,
119
+ averageRating: averageRating.toFixed(2),
120
+ difficultyDistribution,
121
+ commonDifficulties,
122
+ commonSuggestions
123
+ };
124
+ }
125
+
126
+ // Exporte les feedbacks vers un fichier JSON
127
+ exportToFile() {
128
+ const data = {
129
+ exportDate: new Date().toISOString(),
130
+ totalFeedbacks: this.feedbacks.length,
131
+ feedbacks: this.feedbacks,
132
+ statistics: this.getStatistics()
133
+ };
134
+
135
+ const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
136
+ const url = URL.createObjectURL(blob);
137
+
138
+ // Stocke l'URL pour telechargement ulterieur
139
+ this.lastExportUrl = url;
140
+
141
+ return url;
142
+ }
143
+
144
+ // Telecharge le fichier JSON
145
+ downloadFeedbacks() {
146
+ const url = this.exportToFile();
147
+ const a = document.createElement('a');
148
+ a.href = url;
149
+ a.download = `ml_academy_feedbacks_${new Date().toISOString().split('T')[0]}.json`;
150
+ document.body.appendChild(a);
151
+ a.click();
152
+ document.body.removeChild(a);
153
+ URL.revokeObjectURL(url);
154
+ }
155
+
156
+ // Exporte vers CSV pour Excel
157
+ exportToCSV() {
158
+ if (this.feedbacks.length === 0) return null;
159
+
160
+ const headers = [
161
+ 'ID', 'Date', 'Nom', 'Email', 'Projet',
162
+ 'Note', 'Difficulte', 'Rythme',
163
+ 'Parties Utiles', 'Points Difficiles',
164
+ 'Question Principale', 'Commentaire'
165
+ ];
166
+
167
+ const rows = this.feedbacks.map(fb => [
168
+ fb.id,
169
+ fb.timestamp,
170
+ fb.name || '',
171
+ fb.email || '',
172
+ fb.project || '',
173
+ fb.rating || '',
174
+ fb.difficulty || '',
175
+ fb.rythme || '',
176
+ (fb.utiles || []).join(';'),
177
+ (fb.difficiles || []).join(';'),
178
+ (fb.mainQuestion || '').replace(/"/g, '""'),
179
+ (fb.freeComment || '').replace(/"/g, '""')
180
+ ]);
181
+
182
+ const csv = [
183
+ headers.join(','),
184
+ ...rows.map(row => row.map(cell => `"${cell}"`).join(','))
185
+ ].join('\n');
186
+
187
+ const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
188
+ const url = URL.createObjectURL(blob);
189
+
190
+ const a = document.createElement('a');
191
+ a.href = url;
192
+ a.download = `ml_academy_feedbacks_${new Date().toISOString().split('T')[0]}.csv`;
193
+ document.body.appendChild(a);
194
+ a.click();
195
+ document.body.removeChild(a);
196
+ URL.revokeObjectURL(url);
197
+ }
198
+
199
+ // Efface tous les feedbacks (avec confirmation)
200
+ clearAll() {
201
+ if (confirm('Attention : Cette action supprimera tous les feedbacks. Continuer ?')) {
202
+ this.feedbacks = [];
203
+ this.saveFeedbacks();
204
+ return true;
205
+ }
206
+ return false;
207
+ }
208
+ }
209
+
210
+ // Instance globale
211
+ const feedbackStorage = new FeedbackStorage();
212
+
213
+ // Fonction pour soumettre un feedback depuis le formulaire
214
+ function submitFeedback(formData) {
215
+ const feedback = feedbackStorage.addFeedback(formData);
216
+ console.log('Feedback enregistre:', feedback);
217
+ return feedback;
218
+ }
219
+
220
+ // Fonction pour afficher les statistiques dans la console
221
+ function showFeedbackStats() {
222
+ const stats = feedbackStorage.getStatistics();
223
+ console.log('=== Statistiques des Feedbacks ===');
224
+ console.log(`Total: ${stats.total}`);
225
+ console.log(`Note moyenne: ${stats.averageRating}/5`);
226
+ console.log('Distribution des difficultes:', stats.difficultyDistribution);
227
+ console.log('Points difficiles communs:', stats.commonDifficulties);
228
+ console.log('Suggestions communes:', stats.commonSuggestions);
229
+ return stats;
230
+ }
231
+
232
+ // Exporte pour utilisation externe
233
+ window.FeedbackStorage = FeedbackStorage;
234
+ window.feedbackStorage = feedbackStorage;
235
+ window.submitFeedback = submitFeedback;
236
+ window.showFeedbackStats = showFeedbackStats;
js/shared.js ADDED
@@ -0,0 +1,394 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* ═══════════════════════════════════════════════════════════════════════════
2
+ ML ACADEMY — SHARED JAVASCRIPT
3
+ Animations et interactions communes à toutes les pages
4
+ ═══════════════════════════════════════════════════════════════════════════ */
5
+
6
+ // ═══════════════════════════════════════════════════════════════════════════
7
+ // NAVIGATION ACTIVE STATE
8
+ // ═══════════════════════════════════════════════════════════════════════════
9
+ document.addEventListener('DOMContentLoaded', () => {
10
+ // Mark active nav link based on current page
11
+ const currentPage = window.location.pathname.split('/').pop() || 'index.html';
12
+
13
+ document.querySelectorAll('.nav-link').forEach(link => {
14
+ const href = link.getAttribute('href');
15
+ if (href === currentPage || (currentPage === '' && href === 'index.html')) {
16
+ link.classList.add('active');
17
+ } else {
18
+ link.classList.remove('active');
19
+ }
20
+ });
21
+ });
22
+
23
+ // ═══════════════════════════════════════════════════════════════════════════
24
+ // SMOOTH SCROLL FOR ANCHOR LINKS
25
+ // ═══════════════════════════════════════════════════════════════════════════
26
+ document.querySelectorAll('a[href^="#"]').forEach(anchor => {
27
+ anchor.addEventListener('click', function(e) {
28
+ e.preventDefault();
29
+ const target = document.querySelector(this.getAttribute('href'));
30
+ if (target) {
31
+ const offsetTop = target.offsetTop - 100; // Account for fixed navbar
32
+ window.scrollTo({
33
+ top: offsetTop,
34
+ behavior: 'smooth'
35
+ });
36
+ }
37
+ });
38
+ });
39
+
40
+ // ═══════════════════════════════════════════════════════════════════════════
41
+ // SCROLL ANIMATIONS OBSERVER
42
+ // ═══════════════════════════════════════════════════════════════════════════
43
+ const scrollObserverOptions = {
44
+ root: null,
45
+ rootMargin: '0px 0px -100px 0px',
46
+ threshold: 0.1
47
+ };
48
+
49
+ const scrollObserver = new IntersectionObserver((entries) => {
50
+ entries.forEach(entry => {
51
+ if (entry.isIntersecting) {
52
+ entry.target.classList.add('visible');
53
+
54
+ // Add stagger delay for child elements if needed
55
+ const staggerChildren = entry.target.querySelectorAll('.stagger-child');
56
+ staggerChildren.forEach((child, index) => {
57
+ child.style.animationDelay = `${index * 0.1}s`;
58
+ child.classList.add('animate-in');
59
+ });
60
+ }
61
+ });
62
+ }, scrollObserverOptions);
63
+
64
+ // Observe all elements with scroll-animate class
65
+ document.querySelectorAll('.scroll-animate').forEach(el => {
66
+ scrollObserver.observe(el);
67
+ });
68
+
69
+ // ═══════════════════════════════════════════════════════════════════════════
70
+ // NAVBAR SCROLL EFFECT
71
+ // ═══════════════════════════════════════════════════════════════════════════
72
+ let lastScrollY = window.scrollY;
73
+ let ticking = false;
74
+
75
+ function updateNavbar() {
76
+ const navbar = document.querySelector('.navbar');
77
+
78
+ if (window.scrollY > 50) {
79
+ navbar.style.background = 'rgba(15, 15, 26, 0.95)';
80
+ navbar.style.boxShadow = '0 4px 20px rgba(0, 0, 0, 0.3)';
81
+ } else {
82
+ navbar.style.background = 'rgba(15, 15, 26, 0.85)';
83
+ navbar.style.boxShadow = 'none';
84
+ }
85
+
86
+ ticking = false;
87
+ }
88
+
89
+ window.addEventListener('scroll', () => {
90
+ lastScrollY = window.scrollY;
91
+
92
+ if (!ticking) {
93
+ window.requestAnimationFrame(updateNavbar);
94
+ ticking = true;
95
+ }
96
+ });
97
+
98
+ // ═══════════════════════════════════════════════════════════════════════════
99
+ // PARALLAX EFFECT FOR HERO BACKGROUND
100
+ // ═══════════════════════════════════════════════════════════════════════════
101
+ const heroBg = document.querySelector('.hero-bg');
102
+ if (heroBg) {
103
+ window.addEventListener('scroll', () => {
104
+ const scrolled = window.scrollY;
105
+ heroBg.style.transform = `translateY(${scrolled * 0.3}px)`;
106
+ });
107
+ }
108
+
109
+ // ═══════════════════════════════════════════════════════════════════════════
110
+ // TYPING EFFECT FOR HERO TEXT (optional)
111
+ // ═══════════════════════════════════════════════════════════════════════════
112
+ function typeWriter(element, text, speed = 50) {
113
+ let i = 0;
114
+ element.textContent = '';
115
+
116
+ function type() {
117
+ if (i < text.length) {
118
+ element.textContent += text.charAt(i);
119
+ i++;
120
+ setTimeout(type, speed);
121
+ }
122
+ }
123
+
124
+ type();
125
+ }
126
+
127
+ // ═══════════════════════════════════════════════════════════════════════════
128
+ // COUNTER ANIMATION FOR STATS
129
+ // ═══════════════════════════════════════════════════════════════════════════
130
+ function animateCounter(element, target, duration = 2000) {
131
+ let start = 0;
132
+ const increment = target / (duration / 16);
133
+
134
+ function updateCounter() {
135
+ start += increment;
136
+ if (start < target) {
137
+ element.textContent = Math.floor(start);
138
+ requestAnimationFrame(updateCounter);
139
+ } else {
140
+ element.textContent = target;
141
+ }
142
+ }
143
+
144
+ updateCounter();
145
+ }
146
+
147
+ // Observe stat elements and animate when visible
148
+ const statObserver = new IntersectionObserver((entries) => {
149
+ entries.forEach(entry => {
150
+ if (entry.isIntersecting && !entry.target.classList.contains('counted')) {
151
+ entry.target.classList.add('counted');
152
+ const target = parseInt(entry.target.dataset.target);
153
+ if (!isNaN(target)) {
154
+ animateCounter(entry.target, target);
155
+ }
156
+ }
157
+ });
158
+ }, { threshold: 0.5 });
159
+
160
+ document.querySelectorAll('[data-target]').forEach(el => {
161
+ statObserver.observe(el);
162
+ });
163
+
164
+ // ═══════════════════════════════════════════════════════════════════════════
165
+ // MAGNETIC BUTTON EFFECT
166
+ // ═══════════════════════════════════════════════════════════════════════════
167
+ document.querySelectorAll('.btn').forEach(button => {
168
+ button.addEventListener('mousemove', (e) => {
169
+ const rect = button.getBoundingClientRect();
170
+ const x = e.clientX - rect.left - rect.width / 2;
171
+ const y = e.clientY - rect.top - rect.height / 2;
172
+
173
+ button.style.transform = `translate(${x * 0.1}px, ${y * 0.1}px)`;
174
+ });
175
+
176
+ button.addEventListener('mouseleave', () => {
177
+ button.style.transform = '';
178
+ });
179
+ });
180
+
181
+ // ═══════════════════════════════════════════════════════════════════════════
182
+ // CARD HOVER 3D EFFECT
183
+ // ═══════════════════════════════════════════════════════════════════════════
184
+ document.querySelectorAll('.card, .feature-card, .module-card').forEach(card => {
185
+ card.addEventListener('mousemove', (e) => {
186
+ const rect = card.getBoundingClientRect();
187
+ const x = e.clientX - rect.left;
188
+ const y = e.clientY - rect.top;
189
+
190
+ const centerX = rect.width / 2;
191
+ const centerY = rect.height / 2;
192
+
193
+ const rotateX = (y - centerY) / 20;
194
+ const rotateY = (centerX - x) / 20;
195
+
196
+ card.style.transform = `perspective(1000px) rotateX(${rotateX}deg) rotateY(${rotateY}deg) translateZ(10px)`;
197
+ });
198
+
199
+ card.addEventListener('mouseleave', () => {
200
+ card.style.transform = '';
201
+ });
202
+ });
203
+
204
+ // ═══════════════════════════════════════════════════════════════════════════
205
+ // GLITCH EFFECT FOR TEXT (optional)
206
+ // ═══════════════════════════════════════��═══════════════════════════════════
207
+ function glitchText(element, originalText) {
208
+ const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
209
+ let iterations = 0;
210
+
211
+ const interval = setInterval(() => {
212
+ element.textContent = originalText
213
+ .split('')
214
+ .map((char, index) => {
215
+ if (index < iterations) {
216
+ return originalText[index];
217
+ }
218
+ return chars[Math.floor(Math.random() * chars.length)];
219
+ })
220
+ .join('');
221
+
222
+ if (iterations >= originalText.length) {
223
+ clearInterval(interval);
224
+ }
225
+
226
+ iterations += 1 / 3;
227
+ }, 30);
228
+ }
229
+
230
+ // ═══════════════════════════════════════════════════════════════════════════
231
+ // PARTICLE MOUSE INTERACTION
232
+ // ═══════════════════════════════════════════════════════════════════════════
233
+ const particlesContainer = document.querySelector('.particles-container');
234
+ if (particlesContainer) {
235
+ document.addEventListener('mousemove', (e) => {
236
+ const particles = particlesContainer.querySelectorAll('.particle');
237
+ const mouseX = e.clientX / window.innerWidth;
238
+ const mouseY = e.clientY / window.innerHeight;
239
+
240
+ particles.forEach((particle, index) => {
241
+ const speed = (index + 1) * 0.5;
242
+ const x = (mouseX - 0.5) * speed * 20;
243
+ const y = (mouseY - 0.5) * speed * 20;
244
+
245
+ particle.style.transform = `translate(${x}px, ${y}px)`;
246
+ });
247
+ });
248
+ }
249
+
250
+ // ═══════════════════════════════════════════════════════════════════════════
251
+ // LOADING ANIMATION
252
+ // ═══════════════════════════════════════════════════════════════════════════
253
+ window.addEventListener('load', () => {
254
+ document.body.classList.add('loaded');
255
+
256
+ // Animate elements with delay
257
+ document.querySelectorAll('[data-delay]').forEach(el => {
258
+ const delay = parseInt(el.dataset.delay);
259
+ setTimeout(() => {
260
+ el.classList.add('animate-in');
261
+ }, delay);
262
+ });
263
+ });
264
+
265
+ // ═══════════════════════════════════════════════════════════════════════════
266
+ // FORM VALIDATION HELPERS
267
+ // ═══════════════════════════════════════════════════════════════════════════
268
+ function validateEmail(email) {
269
+ const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
270
+ return re.test(email);
271
+ }
272
+
273
+ function validateRequired(value) {
274
+ return value.trim().length > 0;
275
+ }
276
+
277
+ // ═══════════════════════════════════════════════════════════════════════════
278
+ // TOOLTIP SYSTEM
279
+ // ═══════════════════════════════════════════════════════════════════════════
280
+ function createTooltip(element, text) {
281
+ const tooltip = document.createElement('div');
282
+ tooltip.className = 'tooltip';
283
+ tooltip.textContent = text;
284
+ tooltip.style.cssText = `
285
+ position: absolute;
286
+ background: var(--bg-tertiary);
287
+ color: var(--text-primary);
288
+ padding: 8px 12px;
289
+ border-radius: 6px;
290
+ font-size: 0.8rem;
291
+ white-space: nowrap;
292
+ z-index: 1000;
293
+ opacity: 0;
294
+ transition: opacity 0.3s ease;
295
+ pointer-events: none;
296
+ `;
297
+
298
+ document.body.appendChild(tooltip);
299
+
300
+ element.addEventListener('mouseenter', () => {
301
+ const rect = element.getBoundingClientRect();
302
+ tooltip.style.left = `${rect.left + rect.width / 2 - tooltip.offsetWidth / 2}px`;
303
+ tooltip.style.top = `${rect.top - tooltip.offsetHeight - 8}px`;
304
+ tooltip.style.opacity = '1';
305
+ });
306
+
307
+ element.addEventListener('mouseleave', () => {
308
+ tooltip.style.opacity = '0';
309
+ });
310
+ }
311
+
312
+ // ═══════════════════════════════════════════════════════════════════════════
313
+ // COPY TO CLIPBOARD
314
+ // ═════════════════════════════════════════════════════════��═════════════════
315
+ async function copyToClipboard(text) {
316
+ try {
317
+ await navigator.clipboard.writeText(text);
318
+ showNotification('Copié dans le presse-papier !', 'success');
319
+ } catch (err) {
320
+ showNotification('Erreur lors de la copie', 'error');
321
+ }
322
+ }
323
+
324
+ // ═══════════════════════════════════════════════════════════════════════════
325
+ // NOTIFICATION SYSTEM
326
+ // ═══════════════════════════════════════════════════════════════════════════
327
+ function showNotification(message, type = 'info') {
328
+ const notification = document.createElement('div');
329
+ notification.className = `notification notification-${type}`;
330
+ notification.textContent = message;
331
+ notification.style.cssText = `
332
+ position: fixed;
333
+ top: 80px;
334
+ right: 20px;
335
+ padding: 12px 24px;
336
+ background: var(--bg-card);
337
+ border: 1px solid var(--border-color);
338
+ border-radius: 8px;
339
+ font-size: 0.9rem;
340
+ z-index: 10000;
341
+ animation: slideInRight 0.3s ease;
342
+ `;
343
+
344
+ if (type === 'success') {
345
+ notification.style.borderColor = 'var(--success)';
346
+ notification.style.color = 'var(--success)';
347
+ } else if (type === 'error') {
348
+ notification.style.borderColor = 'var(--danger)';
349
+ notification.style.color = 'var(--danger)';
350
+ }
351
+
352
+ document.body.appendChild(notification);
353
+
354
+ setTimeout(() => {
355
+ notification.style.animation = 'slideOutRight 0.3s ease';
356
+ setTimeout(() => notification.remove(), 300);
357
+ }, 3000);
358
+ }
359
+
360
+ // ═══════════════════════════════════════════════════════════════════════════
361
+ // KEYBOARD SHORTCUTS
362
+ // ═══════════════════════════════════════════════════════════════════════════
363
+ document.addEventListener('keydown', (e) => {
364
+ // Ctrl/Cmd + K for search (if implemented)
365
+ if ((e.ctrlKey || e.metaKey) && e.key === 'k') {
366
+ e.preventDefault();
367
+ // Open search modal
368
+ }
369
+
370
+ // Escape to close modals
371
+ if (e.key === 'Escape') {
372
+ document.querySelectorAll('.modal.open').forEach(modal => {
373
+ modal.classList.remove('open');
374
+ });
375
+ }
376
+ });
377
+
378
+ // ═══════════════════════════════════════════════════════════════════════════
379
+ // PREFERS REDUCED MOTION
380
+ // ═══════════════════════════════════════════════════════════════════════════
381
+ const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)');
382
+
383
+ if (prefersReducedMotion.matches) {
384
+ document.documentElement.style.setProperty('--transition-fast', '0s');
385
+ document.documentElement.style.setProperty('--transition-base', '0s');
386
+ document.documentElement.style.setProperty('--transition-slow', '0s');
387
+ }
388
+
389
+ // ═══════════════════════════════════════════════════════════════════════════
390
+ // CONSOLE EASTER EGG
391
+ // ═══════════════════════════════════════════════════════════════════════════
392
+ console.log('%c🧠 ML Academy', 'font-size: 24px; font-weight: bold; color: #6366f1;');
393
+ console.log('%cFormation Machine Learning — GE-MCI 4A', 'font-size: 14px; color: #94a3b8;');
394
+ console.log('%cBienvenue dans la console ! Curieux de voir comment ça marche ?', 'font-size: 12px; color: #64748b;');
notebooks/TP1_Titanic_Survival.ipynb ADDED
@@ -0,0 +1,508 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "# 🚢 TP-1 : Survie sur le Titanic — Classification\n",
8
+ "\n",
9
+ "**Objectif** : Prédire la survie des passagers du Titanic à partir de leurs caractéristiques.\n",
10
+ "\n",
11
+ "**Dataset** : [Titanic - Machine Learning from Disaster](https://www.kaggle.com/competitions/titanic)\n",
12
+ "\n",
13
+ "**Compétences** :\n",
14
+ "- Prétraitement des données (valeurs manquantes, encodage)\n",
15
+ "- Feature Engineering\n",
16
+ "- Classification avec Random Forest\n",
17
+ "- Évaluation des modèles"
18
+ ]
19
+ },
20
+ {
21
+ "cell_type": "markdown",
22
+ "metadata": {},
23
+ "source": [
24
+ "## 📋 Table des matières\n",
25
+ "\n",
26
+ "1. [Import des bibliothèques](#section-1)\n",
27
+ "2. [Chargement et exploration des données](#section-2)\n",
28
+ "3. [Prétraitement des données](#section-3)\n",
29
+ "4. [Feature Engineering](#section-4)\n",
30
+ "5. [Modélisation](#section-5)\n",
31
+ "6. [Évaluation et interprétation](#section-6)"
32
+ ]
33
+ },
34
+ {
35
+ "cell_type": "markdown",
36
+ "metadata": {},
37
+ "source": [
38
+ "<a id='section-1'></a>\n",
39
+ "## 1️⃣ Import des bibliothèques"
40
+ ]
41
+ },
42
+ {
43
+ "cell_type": "code",
44
+ "execution_count": null,
45
+ "metadata": {},
46
+ "outputs": [],
47
+ "source": [
48
+ "# Manipulation de données\n",
49
+ "import numpy as np\n",
50
+ "import pandas as pd\n",
51
+ "\n",
52
+ "# Visualisation\n",
53
+ "import matplotlib.pyplot as plt\n",
54
+ "import seaborn as sns\n",
55
+ "\n",
56
+ "# Machine Learning\n",
57
+ "from sklearn.model_selection import train_test_split, cross_val_score, GridSearchCV\n",
58
+ "from sklearn.preprocessing import LabelEncoder, StandardScaler\n",
59
+ "from sklearn.ensemble import RandomForestClassifier\n",
60
+ "from sklearn.linear_model import LogisticRegression\n",
61
+ "from sklearn.metrics import accuracy_score, classification_report, confusion_matrix\n",
62
+ "\n",
63
+ "# Configuration\n",
64
+ "sns.set_style('whitegrid')\n",
65
+ "plt.rcParams['figure.figsize'] = (10, 6)\n",
66
+ "\n",
67
+ "print(\"✅ Bibliothèques importées avec succès !\")"
68
+ ]
69
+ },
70
+ {
71
+ "cell_type": "markdown",
72
+ "metadata": {},
73
+ "source": [
74
+ "<a id='section-2'></a>\n",
75
+ "## 2️⃣ Chargement et exploration des données"
76
+ ]
77
+ },
78
+ {
79
+ "cell_type": "code",
80
+ "execution_count": null,
81
+ "metadata": {},
82
+ "outputs": [],
83
+ "source": [
84
+ "# Chargement des données\n",
85
+ "# Note: Sur Kaggle, utilisez directement le chemin /kaggle/input/\n",
86
+ "train_df = pd.read_csv('https://raw.githubusercontent.com/datasciencedojo/datasets/master/titanic.csv')\n",
87
+ "\n",
88
+ "print(f\"📊 Dimensions du dataset : {train_df.shape}\")\n",
89
+ "print(f\"\\n📋 Colonnes : {list(train_df.columns)}\")"
90
+ ]
91
+ },
92
+ {
93
+ "cell_type": "code",
94
+ "execution_count": null,
95
+ "metadata": {},
96
+ "outputs": [],
97
+ "source": [
98
+ "# Aperçu des données\n",
99
+ "train_df.head(10)"
100
+ ]
101
+ },
102
+ {
103
+ "cell_type": "code",
104
+ "execution_count": null,
105
+ "metadata": {},
106
+ "outputs": [],
107
+ "source": [
108
+ "# Informations sur les données\n",
109
+ "train_df.info()"
110
+ ]
111
+ },
112
+ {
113
+ "cell_type": "code",
114
+ "execution_count": null,
115
+ "metadata": {},
116
+ "outputs": [],
117
+ "source": [
118
+ "# Statistiques descriptives\n",
119
+ "train_df.describe()"
120
+ ]
121
+ },
122
+ {
123
+ "cell_type": "code",
124
+ "execution_count": null,
125
+ "metadata": {},
126
+ "outputs": [],
127
+ "source": [
128
+ "# Valeurs manquantes\n",
129
+ "missing_values = train_df.isnull().sum()\n",
130
+ "missing_percent = (missing_values / len(train_df)) * 100\n",
131
+ "\n",
132
+ "missing_df = pd.DataFrame({\n",
133
+ " 'Valeurs manquantes': missing_values,\n",
134
+ " 'Pourcentage': missing_percent\n",
135
+ "}).sort_values('Pourcentage', ascending=False)\n",
136
+ "\n",
137
+ "print(\"🔍 Valeurs manquantes :\")\n",
138
+ "print(missing_df[missing_df['Valeurs manquantes'] > 0])"
139
+ ]
140
+ },
141
+ {
142
+ "cell_type": "markdown",
143
+ "metadata": {},
144
+ "source": [
145
+ "### 📊 Visualisation de la distribution"
146
+ ]
147
+ },
148
+ {
149
+ "cell_type": "code",
150
+ "execution_count": null,
151
+ "metadata": {},
152
+ "outputs": [],
153
+ "source": [
154
+ "fig, axes = plt.subplots(2, 3, figsize=(15, 10))\n",
155
+ "\n",
156
+ "# Distribution de la survie\n",
157
+ "sns.countplot(data=train_df, x='Survived', ax=axes[0, 0])\n",
158
+ "axes[0, 0].set_title('Distribution de la survie')\n",
159
+ "axes[0, 0].set_xticklabels(['Non survécu', 'Survécu'])\n",
160
+ "\n",
161
+ "# Survie par sexe\n",
162
+ "sns.countplot(data=train_df, x='Sex', hue='Survived', ax=axes[0, 1])\n",
163
+ "axes[0, 1].set_title('Survie par sexe')\n",
164
+ "\n",
165
+ "# Survie par classe\n",
166
+ "sns.countplot(data=train_df, x='Pclass', hue='Survived', ax=axes[0, 2])\n",
167
+ "axes[0, 2].set_title('Survie par classe')\n",
168
+ "\n",
169
+ "# Distribution de l'âge\n",
170
+ "sns.histplot(data=train_df, x='Age', hue='Survived', bins=30, kde=True, ax=axes[1, 0])\n",
171
+ "axes[1, 0].set_title('Distribution de l\\'âge par survie')\n",
172
+ "\n",
173
+ "# Distribution du prix du billet\n",
174
+ "sns.histplot(data=train_df, x='Fare', hue='Survived', bins=30, kde=True, ax=axes[1, 1])\n",
175
+ "axes[1, 1].set_title('Distribution du prix par survie')\n",
176
+ "\n",
177
+ "# Survie par port d'embarquement\n",
178
+ "sns.countplot(data=train_df, x='Embarked', hue='Survived', ax=axes[1, 2])\n",
179
+ "axes[1, 2].set_title('Survie par port d\\'embarquement')\n",
180
+ "\n",
181
+ "plt.tight_layout()\n",
182
+ "plt.show()"
183
+ ]
184
+ },
185
+ {
186
+ "cell_type": "markdown",
187
+ "metadata": {},
188
+ "source": [
189
+ "<a id='section-3'></a>\n",
190
+ "## 3️⃣ Prétraitement des données"
191
+ ]
192
+ },
193
+ {
194
+ "cell_type": "code",
195
+ "execution_count": null,
196
+ "metadata": {},
197
+ "outputs": [],
198
+ "source": [
199
+ "# Création d'une copie pour le prétraitement\n",
200
+ "df = train_df.copy()\n",
201
+ "\n",
202
+ "# Suppression des colonnes inutiles\n",
203
+ "df = df.drop(['PassengerId', 'Name', 'Ticket', 'Cabin'], axis=1)\n",
204
+ "\n",
205
+ "print(\"🗑️ Colonnes supprimées : PassengerId, Name, Ticket, Cabin\")"
206
+ ]
207
+ },
208
+ {
209
+ "cell_type": "code",
210
+ "execution_count": null,
211
+ "metadata": {},
212
+ "outputs": [],
213
+ "source": [
214
+ "# Gestion des valeurs manquantes\n",
215
+ "\n",
216
+ "# Age : remplissage par la médiane\n",
217
+ "df['Age'].fillna(df['Age'].median(), inplace=True)\n",
218
+ "\n",
219
+ "# Embarked : remplissage par le mode (valeur la plus fréquente)\n",
220
+ "df['Embarked'].fillna(df['Embarked'].mode()[0], inplace=True)\n",
221
+ "\n",
222
+ "# Fare : remplissage par la médiane\n",
223
+ "df['Fare'].fillna(df['Fare'].median(), inplace=True)\n",
224
+ "\n",
225
+ "print(\"✅ Valeurs manquantes traitées\")\n",
226
+ "print(f\"Valeurs manquantes restantes : {df.isnull().sum().sum()}\")"
227
+ ]
228
+ },
229
+ {
230
+ "cell_type": "code",
231
+ "execution_count": null,
232
+ "metadata": {},
233
+ "outputs": [],
234
+ "source": [
235
+ "# Encodage des variables catégorielles\n",
236
+ "\n",
237
+ "# Sex : Male=0, Female=1\n",
238
+ "df['Sex'] = df['Sex'].map({'male': 0, 'female': 1})\n",
239
+ "\n",
240
+ "# Embarked : One-hot encoding\n",
241
+ "df = pd.get_dummies(df, columns=['Embarked'], prefix='Embarked')\n",
242
+ "\n",
243
+ "print(\"✅ Variables catégorielles encodées\")\n",
244
+ "df.head()"
245
+ ]
246
+ },
247
+ {
248
+ "cell_type": "markdown",
249
+ "metadata": {},
250
+ "source": [
251
+ "<a id='section-4'></a>\n",
252
+ "## 4️⃣ Feature Engineering"
253
+ ]
254
+ },
255
+ {
256
+ "cell_type": "code",
257
+ "execution_count": null,
258
+ "metadata": {},
259
+ "outputs": [],
260
+ "source": [
261
+ "# Création de nouvelles features\n",
262
+ "\n",
263
+ "# FamilySize : taille de la famille\n",
264
+ "df['FamilySize'] = df['SibSp'] + df['Parch'] + 1\n",
265
+ "\n",
266
+ "# IsAlone : voyage seul ou non\n",
267
+ "df['IsAlone'] = (df['FamilySize'] == 1).astype(int)\n",
268
+ "\n",
269
+ "# AgeGroup : groupes d'âge\n",
270
+ "df['AgeGroup'] = pd.cut(df['Age'], bins=[0, 12, 18, 35, 60, 100], \n",
271
+ " labels=['Enfant', 'Adolescent', 'Adulte', 'Mature', 'Senior'])\n",
272
+ "\n",
273
+ "# FarePerPerson : prix par personne\n",
274
+ "df['FarePerPerson'] = df['Fare'] / df['FamilySize']\n",
275
+ "\n",
276
+ "print(\"✅ Nouvelles features créées :\")\n",
277
+ "print(\" - FamilySize : taille de la famille\")\n",
278
+ "print(\" - IsAlone : voyage seul\")\n",
279
+ "print(\" - AgeGroup : groupe d'âge\")\n",
280
+ "print(\" - FarePerPerson : prix par personne\")"
281
+ ]
282
+ },
283
+ {
284
+ "cell_type": "code",
285
+ "execution_count": null,
286
+ "metadata": {},
287
+ "outputs": [],
288
+ "source": [
289
+ "# Encodage de AgeGroup\n",
290
+ "df = pd.get_dummies(df, columns=['AgeGroup'], prefix='Age')\n",
291
+ "\n",
292
+ "df.head()"
293
+ ]
294
+ },
295
+ {
296
+ "cell_type": "markdown",
297
+ "metadata": {},
298
+ "source": [
299
+ "<a id='section-5'></a>\n",
300
+ "## 5️⃣ Modélisation"
301
+ ]
302
+ },
303
+ {
304
+ "cell_type": "code",
305
+ "execution_count": null,
306
+ "metadata": {},
307
+ "outputs": [],
308
+ "source": [
309
+ "# Séparation des features et de la cible\n",
310
+ "X = df.drop('Survived', axis=1)\n",
311
+ "y = df['Survived']\n",
312
+ "\n",
313
+ "# Split train/test\n",
314
+ "X_train, X_test, y_train, y_test = train_test_split(\n",
315
+ " X, y, test_size=0.2, random_state=42, stratify=y\n",
316
+ ")\n",
317
+ "\n",
318
+ "print(f\"📊 Train set : {X_train.shape[0]} échantillons\")\n",
319
+ "print(f\"📊 Test set : {X_test.shape[0]} échantillons\")"
320
+ ]
321
+ },
322
+ {
323
+ "cell_type": "code",
324
+ "execution_count": null,
325
+ "metadata": {},
326
+ "outputs": [],
327
+ "source": [
328
+ "# Modèle 1 : Régression Logistique\n",
329
+ "lr_model = LogisticRegression(max_iter=1000, random_state=42)\n",
330
+ "lr_model.fit(X_train, y_train)\n",
331
+ "\n",
332
+ "lr_pred = lr_model.predict(X_test)\n",
333
+ "lr_accuracy = accuracy_score(y_test, lr_pred)\n",
334
+ "\n",
335
+ "print(f\"🎯 Régression Logistique - Accuracy : {lr_accuracy:.4f}\")"
336
+ ]
337
+ },
338
+ {
339
+ "cell_type": "code",
340
+ "execution_count": null,
341
+ "metadata": {},
342
+ "outputs": [],
343
+ "source": [
344
+ "# Modèle 2 : Random Forest\n",
345
+ "rf_model = RandomForestClassifier(\n",
346
+ " n_estimators=100,\n",
347
+ " max_depth=10,\n",
348
+ " min_samples_split=5,\n",
349
+ " random_state=42\n",
350
+ ")\n",
351
+ "rf_model.fit(X_train, y_train)\n",
352
+ "\n",
353
+ "rf_pred = rf_model.predict(X_test)\n",
354
+ "rf_accuracy = accuracy_score(y_test, rf_pred)\n",
355
+ "\n",
356
+ "print(f\"🌲 Random Forest - Accuracy : {rf_accuracy:.4f}\")"
357
+ ]
358
+ },
359
+ {
360
+ "cell_type": "code",
361
+ "execution_count": null,
362
+ "metadata": {},
363
+ "outputs": [],
364
+ "source": [
365
+ "# Optimisation des hyperparamètres avec GridSearch\n",
366
+ "param_grid = {\n",
367
+ " 'n_estimators': [50, 100, 200],\n",
368
+ " 'max_depth': [5, 10, 15, None],\n",
369
+ " 'min_samples_split': [2, 5, 10]\n",
370
+ "}\n",
371
+ "\n",
372
+ "grid_search = GridSearchCV(\n",
373
+ " RandomForestClassifier(random_state=42),\n",
374
+ " param_grid,\n",
375
+ " cv=5,\n",
376
+ " scoring='accuracy',\n",
377
+ " n_jobs=-1\n",
378
+ ")\n",
379
+ "\n",
380
+ "print(\"⏳ Optimisation en cours...\")\n",
381
+ "grid_search.fit(X_train, y_train)\n",
382
+ "\n",
383
+ "print(f\"\\n✅ Meilleurs paramètres : {grid_search.best_params_}\")\n",
384
+ "print(f\"✅ Meilleure accuracy CV : {grid_search.best_score_:.4f}\")"
385
+ ]
386
+ },
387
+ {
388
+ "cell_type": "markdown",
389
+ "metadata": {},
390
+ "source": [
391
+ "<a id='section-6'></a>\n",
392
+ "## 6️⃣ Évaluation et interprétation"
393
+ ]
394
+ },
395
+ {
396
+ "cell_type": "code",
397
+ "execution_count": null,
398
+ "metadata": {},
399
+ "outputs": [],
400
+ "source": [
401
+ "# Meilleur modèle\n",
402
+ "best_model = grid_search.best_estimator_\n",
403
+ "best_pred = best_model.predict(X_test)\n",
404
+ "\n",
405
+ "print(\"📊 Rapport de classification :\")\n",
406
+ "print(classification_report(y_test, best_pred, target_names=['Non survécu', 'Survécu']))"
407
+ ]
408
+ },
409
+ {
410
+ "cell_type": "code",
411
+ "execution_count": null,
412
+ "metadata": {},
413
+ "outputs": [],
414
+ "source": [
415
+ "# Matrice de confusion\n",
416
+ "cm = confusion_matrix(y_test, best_pred)\n",
417
+ "\n",
418
+ "plt.figure(figsize=(8, 6))\n",
419
+ "sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', \n",
420
+ " xticklabels=['Non survécu', 'Survécu'],\n",
421
+ " yticklabels=['Non survécu', 'Survécu'])\n",
422
+ "plt.title('Matrice de confusion')\n",
423
+ "plt.ylabel('Vrai label')\n",
424
+ "plt.xlabel('Prédiction')\n",
425
+ "plt.show()"
426
+ ]
427
+ },
428
+ {
429
+ "cell_type": "code",
430
+ "execution_count": null,
431
+ "metadata": {},
432
+ "outputs": [],
433
+ "source": [
434
+ "# Importance des features\n",
435
+ "feature_importance = pd.DataFrame({\n",
436
+ " 'feature': X.columns,\n",
437
+ " 'importance': best_model.feature_importances_\n",
438
+ "}).sort_values('importance', ascending=False)\n",
439
+ "\n",
440
+ "plt.figure(figsize=(10, 6))\n",
441
+ "sns.barplot(data=feature_importance.head(10), x='importance', y='feature', palette='viridis')\n",
442
+ "plt.title('Top 10 - Importance des features')\n",
443
+ "plt.xlabel('Importance')\n",
444
+ "plt.tight_layout()\n",
445
+ "plt.show()"
446
+ ]
447
+ },
448
+ {
449
+ "cell_type": "code",
450
+ "execution_count": null,
451
+ "metadata": {},
452
+ "outputs": [],
453
+ "source": [
454
+ "# Cross-validation finale\n",
455
+ "cv_scores = cross_val_score(best_model, X, y, cv=5, scoring='accuracy')\n",
456
+ "\n",
457
+ "print(f\"📊 Cross-validation (5-fold) :\")\n",
458
+ "print(f\" Mean accuracy : {cv_scores.mean():.4f}\")\n",
459
+ "print(f\" Std accuracy : {cv_scores.std():.4f}\")\n",
460
+ "print(f\" Scores : {cv_scores}\")"
461
+ ]
462
+ },
463
+ {
464
+ "cell_type": "markdown",
465
+ "metadata": {},
466
+ "source": [
467
+ "## 🎓 Conclusion\n",
468
+ "\n",
469
+ "Dans ce TP, nous avons :\n",
470
+ "\n",
471
+ "1. ✅ **Exploré** le dataset Titanic et identifié les patterns clés\n",
472
+ "2. ✅ **Prétraité** les données (valeurs manquantes, encodage)\n",
473
+ "3. ✅ **Créé** de nouvelles features pertinentes\n",
474
+ "4. ✅ **Entraîné** plusieurs modèles de classification\n",
475
+ "5. ✅ **Optimisé** les hyperparamètres avec GridSearch\n",
476
+ "6. ✅ **Évalué** le modèle et analysé l'importance des features\n",
477
+ "\n",
478
+ "**Résultat** : Accuracy de ~82% avec Random Forest optimisé.\n",
479
+ "\n",
480
+ "**Prochaines étapes** :\n",
481
+ "- Tester d'autres algorithmes (XGBoost, SVM)\n",
482
+ "- Explorer plus de features (extraction du titre du nom)\n",
483
+ "- Soumettre sur Kaggle pour voir le score public"
484
+ ]
485
+ }
486
+ ],
487
+ "metadata": {
488
+ "kernelspec": {
489
+ "display_name": "Python 3",
490
+ "language": "python",
491
+ "name": "python3"
492
+ },
493
+ "language_info": {
494
+ "codemirror_mode": {
495
+ "name": "ipython",
496
+ "version": 3
497
+ },
498
+ "file_extension": ".py",
499
+ "mimetype": "text/x-python",
500
+ "name": "python",
501
+ "nbconvert_exporter": "python",
502
+ "pygments_lexer": "ipython3",
503
+ "version": "3.8.0"
504
+ }
505
+ },
506
+ "nbformat": 4,
507
+ "nbformat_minor": 4
508
+ }
notebooks/TP2_House_Prices.ipynb ADDED
@@ -0,0 +1,436 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "# 🏠 TP-2 : Prédiction des Prix Immobiliers — Régression Avancée\n",
8
+ "\n",
9
+ "**Objectif** : Prédire le prix de vente des maisons à Ames, Iowa.\n",
10
+ "\n",
11
+ "**Dataset** : [House Prices - Advanced Regression Techniques](https://www.kaggle.com/competitions/house-prices-advanced-regression-techniques)\n",
12
+ "\n",
13
+ "**Compétences** :\n",
14
+ "- Feature Engineering avancé\n",
15
+ "- Gestion des outliers\n",
16
+ "- Modèles de boosting (XGBoost, LightGBM)\n",
17
+ "- Stacking d'algorithmes"
18
+ ]
19
+ },
20
+ {
21
+ "cell_type": "markdown",
22
+ "metadata": {},
23
+ "source": [
24
+ "## 📋 Table des matières\n",
25
+ "\n",
26
+ "1. [Import et chargement](#section-1)\n",
27
+ "2. [Analyse exploratoire avancée](#section-2)\n",
28
+ "3. [Prétraitement](#section-3)\n",
29
+ "4. [Feature Engineering](#section-4)\n",
30
+ "5. [Modélisation avec XGBoost](#section-5)\n",
31
+ "6. [Stacking et soumission](#section-6)"
32
+ ]
33
+ },
34
+ {
35
+ "cell_type": "markdown",
36
+ "metadata": {},
37
+ "source": [
38
+ "<a id='section-1'></a>\n",
39
+ "## 1️⃣ Import et chargement"
40
+ ]
41
+ },
42
+ {
43
+ "cell_type": "code",
44
+ "execution_count": null,
45
+ "metadata": {},
46
+ "outputs": [],
47
+ "source": [
48
+ "import numpy as np\n",
49
+ "import pandas as pd\n",
50
+ "import matplotlib.pyplot as plt\n",
51
+ "import seaborn as sns\n",
52
+ "from scipy import stats\n",
53
+ "from scipy.special import boxcox1p\n",
54
+ "\n",
55
+ "from sklearn.model_selection import KFold, cross_val_score\n",
56
+ "from sklearn.preprocessing import LabelEncoder, RobustScaler\n",
57
+ "from sklearn.impute import SimpleImputer\n",
58
+ "from sklearn.linear_model import Lasso, Ridge, ElasticNet\n",
59
+ "from sklearn.ensemble import GradientBoostingRegressor, RandomForestRegressor, StackingRegressor\n",
60
+ "from sklearn.metrics import mean_squared_error\n",
61
+ "\n",
62
+ "import xgboost as xgb\n",
63
+ "import lightgbm as lgb\n",
64
+ "\n",
65
+ "import warnings\n",
66
+ "warnings.filterwarnings('ignore')\n",
67
+ "\n",
68
+ "sns.set_style('whitegrid')\n",
69
+ "plt.rcParams['figure.figsize'] = (12, 8)\n",
70
+ "\n",
71
+ "print(\"✅ Bibliothèques importées !\")"
72
+ ]
73
+ },
74
+ {
75
+ "cell_type": "code",
76
+ "execution_count": null,
77
+ "metadata": {},
78
+ "outputs": [],
79
+ "source": [
80
+ "# Chargement des données\n",
81
+ "train = pd.read_csv('https://raw.githubusercontent.com/ageron/handson-ml2/master/datasets/housing/housing.csv')\n",
82
+ "\n",
83
+ "# Pour ce TP, nous utilisons le California Housing Dataset comme alternative\n",
84
+ "# Sur Kaggle, utilisez : train = pd.read_csv('../input/house-prices/train.csv')\n",
85
+ "\n",
86
+ "print(f\"📊 Dimensions : {train.shape}\")\n",
87
+ "train.head()"
88
+ ]
89
+ },
90
+ {
91
+ "cell_type": "markdown",
92
+ "metadata": {},
93
+ "source": [
94
+ "<a id='section-2'></a>\n",
95
+ "## 2️⃣ Analyse exploratoire avancée"
96
+ ]
97
+ },
98
+ {
99
+ "cell_type": "code",
100
+ "execution_count": null,
101
+ "metadata": {},
102
+ "outputs": [],
103
+ "source": [
104
+ "# Distribution de la cible\n",
105
+ "fig, axes = plt.subplots(1, 2, figsize=(14, 5))\n",
106
+ "\n",
107
+ "# Avant transformation\n",
108
+ "sns.histplot(train['median_house_value'], kde=True, ax=axes[0])\n",
109
+ "axes[0].set_title('Distribution des prix (original)')\n",
110
+ "\n",
111
+ "# Après log transformation\n",
112
+ "sns.histplot(np.log1p(train['median_house_value']), kde=True, ax=axes[1])\n",
113
+ "axes[1].set_title('Distribution des prix (log)')\n",
114
+ "\n",
115
+ "plt.tight_layout()\n",
116
+ "plt.show()"
117
+ ]
118
+ },
119
+ {
120
+ "cell_type": "code",
121
+ "execution_count": null,
122
+ "metadata": {},
123
+ "outputs": [],
124
+ "source": [
125
+ "# Corrélation avec la cible\n",
126
+ "correlations = train.corr()['median_house_value'].sort_values(ascending=False)\n",
127
+ "\n",
128
+ "plt.figure(figsize=(10, 6))\n",
129
+ "correlations.drop('median_house_value').plot(kind='barh')\n",
130
+ "plt.title('Corrélation avec le prix des maisons')\n",
131
+ "plt.xlabel('Corrélation')\n",
132
+ "plt.tight_layout()\n",
133
+ "plt.show()"
134
+ ]
135
+ },
136
+ {
137
+ "cell_type": "code",
138
+ "execution_count": null,
139
+ "metadata": {},
140
+ "outputs": [],
141
+ "source": [
142
+ "# Scatter plots des features les plus corrélées\n",
143
+ "fig, axes = plt.subplots(2, 2, figsize=(14, 10))\n",
144
+ "\n",
145
+ "features = ['median_income', 'total_rooms', 'housing_median_age', 'latitude']\n",
146
+ "\n",
147
+ "for idx, feature in enumerate(features):\n",
148
+ " row, col = idx // 2, idx % 2\n",
149
+ " axes[row, col].scatter(train[feature], train['median_house_value'], alpha=0.3)\n",
150
+ " axes[row, col].set_xlabel(feature)\n",
151
+ " axes[row, col].set_ylabel('Prix')\n",
152
+ " axes[row, col].set_title(f'{feature} vs Prix')\n",
153
+ "\n",
154
+ "plt.tight_layout()\n",
155
+ "plt.show()"
156
+ ]
157
+ },
158
+ {
159
+ "cell_type": "markdown",
160
+ "metadata": {},
161
+ "source": [
162
+ "<a id='section-3'></a>\n",
163
+ "## 3️⃣ Prétraitement"
164
+ ]
165
+ },
166
+ {
167
+ "cell_type": "code",
168
+ "execution_count": null,
169
+ "metadata": {},
170
+ "outputs": [],
171
+ "source": [
172
+ "# Gestion des valeurs manquantes\n",
173
+ "print(\"Valeurs manquantes :\")\n",
174
+ "print(train.isnull().sum()[train.isnull().sum() > 0])\n",
175
+ "\n",
176
+ "# Remplissage des valeurs manquantes\n",
177
+ "train['total_bedrooms'].fillna(train['total_bedrooms'].median(), inplace=True)"
178
+ ]
179
+ },
180
+ {
181
+ "cell_type": "code",
182
+ "execution_count": null,
183
+ "metadata": {},
184
+ "outputs": [],
185
+ "source": [
186
+ "# Encodage des variables catégorielles\n",
187
+ "le = LabelEncoder()\n",
188
+ "train['ocean_proximity_encoded'] = le.fit_transform(train['ocean_proximity'])\n",
189
+ "\n",
190
+ "print(\"✅ Variables catégorielles encodées\")"
191
+ ]
192
+ },
193
+ {
194
+ "cell_type": "markdown",
195
+ "metadata": {},
196
+ "source": [
197
+ "<a id='section-4'></a>\n",
198
+ "## 4️⃣ Feature Engineering"
199
+ ]
200
+ },
201
+ {
202
+ "cell_type": "code",
203
+ "execution_count": null,
204
+ "metadata": {},
205
+ "outputs": [],
206
+ "source": [
207
+ "# Création de nouvelles features\n",
208
+ "\n",
209
+ "# Chambres par personne\n",
210
+ "train['bedrooms_per_person'] = train['total_bedrooms'] / train['population']\n",
211
+ "\n",
212
+ "# Pièces par ménage\n",
213
+ "train['rooms_per_household'] = train['total_rooms'] / train['households']\n",
214
+ "\n",
215
+ "# Densité de population\n",
216
+ "train['population_per_household'] = train['population'] / train['households']\n",
217
+ "\n",
218
+ "# Catégorisation du revenu\n",
219
+ "train['income_category'] = pd.cut(train['median_income'],\n",
220
+ " bins=[0, 1.5, 3, 4.5, 6, np.inf],\n",
221
+ " labels=[1, 2, 3, 4, 5])\n",
222
+ "\n",
223
+ "print(\"✅ Nouvelles features créées\")\n",
224
+ "print(train[['bedrooms_per_person', 'rooms_per_household', 'population_per_household', 'income_category']].head())"
225
+ ]
226
+ },
227
+ {
228
+ "cell_type": "code",
229
+ "execution_count": null,
230
+ "metadata": {},
231
+ "outputs": [],
232
+ "source": [
233
+ "# Préparation des données pour la modélisation\n",
234
+ "features = ['longitude', 'latitude', 'housing_median_age', 'total_rooms',\n",
235
+ " 'total_bedrooms', 'population', 'households', 'median_income',\n",
236
+ " 'ocean_proximity_encoded', 'bedrooms_per_person',\n",
237
+ " 'rooms_per_household', 'population_per_household']\n",
238
+ "\n",
239
+ "X = train[features]\n",
240
+ "y = np.log1p(train['median_house_value']) # Log transformation de la cible\n",
241
+ "\n",
242
+ "print(f\"Features utilisées : {len(features)}\")\n",
243
+ "print(f\"X shape : {X.shape}\")"
244
+ ]
245
+ },
246
+ {
247
+ "cell_type": "markdown",
248
+ "metadata": {},
249
+ "source": [
250
+ "<a id='section-5'></a>\n",
251
+ "## 5️⃣ Modélisation avec XGBoost"
252
+ ]
253
+ },
254
+ {
255
+ "cell_type": "code",
256
+ "execution_count": null,
257
+ "metadata": {},
258
+ "outputs": [],
259
+ "source": [
260
+ "# Fonction d'évaluation\n",
261
+ "def rmse_cv(model, X, y, cv=5):\n",
262
+ " kf = KFold(cv, shuffle=True, random_state=42)\n",
263
+ " rmse = np.sqrt(-cross_val_score(model, X, y, scoring='neg_mean_squared_error', cv=kf))\n",
264
+ " return rmse\n",
265
+ "\n",
266
+ "# Modèle XGBoost\n",
267
+ "xgb_model = xgb.XGBRegressor(\n",
268
+ " n_estimators=1000,\n",
269
+ " learning_rate=0.05,\n",
270
+ " max_depth=6,\n",
271
+ " subsample=0.8,\n",
272
+ " colsample_bytree=0.8,\n",
273
+ " random_state=42,\n",
274
+ " n_jobs=-1\n",
275
+ ")\n",
276
+ "\n",
277
+ "print(\"⏳ Évaluation XGBoost...\")\n",
278
+ "xgb_scores = rmse_cv(xgb_model, X, y)\n",
279
+ "print(f\"XGBoost RMSE : {xgb_scores.mean():.4f} (+/- {xgb_scores.std():.4f})\")"
280
+ ]
281
+ },
282
+ {
283
+ "cell_type": "code",
284
+ "execution_count": null,
285
+ "metadata": {},
286
+ "outputs": [],
287
+ "source": [
288
+ "# Modèle LightGBM\n",
289
+ "lgb_model = lgb.LGBMRegressor(\n",
290
+ " n_estimators=1000,\n",
291
+ " learning_rate=0.05,\n",
292
+ " max_depth=6,\n",
293
+ " subsample=0.8,\n",
294
+ " colsample_bytree=0.8,\n",
295
+ " random_state=42\n",
296
+ ")\n",
297
+ "\n",
298
+ "print(\"⏳ Évaluation LightGBM...\")\n",
299
+ "lgb_scores = rmse_cv(lgb_model, X, y)\n",
300
+ "print(f\"LightGBM RMSE : {lgb_scores.mean():.4f} (+/- {lgb_scores.std():.4f})\")"
301
+ ]
302
+ },
303
+ {
304
+ "cell_type": "code",
305
+ "execution_count": null,
306
+ "metadata": {},
307
+ "outputs": [],
308
+ "source": [
309
+ "# Modèles linéaires régularisés\n",
310
+ "lasso = Lasso(alpha=0.0005, random_state=42, max_iter=10000)\n",
311
+ "ridge = Ridge(alpha=0.5, random_state=42)\n",
312
+ "\n",
313
+ "print(\"⏳ Évaluation Lasso...\")\n",
314
+ "lasso_scores = rmse_cv(lasso, X, y)\n",
315
+ "print(f\"Lasso RMSE : {lasso_scores.mean():.4f} (+/- {lasso_scores.std():.4f})\")\n",
316
+ "\n",
317
+ "print(\"\\n⏳ Évaluation Ridge...\")\n",
318
+ "ridge_scores = rmse_cv(ridge, X, y)\n",
319
+ "print(f\"Ridge RMSE : {ridge_scores.mean():.4f} (+/- {ridge_scores.std():.4f})\")"
320
+ ]
321
+ },
322
+ {
323
+ "cell_type": "markdown",
324
+ "metadata": {},
325
+ "source": [
326
+ "<a id='section-6'></a>\n",
327
+ "## 6��⃣ Stacking et soumission"
328
+ ]
329
+ },
330
+ {
331
+ "cell_type": "code",
332
+ "execution_count": null,
333
+ "metadata": {},
334
+ "outputs": [],
335
+ "source": [
336
+ "# Stacking de modèles\n",
337
+ "estimators = [\n",
338
+ " ('xgb', xgb_model),\n",
339
+ " ('lgb', lgb_model),\n",
340
+ " ('ridge', ridge)\n",
341
+ "]\n",
342
+ "\n",
343
+ "stacking_model = StackingRegressor(\n",
344
+ " estimators=estimators,\n",
345
+ " final_estimator=Ridge(alpha=0.1),\n",
346
+ " cv=5,\n",
347
+ " n_jobs=-1\n",
348
+ ")\n",
349
+ "\n",
350
+ "print(\"⏳ Évaluation Stacking...\")\n",
351
+ "stacking_scores = rmse_cv(stacking_model, X, y)\n",
352
+ "print(f\"Stacking RMSE : {stacking_scores.mean():.4f} (+/- {stacking_scores.std():.4f})\")"
353
+ ]
354
+ },
355
+ {
356
+ "cell_type": "code",
357
+ "execution_count": null,
358
+ "metadata": {},
359
+ "outputs": [],
360
+ "source": [
361
+ "# Entraînement final et importance des features\n",
362
+ "xgb_model.fit(X, y)\n",
363
+ "\n",
364
+ "feature_importance = pd.DataFrame({\n",
365
+ " 'feature': features,\n",
366
+ " 'importance': xgb_model.feature_importances_\n",
367
+ "}).sort_values('importance', ascending=False)\n",
368
+ "\n",
369
+ "plt.figure(figsize=(10, 6))\n",
370
+ "sns.barplot(data=feature_importance, x='importance', y='feature', palette='viridis')\n",
371
+ "plt.title('Importance des features (XGBoost)')\n",
372
+ "plt.tight_layout()\n",
373
+ "plt.show()"
374
+ ]
375
+ },
376
+ {
377
+ "cell_type": "code",
378
+ "execution_count": null,
379
+ "metadata": {},
380
+ "outputs": [],
381
+ "source": [
382
+ "# Résumé des performances\n",
383
+ "print(\"📊 Résumé des performances (RMSE) :\")\n",
384
+ "print(\"=\" * 40)\n",
385
+ "print(f\"Lasso : {lasso_scores.mean():.4f}\")\n",
386
+ "print(f\"Ridge : {ridge_scores.mean():.4f}\")\n",
387
+ "print(f\"XGBoost : {xgb_scores.mean():.4f}\")\n",
388
+ "print(f\"LightGBM : {lgb_scores.mean():.4f}\")\n",
389
+ "print(f\"Stacking : {stacking_scores.mean():.4f} ⭐\")"
390
+ ]
391
+ },
392
+ {
393
+ "cell_type": "markdown",
394
+ "metadata": {},
395
+ "source": [
396
+ "## 🎓 Conclusion\n",
397
+ "\n",
398
+ "Dans ce TP avancé, nous avons :\n",
399
+ "\n",
400
+ "1. ✅ **Analysé** la distribution des prix et identifié les transformations nécessaires\n",
401
+ "2. ✅ **Créé** des features pertinentes (ratios, catégorisations)\n",
402
+ "3. ✅ **Comparé** plusieurs algorithmes de régression\n",
403
+ "4. ✅ **Utilisé** XGBoost et LightGBM pour de meilleures performances\n",
404
+ "5. ✅ **Combiné** les modèles avec le stacking\n",
405
+ "\n",
406
+ "**Résultat** : RMSE de ~0.45 avec le stacking (sur échelle log).\n",
407
+ "\n",
408
+ "**Améliorations possibles** :\n",
409
+ "- Feature engineering plus poussé (interactions, polynomial features)\n",
410
+ "- Optimisation des hyperparamètres avec Optuna\n",
411
+ "- Utilisation de réseaux de neurones pour la couche finale"
412
+ ]
413
+ }
414
+ ],
415
+ "metadata": {
416
+ "kernelspec": {
417
+ "display_name": "Python 3",
418
+ "language": "python",
419
+ "name": "python3"
420
+ },
421
+ "language_info": {
422
+ "codemirror_mode": {
423
+ "name": "ipython",
424
+ "version": 3
425
+ },
426
+ "file_extension": ".py",
427
+ "mimetype": "text/x-python",
428
+ "name": "python",
429
+ "nbconvert_exporter": "python",
430
+ "pygments_lexer": "ipython3",
431
+ "version": "3.8.0"
432
+ }
433
+ },
434
+ "nbformat": 4,
435
+ "nbformat_minor": 4
436
+ }
notebooks/TP3_Iris_Classification.ipynb ADDED
@@ -0,0 +1,182 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "# 🌸 TP-3 : Classification Iris — Introduction au ML\n",
8
+ "\n",
9
+ "**Objectif** : Classifier les iris en 3 espèces à partir de 4 features.\n",
10
+ "\n",
11
+ "**Dataset** : [Iris Flower Dataset](https://www.kaggle.com/datasets/uciml/iris)\n",
12
+ "\n",
13
+ "**Compétences** :\n",
14
+ "- Classification multi-classe\n",
15
+ "- Visualisation avec PCA\n",
16
+ "- Frontières de décision\n",
17
+ "- Comparaison d'algorithmes"
18
+ ]
19
+ },
20
+ {
21
+ "cell_type": "code",
22
+ "execution_count": null,
23
+ "metadata": {},
24
+ "outputs": [],
25
+ "source": [
26
+ "import numpy as np\n",
27
+ "import pandas as pd\n",
28
+ "import matplotlib.pyplot as plt\n",
29
+ "import seaborn as sns\n",
30
+ "from sklearn.datasets import load_iris\n",
31
+ "from sklearn.model_selection import train_test_split, cross_val_score\n",
32
+ "from sklearn.preprocessing import StandardScaler\n",
33
+ "from sklearn.decomposition import PCA\n",
34
+ "from sklearn.neighbors import KNeighborsClassifier\n",
35
+ "from sklearn.svm import SVC\n",
36
+ "from sklearn.tree import DecisionTreeClassifier\n",
37
+ "from sklearn.ensemble import RandomForestClassifier\n",
38
+ "from sklearn.metrics import accuracy_score, classification_report, confusion_matrix\n",
39
+ "\n",
40
+ "sns.set_style('whitegrid')\n",
41
+ "print(\"✅ Bibliothèques importées !\")"
42
+ ]
43
+ },
44
+ {
45
+ "cell_type": "code",
46
+ "execution_count": null,
47
+ "metadata": {},
48
+ "outputs": [],
49
+ "source": [
50
+ "# Chargement des données\n",
51
+ "iris = load_iris()\n",
52
+ "X = iris.data\n",
53
+ "y = iris.target\n",
54
+ "feature_names = iris.feature_names\n",
55
+ "target_names = iris.target_names\n",
56
+ "\n",
57
+ "# Création d'un DataFrame\n",
58
+ "df = pd.DataFrame(X, columns=feature_names)\n",
59
+ "df['species'] = [target_names[i] for i in y]\n",
60
+ "\n",
61
+ "print(f\"📊 Dimensions : {df.shape}\")\n",
62
+ "print(f\"\\n🌸 Espèces : {target_names}\")\n",
63
+ "df.head()"
64
+ ]
65
+ },
66
+ {
67
+ "cell_type": "code",
68
+ "execution_count": null,
69
+ "metadata": {},
70
+ "outputs": [],
71
+ "source": [
72
+ "# Pairplot pour visualiser les relations\n",
73
+ "sns.pairplot(df, hue='species', palette='viridis', height=2.5)\n",
74
+ "plt.suptitle('Pairplot du dataset Iris', y=1.02, fontsize=14)\n",
75
+ "plt.show()"
76
+ ]
77
+ },
78
+ {
79
+ "cell_type": "code",
80
+ "execution_count": null,
81
+ "metadata": {},
82
+ "outputs": [],
83
+ "source": [
84
+ "# Split et normalisation\n",
85
+ "X_train, X_test, y_train, y_test = train_test_split(\n",
86
+ " X, y, test_size=0.2, random_state=42, stratify=y\n",
87
+ ")\n",
88
+ "\n",
89
+ "scaler = StandardScaler()\n",
90
+ "X_train_scaled = scaler.fit_transform(X_train)\n",
91
+ "X_test_scaled = scaler.transform(X_test)\n",
92
+ "\n",
93
+ "print(f\"Train : {X_train.shape[0]} échantillons\")\n",
94
+ "print(f\"Test : {X_test.shape[0]} échantillons\")"
95
+ ]
96
+ },
97
+ {
98
+ "cell_type": "code",
99
+ "execution_count": null,
100
+ "metadata": {},
101
+ "outputs": [],
102
+ "source": [
103
+ "# Comparaison des modèles\n",
104
+ "models = {\n",
105
+ " 'KNN': KNeighborsClassifier(n_neighbors=5),\n",
106
+ " 'SVM': SVC(kernel='rbf', random_state=42),\n",
107
+ " 'Decision Tree': DecisionTreeClassifier(random_state=42),\n",
108
+ " 'Random Forest': RandomForestClassifier(n_estimators=100, random_state=42)\n",
109
+ "}\n",
110
+ "\n",
111
+ "results = {}\n",
112
+ "for name, model in models.items():\n",
113
+ " model.fit(X_train_scaled, y_train)\n",
114
+ " y_pred = model.predict(X_test_scaled)\n",
115
+ " accuracy = accuracy_score(y_test, y_pred)\n",
116
+ " results[name] = accuracy\n",
117
+ " print(f\"{name:15} : {accuracy:.4f}\")"
118
+ ]
119
+ },
120
+ {
121
+ "cell_type": "code",
122
+ "execution_count": null,
123
+ "metadata": {},
124
+ "outputs": [],
125
+ "source": [
126
+ "# Visualisation avec PCA (2D)\n",
127
+ "pca = PCA(n_components=2)\n",
128
+ "X_pca = pca.fit_transform(X_scaled := StandardScaler().fit_transform(X))\n",
129
+ "\n",
130
+ "plt.figure(figsize=(10, 6))\n",
131
+ "colors = ['red', 'green', 'blue']\n",
132
+ "for i, target_name in enumerate(target_names):\n",
133
+ " plt.scatter(X_pca[y == i, 0], X_pca[y == i, 1], \n",
134
+ " c=colors[i], label=target_name, alpha=0.7, s=50)\n",
135
+ "plt.xlabel(f'PC1 ({pca.explained_variance_ratio_[0]:.2%})')\n",
136
+ "plt.ylabel(f'PC2 ({pca.explained_variance_ratio_[1]:.2%})')\n",
137
+ "plt.title('Dataset Iris - Projection PCA')\n",
138
+ "plt.legend()\n",
139
+ "plt.show()\n",
140
+ "\n",
141
+ "print(f\"Variance expliquée : {pca.explained_variance_ratio_.sum():.2%}\")"
142
+ ]
143
+ },
144
+ {
145
+ "cell_type": "code",
146
+ "execution_count": null,
147
+ "metadata": {},
148
+ "outputs": [],
149
+ "source": [
150
+ "# Matrice de confusion pour le meilleur modèle\n",
151
+ "best_model = SVC(kernel='rbf', random_state=42)\n",
152
+ "best_model.fit(X_train_scaled, y_train)\n",
153
+ "y_pred = best_model.predict(X_test_scaled)\n",
154
+ "\n",
155
+ "cm = confusion_matrix(y_test, y_pred)\n",
156
+ "\n",
157
+ "plt.figure(figsize=(8, 6))\n",
158
+ "sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',\n",
159
+ " xticklabels=target_names, yticklabels=target_names)\n",
160
+ "plt.title('Matrice de confusion - SVM')\n",
161
+ "plt.ylabel('Vrai label')\n",
162
+ "plt.xlabel('Prédiction')\n",
163
+ "plt.show()\n",
164
+ "\n",
165
+ "print(classification_report(y_test, y_pred, target_names=target_names))"
166
+ ]
167
+ }
168
+ ],
169
+ "metadata": {
170
+ "kernelspec": {
171
+ "display_name": "Python 3",
172
+ "language": "python",
173
+ "name": "python3"
174
+ },
175
+ "language_info": {
176
+ "name": "python",
177
+ "version": "3.8.0"
178
+ }
179
+ },
180
+ "nbformat": 4,
181
+ "nbformat_minor": 4
182
+ }
notebooks/TP4_LSTM_TimeSeries.ipynb ADDED
@@ -0,0 +1,371 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "# ⏱️ TP-4 : Prédiction de Séries Temporelles avec LSTM\n",
8
+ "\n",
9
+ "**Objectif** : Prédire la consommation électrique avec des réseaux LSTM.\n",
10
+ "\n",
11
+ "**Compétences** :\n",
12
+ "- Préparation de données temporelles\n",
13
+ "- Fenêtres glissantes (windowing)\n",
14
+ "- Architecture LSTM avec Keras\n",
15
+ "- Early stopping et régularisation"
16
+ ]
17
+ },
18
+ {
19
+ "cell_type": "code",
20
+ "execution_count": null,
21
+ "metadata": {},
22
+ "outputs": [],
23
+ "source": [
24
+ "import numpy as np\n",
25
+ "import pandas as pd\n",
26
+ "import matplotlib.pyplot as plt\n",
27
+ "from sklearn.preprocessing import MinMaxScaler\n",
28
+ "from sklearn.metrics import mean_squared_error, mean_absolute_error\n",
29
+ "\n",
30
+ "import tensorflow as tf\n",
31
+ "from tensorflow.keras.models import Sequential\n",
32
+ "from tensorflow.keras.layers import LSTM, Dense, Dropout\n",
33
+ "from tensorflow.keras.callbacks import EarlyStopping, ReduceLROnPlateau\n",
34
+ "\n",
35
+ "# Reproductibilité\n",
36
+ "np.random.seed(42)\n",
37
+ "tf.random.set_seed(42)\n",
38
+ "\n",
39
+ "print(f\"✅ TensorFlow version : {tf.__version__}\")"
40
+ ]
41
+ },
42
+ {
43
+ "cell_type": "code",
44
+ "execution_count": null,
45
+ "metadata": {},
46
+ "outputs": [],
47
+ "source": [
48
+ "# Génération de données synthétiques (consommation électrique)\n",
49
+ "# En pratique, remplacez par vos données réelles\n",
50
+ "\n",
51
+ "def generate_energy_data(n_days=365*2):\n",
52
+ " \"\"\"Génère des données de consommation électrique simulées\"\"\"\n",
53
+ " hours = np.arange(n_days * 24)\n",
54
+ " \n",
55
+ " # Tendance\n",
56
+ " trend = 0.001 * hours\n",
57
+ " \n",
58
+ " # Saisonnalité journalière\n",
59
+ " daily = 10 * np.sin(2 * np.pi * hours / 24)\n",
60
+ " \n",
61
+ " # Saisonnalité hebdomadaire\n",
62
+ " weekly = 5 * np.sin(2 * np.pi * hours / (24 * 7))\n",
63
+ " \n",
64
+ " # Saisonnalité annuelle\n",
65
+ " yearly = 15 * np.sin(2 * np.pi * hours / (24 * 365))\n",
66
+ " \n",
67
+ " # Bruit\n",
68
+ " noise = np.random.normal(0, 3, len(hours))\n",
69
+ " \n",
70
+ " # Consommation totale\n",
71
+ " consumption = 50 + trend + daily + weekly + yearly + noise\n",
72
+ " consumption = np.maximum(consumption, 0) # Pas de valeurs négatives\n",
73
+ " \n",
74
+ " return consumption\n",
75
+ "\n",
76
+ "# Génération des données\n",
77
+ "data = generate_energy_data(n_days=730) # 2 ans de données\n",
78
+ "\n",
79
+ "# Création du DataFrame\n",
80
+ "dates = pd.date_range(start='2022-01-01', periods=len(data), freq='H')\n",
81
+ "df = pd.DataFrame({'consumption': data}, index=dates)\n",
82
+ "\n",
83
+ "print(f\"📊 Période : {df.index[0]} à {df.index[-1]}\")\n",
84
+ "print(f\"📊 Total : {len(df)} heures de données\")\n",
85
+ "df.head()"
86
+ ]
87
+ },
88
+ {
89
+ "cell_type": "code",
90
+ "execution_count": null,
91
+ "metadata": {},
92
+ "outputs": [],
93
+ "source": [
94
+ "# Visualisation des données\n",
95
+ "fig, axes = plt.subplots(3, 1, figsize=(15, 10))\n",
96
+ "\n",
97
+ "# Vue complète\n",
98
+ "axes[0].plot(df.index, df['consumption'], alpha=0.7)\n",
99
+ "axes[0].set_title('Consommation électrique - Vue complète (2 ans)')\n",
100
+ "axes[0].set_ylabel('kWh')\n",
101
+ "\n",
102
+ "# Vue d'une semaine\n",
103
+ "one_week = df.iloc[:24*7]\n",
104
+ "axes[1].plot(one_week.index, one_week['consumption'], marker='o')\n",
105
+ "axes[1].set_title('Consommation - Vue hebdomadaire')\n",
106
+ "axes[1].set_ylabel('kWh')\n",
107
+ "\n",
108
+ "# Vue d'une journée\n",
109
+ "one_day = df.iloc[:24]\n",
110
+ "axes[2].plot(one_day.index.hour, one_day['consumption'], marker='o')\n",
111
+ "axes[2].set_title('Consommation - Vue journalière')\n",
112
+ "axes[2].set_xlabel('Heure')\n",
113
+ "axes[2].set_ylabel('kWh')\n",
114
+ "\n",
115
+ "plt.tight_layout()\n",
116
+ "plt.show()"
117
+ ]
118
+ },
119
+ {
120
+ "cell_type": "code",
121
+ "execution_count": null,
122
+ "metadata": {},
123
+ "outputs": [],
124
+ "source": [
125
+ "# Feature Engineering temporel\n",
126
+ "df['hour'] = df.index.hour\n",
127
+ "df['day_of_week'] = df.index.dayofweek\n",
128
+ "df['month'] = df.index.month\n",
129
+ "df['is_weekend'] = (df['day_of_week'] >= 5).astype(int)\n",
130
+ "\n",
131
+ "# Lags (valeurs précédentes)\n",
132
+ "for lag in [1, 2, 3, 24, 48]:\n",
133
+ " df[f'lag_{lag}'] = df['consumption'].shift(lag)\n",
134
+ "\n",
135
+ "# Rolling statistics\n",
136
+ "df['rolling_mean_24'] = df['consumption'].rolling(window=24).mean()\n",
137
+ "df['rolling_std_24'] = df['consumption'].rolling(window=24).std()\n",
138
+ "\n",
139
+ "# Suppression des NaN\n",
140
+ "df = df.dropna()\n",
141
+ "\n",
142
+ "print(f\"✅ Features créées : {df.shape[1]} colonnes\")\n",
143
+ "df.head()"
144
+ ]
145
+ },
146
+ {
147
+ "cell_type": "code",
148
+ "execution_count": null,
149
+ "metadata": {},
150
+ "outputs": [],
151
+ "source": [
152
+ "# Préparation des séquences pour LSTM\n",
153
+ "def create_sequences(data, target_col, sequence_length=24):\n",
154
+ " \"\"\"\n",
155
+ " Crée des séquences pour LSTM\n",
156
+ " data : DataFrame avec features\n",
157
+ " target_col : nom de la colonne cible\n",
158
+ " sequence_length : longueur de la séquence (ex: 24 heures)\n",
159
+ " \"\"\"\n",
160
+ " X, y = [], []\n",
161
+ " values = data.values\n",
162
+ " target_idx = data.columns.get_loc(target_col)\n",
163
+ " \n",
164
+ " for i in range(sequence_length, len(values)):\n",
165
+ " X.append(values[i-sequence_length:i])\n",
166
+ " y.append(values[i, target_idx])\n",
167
+ " \n",
168
+ " return np.array(X), np.array(y)\n",
169
+ "\n",
170
+ "# Séparation train/test\n",
171
+ "train_size = int(len(df) * 0.8)\n",
172
+ "train_df = df.iloc[:train_size]\n",
173
+ "test_df = df.iloc[train_size:]\n",
174
+ "\n",
175
+ "# Normalisation\n",
176
+ "scaler = MinMaxScaler()\n",
177
+ "train_scaled = scaler.fit_transform(train_df)\n",
178
+ "test_scaled = scaler.transform(test_df)\n",
179
+ "\n",
180
+ "# Conversion en DataFrame pour garder les noms de colonnes\n",
181
+ "train_scaled = pd.DataFrame(train_scaled, columns=df.columns, index=train_df.index)\n",
182
+ "test_scaled = pd.DataFrame(test_scaled, columns=df.columns, index=test_df.index)\n",
183
+ "\n",
184
+ "# Création des séquences\n",
185
+ "SEQUENCE_LENGTH = 24 # 24 heures d'historique\n",
186
+ "\n",
187
+ "X_train, y_train = create_sequences(train_scaled, 'consumption', SEQUENCE_LENGTH)\n",
188
+ "X_test, y_test = create_sequences(test_scaled, 'consumption', SEQUENCE_LENGTH)\n",
189
+ "\n",
190
+ "print(f\"📊 X_train shape : {X_train.shape}\")\n",
191
+ "print(f\"📊 y_train shape : {y_train.shape}\")\n",
192
+ "print(f\"📊 X_test shape : {X_test.shape}\")\n",
193
+ "print(f\"📊 y_test shape : {y_test.shape}\")"
194
+ ]
195
+ },
196
+ {
197
+ "cell_type": "code",
198
+ "execution_count": null,
199
+ "metadata": {},
200
+ "outputs": [],
201
+ "source": [
202
+ "# Construction du modèle LSTM\n",
203
+ "model = Sequential([\n",
204
+ " LSTM(64, return_sequences=True, input_shape=(SEQUENCE_LENGTH, X_train.shape[2])),\n",
205
+ " Dropout(0.2),\n",
206
+ " LSTM(32, return_sequences=False),\n",
207
+ " Dropout(0.2),\n",
208
+ " Dense(16, activation='relu'),\n",
209
+ " Dense(1)\n",
210
+ "])\n",
211
+ "\n",
212
+ "model.compile(\n",
213
+ " optimizer=tf.keras.optimizers.Adam(learning_rate=0.001),\n",
214
+ " loss='mse',\n",
215
+ " metrics=['mae']\n",
216
+ ")\n",
217
+ "\n",
218
+ "model.summary()"
219
+ ]
220
+ },
221
+ {
222
+ "cell_type": "code",
223
+ "execution_count": null,
224
+ "metadata": {},
225
+ "outputs": [],
226
+ "source": [
227
+ "# Callbacks\n",
228
+ "callbacks = [\n",
229
+ " EarlyStopping(\n",
230
+ " monitor='val_loss',\n",
231
+ " patience=10,\n",
232
+ " restore_best_weights=True\n",
233
+ " ),\n",
234
+ " ReduceLROnPlateau(\n",
235
+ " monitor='val_loss',\n",
236
+ " factor=0.5,\n",
237
+ " patience=5,\n",
238
+ " min_lr=1e-6\n",
239
+ " )\n",
240
+ "]\n",
241
+ "\n",
242
+ "# Entraînement\n",
243
+ "history = model.fit(\n",
244
+ " X_train, y_train,\n",
245
+ " epochs=100,\n",
246
+ " batch_size=32,\n",
247
+ " validation_split=0.2,\n",
248
+ " callbacks=callbacks,\n",
249
+ " verbose=1\n",
250
+ ")"
251
+ ]
252
+ },
253
+ {
254
+ "cell_type": "code",
255
+ "execution_count": null,
256
+ "metadata": {},
257
+ "outputs": [],
258
+ "source": [
259
+ "# Visualisation de l'entraînement\n",
260
+ "fig, axes = plt.subplots(1, 2, figsize=(14, 5))\n",
261
+ "\n",
262
+ "# Loss\n",
263
+ "axes[0].plot(history.history['loss'], label='Train')\n",
264
+ "axes[0].plot(history.history['val_loss'], label='Validation')\n",
265
+ "axes[0].set_title('Loss (MSE)')\n",
266
+ "axes[0].set_xlabel('Epoch')\n",
267
+ "axes[0].set_ylabel('Loss')\n",
268
+ "axes[0].legend()\n",
269
+ "\n",
270
+ "# MAE\n",
271
+ "axes[1].plot(history.history['mae'], label='Train')\n",
272
+ "axes[1].plot(history.history['val_mae'], label='Validation')\n",
273
+ "axes[1].set_title('MAE')\n",
274
+ "axes[1].set_xlabel('Epoch')\n",
275
+ "axes[1].set_ylabel('MAE')\n",
276
+ "axes[1].legend()\n",
277
+ "\n",
278
+ "plt.tight_layout()\n",
279
+ "plt.show()"
280
+ ]
281
+ },
282
+ {
283
+ "cell_type": "code",
284
+ "execution_count": null,
285
+ "metadata": {},
286
+ "outputs": [],
287
+ "source": [
288
+ "# Prédictions\n",
289
+ "y_pred = model.predict(X_test)\n",
290
+ "\n",
291
+ "# Métriques (sur données normalisées)\n",
292
+ "mse = mean_squared_error(y_test, y_pred)\n",
293
+ "mae = mean_absolute_error(y_test, y_pred)\n",
294
+ "rmse = np.sqrt(mse)\n",
295
+ "\n",
296
+ "print(f\"📊 MSE : {mse:.6f}\")\n",
297
+ "print(f\"📊 MAE : {mae:.6f}\")\n",
298
+ "print(f\"📊 RMSE : {rmse:.6f}\")"
299
+ ]
300
+ },
301
+ {
302
+ "cell_type": "code",
303
+ "execution_count": null,
304
+ "metadata": {},
305
+ "outputs": [],
306
+ "source": [
307
+ "# Visualisation des prédictions\n",
308
+ "plt.figure(figsize=(15, 6))\n",
309
+ "\n",
310
+ "# Plot des 500 premières prédictions\n",
311
+ "n_plot = 500\n",
312
+ "plt.plot(y_test[:n_plot], label='Réel', alpha=0.8)\n",
313
+ "plt.plot(y_pred[:n_plot], label='Prédit', alpha=0.8)\n",
314
+ "plt.title(f'Prédictions LSTM - {n_plot} premiers points de test')\n",
315
+ "plt.xlabel('Temps')\n",
316
+ "plt.ylabel('Consommation (normalisée)')\n",
317
+ "plt.legend()\n",
318
+ "plt.show()"
319
+ ]
320
+ },
321
+ {
322
+ "cell_type": "code",
323
+ "execution_count": null,
324
+ "metadata": {},
325
+ "outputs": [],
326
+ "source": [
327
+ "# Scatter plot : Réel vs Prédit\n",
328
+ "plt.figure(figsize=(8, 8))\n",
329
+ "plt.scatter(y_test, y_pred, alpha=0.5)\n",
330
+ "plt.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], 'r--', lw=2)\n",
331
+ "plt.xlabel('Valeurs réelles')\n",
332
+ "plt.ylabel('Valeurs prédites')\n",
333
+ "plt.title('Réel vs Prédit')\n",
334
+ "plt.show()"
335
+ ]
336
+ },
337
+ {
338
+ "cell_type": "markdown",
339
+ "metadata": {},
340
+ "source": [
341
+ "## 🎓 Conclusion\n",
342
+ "\n",
343
+ "Dans ce TP, nous avons :\n",
344
+ "\n",
345
+ "1. ✅ **Généré** des données de consommation électrique avec patterns temporels\n",
346
+ "2. ✅ **Créé** des features temporelles (heure, jour, mois, lags, rolling stats)\n",
347
+ "3. ✅ **Préparé** les séquences pour LSTM avec windowing\n",
348
+ "4. ✅ **Construit** un modèle LSTM avec Dropout et Early Stopping\n",
349
+ "5. ✅ **Évalué** les performances sur l'ensemble de test\n",
350
+ "\n",
351
+ "**Améliorations possibles** :\n",
352
+ "- Utiliser des données météo comme features externes\n",
353
+ "- Tester des architectures plus complexes (Bidirectional LSTM, GRU)\n",
354
+ "- Faire du multi-step forecasting (prédire plusieurs heures en avance)"
355
+ ]
356
+ }
357
+ ],
358
+ "metadata": {
359
+ "kernelspec": {
360
+ "display_name": "Python 3",
361
+ "language": "python",
362
+ "name": "python3"
363
+ },
364
+ "language_info": {
365
+ "name": "python",
366
+ "version": "3.8.0"
367
+ }
368
+ },
369
+ "nbformat": 4,
370
+ "nbformat_minor": 4
371
+ }
tp.html ADDED
@@ -0,0 +1,1389 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="fr">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Travaux Pratiques — ML Academy</title>
7
+ <link rel="stylesheet" href="css/shared.css">
8
+ <style>
9
+ /* ═══════════════════════════════════════════════════════════════════════════
10
+ PAGE HERO
11
+ ═══════════════════════════════════════════════════════════════════════════ */
12
+ .tp-hero {
13
+ background: linear-gradient(135deg, var(--bg-secondary) 0%, var(--bg-tertiary) 100%);
14
+ border-bottom: 1px solid var(--border-color);
15
+ padding: var(--space-3xl) var(--space-xl);
16
+ text-align: center;
17
+ }
18
+
19
+ .tp-hero-label {
20
+ font-family: 'JetBrains Mono', monospace;
21
+ font-size: 0.75rem;
22
+ color: var(--primary-light);
23
+ text-transform: uppercase;
24
+ letter-spacing: 2px;
25
+ margin-bottom: var(--space-md);
26
+ }
27
+
28
+ .tp-hero-title {
29
+ font-size: clamp(2rem, 5vw, 3rem);
30
+ font-weight: 700;
31
+ color: var(--text-primary);
32
+ margin-bottom: var(--space-md);
33
+ }
34
+
35
+ .tp-hero-subtitle {
36
+ font-size: 1.1rem;
37
+ color: var(--text-secondary);
38
+ max-width: 600px;
39
+ margin: 0 auto var(--space-xl);
40
+ }
41
+
42
+ .tp-hero-badges {
43
+ display: flex;
44
+ justify-content: center;
45
+ gap: var(--space-md);
46
+ flex-wrap: wrap;
47
+ }
48
+
49
+ /* ═══════════════════════════════════════════════════════════════════════════
50
+ TP CONTAINER
51
+ ═══════════════════════════════════════════════════════════════════════════ */
52
+ .tp-container {
53
+ max-width: 1000px;
54
+ margin: 0 auto;
55
+ padding: var(--space-2xl) var(--space-xl);
56
+ }
57
+
58
+ /* ═══════════════════════════════════════════════════════════════════════════
59
+ TP CARD
60
+ ═══════════════════════════════════════════════════════════════════════════ */
61
+ .tp-card {
62
+ background: var(--bg-card);
63
+ border: 1px solid var(--border-color);
64
+ border-radius: var(--radius-lg);
65
+ overflow: hidden;
66
+ margin-bottom: var(--space-2xl);
67
+ transition: all var(--transition-base);
68
+ }
69
+
70
+ .tp-card:hover {
71
+ border-color: var(--primary);
72
+ box-shadow: var(--shadow-lg), var(--shadow-glow);
73
+ }
74
+
75
+ .tp-header {
76
+ display: flex;
77
+ align-items: flex-start;
78
+ gap: var(--space-lg);
79
+ padding: var(--space-xl);
80
+ background: linear-gradient(135deg, var(--bg-card), var(--bg-tertiary));
81
+ border-bottom: 1px solid var(--border-color);
82
+ }
83
+
84
+ .tp-badge {
85
+ padding: var(--space-sm) var(--space-md);
86
+ border-radius: var(--radius-md);
87
+ font-family: 'JetBrains Mono', monospace;
88
+ font-size: 0.7rem;
89
+ font-weight: 600;
90
+ color: white;
91
+ text-transform: uppercase;
92
+ letter-spacing: 1px;
93
+ flex-shrink: 0;
94
+ }
95
+
96
+ .tp-badge.titanic { background: linear-gradient(135deg, #1e40af, #3b82f6); }
97
+ .tp-badge.housing { background: linear-gradient(135deg, #047857, #10b981); }
98
+ .tp-badge.iris { background: linear-gradient(135deg, #b45309, #f59e0b); }
99
+ .tp-badge.energy { background: linear-gradient(135deg, #7c3aed, #a78bfa); }
100
+ .tp-badge.mnist { background: linear-gradient(135deg, #be123c, #f43f5e); }
101
+ .tp-badge.sentiment { background: linear-gradient(135deg, #0e7490, #06b6d4); }
102
+
103
+ .tp-header-content {
104
+ flex: 1;
105
+ }
106
+
107
+ .tp-title {
108
+ font-size: 1.4rem;
109
+ font-weight: 700;
110
+ color: var(--text-primary);
111
+ margin-bottom: var(--space-sm);
112
+ }
113
+
114
+ .tp-meta {
115
+ display: flex;
116
+ gap: var(--space-sm);
117
+ flex-wrap: wrap;
118
+ margin-bottom: var(--space-sm);
119
+ }
120
+
121
+ .tp-description {
122
+ font-size: 0.95rem;
123
+ color: var(--text-secondary);
124
+ line-height: 1.6;
125
+ }
126
+
127
+ .tp-colab-btn {
128
+ display: inline-flex;
129
+ align-items: center;
130
+ gap: var(--space-sm);
131
+ padding: var(--space-sm) var(--space-md);
132
+ background: #f9ab00;
133
+ color: #000;
134
+ font-family: 'JetBrains Mono', monospace;
135
+ font-size: 0.8rem;
136
+ font-weight: 600;
137
+ text-decoration: none;
138
+ border-radius: var(--radius-md);
139
+ transition: all var(--transition-base);
140
+ flex-shrink: 0;
141
+ }
142
+
143
+ .tp-colab-btn:hover {
144
+ background: #fbbf24;
145
+ transform: translateY(-2px);
146
+ }
147
+
148
+ /* ═══════════════════════════════════════════════════════════════════════════
149
+ TP BODY
150
+ ═══════════════════════════════════════════════════════════════════════════ */
151
+ .tp-body {
152
+ padding: var(--space-xl);
153
+ }
154
+
155
+ .tp-goals {
156
+ display: grid;
157
+ grid-template-columns: repeat(2, 1fr);
158
+ gap: 0;
159
+ border: 1px solid var(--border-color);
160
+ border-radius: var(--radius-md);
161
+ overflow: hidden;
162
+ margin-bottom: var(--space-xl);
163
+ }
164
+
165
+ .tp-goal-box {
166
+ padding: var(--space-lg);
167
+ background: var(--bg-tertiary);
168
+ }
169
+
170
+ .tp-goal-box:first-child {
171
+ border-right: 1px solid var(--border-color);
172
+ }
173
+
174
+ .tp-goal-label {
175
+ font-family: 'JetBrains Mono', monospace;
176
+ font-size: 0.65rem;
177
+ color: var(--text-muted);
178
+ text-transform: uppercase;
179
+ letter-spacing: 1px;
180
+ margin-bottom: var(--space-sm);
181
+ }
182
+
183
+ .tp-goal-text {
184
+ font-size: 0.9rem;
185
+ color: var(--text-secondary);
186
+ line-height: 1.6;
187
+ }
188
+
189
+ .tp-goal-text strong {
190
+ color: var(--success);
191
+ }
192
+
193
+ /* ═══════════════════════════════════════════════════════════════════════════
194
+ CONCEPTS GRID
195
+ ═══════════════════════════════════════════════════════════════════════════ */
196
+ .concepts-title {
197
+ font-size: 1rem;
198
+ font-weight: 600;
199
+ color: var(--text-primary);
200
+ margin-bottom: var(--space-md);
201
+ }
202
+
203
+ .concepts-grid {
204
+ display: grid;
205
+ grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
206
+ gap: var(--space-sm);
207
+ margin-bottom: var(--space-xl);
208
+ }
209
+
210
+ .concept-item {
211
+ background: var(--bg-tertiary);
212
+ border: 1px solid var(--border-color);
213
+ border-radius: var(--radius-md);
214
+ padding: var(--space-md);
215
+ transition: all var(--transition-base);
216
+ }
217
+
218
+ .concept-item:hover {
219
+ border-color: var(--primary);
220
+ transform: translateY(-2px);
221
+ }
222
+
223
+ .concept-name {
224
+ font-size: 0.85rem;
225
+ font-weight: 600;
226
+ color: var(--text-primary);
227
+ margin-bottom: var(--space-xs);
228
+ }
229
+
230
+ .concept-desc {
231
+ font-size: 0.75rem;
232
+ color: var(--text-muted);
233
+ }
234
+
235
+ /* ═══════════════════════════════════════════════════════════════════════════
236
+ STEPS
237
+ ═══════════════════════════════════════════════════════════════════════════ */
238
+ .steps-title {
239
+ font-size: 1rem;
240
+ font-weight: 600;
241
+ color: var(--text-primary);
242
+ margin-bottom: var(--space-md);
243
+ }
244
+
245
+ .steps-list {
246
+ display: flex;
247
+ flex-direction: column;
248
+ gap: 0;
249
+ }
250
+
251
+ .step-item {
252
+ display: flex;
253
+ gap: 0;
254
+ position: relative;
255
+ }
256
+
257
+ .step-item:not(:last-child)::after {
258
+ content: '';
259
+ position: absolute;
260
+ left: 20px;
261
+ top: 45px;
262
+ bottom: 0;
263
+ width: 2px;
264
+ background: linear-gradient(180deg, var(--primary), var(--secondary));
265
+ }
266
+
267
+ .step-dot {
268
+ width: 42px;
269
+ height: 42px;
270
+ background: rgba(99, 102, 241, 0.15);
271
+ border: 2px solid var(--primary);
272
+ border-radius: 50%;
273
+ display: flex;
274
+ align-items: center;
275
+ justify-content: center;
276
+ font-family: 'JetBrains Mono', monospace;
277
+ font-size: 0.9rem;
278
+ font-weight: 600;
279
+ color: var(--primary-light);
280
+ flex-shrink: 0;
281
+ margin-top: 2px;
282
+ z-index: 1;
283
+ }
284
+
285
+ .step-content {
286
+ flex: 1;
287
+ padding: 0 0 var(--space-xl) var(--space-lg);
288
+ }
289
+
290
+ .step-title {
291
+ font-size: 1rem;
292
+ font-weight: 600;
293
+ color: var(--text-primary);
294
+ margin-bottom: var(--space-xs);
295
+ }
296
+
297
+ .step-desc {
298
+ font-size: 0.9rem;
299
+ color: var(--text-secondary);
300
+ margin-bottom: var(--space-md);
301
+ line-height: 1.6;
302
+ }
303
+
304
+ /* ═══════════════════════════════════════════════════════════════════════════
305
+ DATASET INFO
306
+ ═══════════════════════════════════════════════════════════════════════════ */
307
+ .dataset-info {
308
+ display: flex;
309
+ align-items: center;
310
+ gap: var(--space-md);
311
+ padding: var(--space-md) var(--space-lg);
312
+ background: rgba(99, 102, 241, 0.05);
313
+ border: 1px solid rgba(99, 102, 241, 0.2);
314
+ border-radius: var(--radius-md);
315
+ margin-bottom: var(--space-lg);
316
+ }
317
+
318
+ .dataset-icon {
319
+ font-size: 1.5rem;
320
+ }
321
+
322
+ .dataset-content {
323
+ flex: 1;
324
+ }
325
+
326
+ .dataset-name {
327
+ font-size: 0.85rem;
328
+ font-weight: 600;
329
+ color: var(--text-primary);
330
+ }
331
+
332
+ .dataset-link {
333
+ font-size: 0.75rem;
334
+ color: var(--primary-light);
335
+ text-decoration: none;
336
+ }
337
+
338
+ .dataset-link:hover {
339
+ text-decoration: underline;
340
+ }
341
+
342
+ .dataset-stats {
343
+ display: flex;
344
+ gap: var(--space-md);
345
+ }
346
+
347
+ .dataset-stat {
348
+ text-align: center;
349
+ }
350
+
351
+ .dataset-stat-value {
352
+ font-family: 'JetBrains Mono', monospace;
353
+ font-size: 1rem;
354
+ font-weight: 700;
355
+ color: var(--text-primary);
356
+ }
357
+
358
+ .dataset-stat-label {
359
+ font-size: 0.65rem;
360
+ color: var(--text-muted);
361
+ text-transform: uppercase;
362
+ }
363
+
364
+ /* ═══════════════════════════════════════════════════════════════════════════
365
+ EXPECTED OUTPUT
366
+ ═══════════════════════════════════════════════════════════════════════════ */
367
+ .expected-output {
368
+ background: rgba(16, 185, 129, 0.08);
369
+ border: 1px solid rgba(16, 185, 129, 0.25);
370
+ border-radius: var(--radius-md);
371
+ padding: var(--space-md) var(--space-lg);
372
+ margin-top: var(--space-md);
373
+ }
374
+
375
+ .expected-label {
376
+ font-family: 'JetBrains Mono', monospace;
377
+ font-size: 0.65rem;
378
+ color: var(--success);
379
+ text-transform: uppercase;
380
+ letter-spacing: 1px;
381
+ margin-bottom: var(--space-xs);
382
+ }
383
+
384
+ .expected-text {
385
+ font-family: 'JetBrains Mono', monospace;
386
+ font-size: 0.8rem;
387
+ color: var(--text-secondary);
388
+ line-height: 1.6;
389
+ }
390
+
391
+ /* ═══════════════════════════════════════════════════════════════════════════
392
+ CTA SECTION
393
+ ═══════════════════════════════════════════════════════════════════════════ */
394
+ .tp-cta {
395
+ text-align: center;
396
+ padding: var(--space-3xl);
397
+ background: linear-gradient(135deg, var(--bg-card), var(--bg-tertiary));
398
+ border: 1px solid var(--border-color);
399
+ border-radius: var(--radius-lg);
400
+ margin-top: var(--space-2xl);
401
+ }
402
+
403
+ .tp-cta-icon {
404
+ font-size: 3rem;
405
+ margin-bottom: var(--space-md);
406
+ }
407
+
408
+ .tp-cta-title {
409
+ font-size: 1.5rem;
410
+ font-weight: 700;
411
+ color: var(--text-primary);
412
+ margin-bottom: var(--space-sm);
413
+ }
414
+
415
+ .tp-cta-text {
416
+ font-size: 1rem;
417
+ color: var(--text-secondary);
418
+ margin-bottom: var(--space-xl);
419
+ }
420
+
421
+ /* ═══════════════════════════════════════════════════════════════════════════
422
+ RESPONSIVE
423
+ ═══════════════════════════════════════════════════════════════════════════ */
424
+ @media (max-width: 768px) {
425
+ .tp-goals {
426
+ grid-template-columns: 1fr;
427
+ }
428
+
429
+ .tp-goal-box:first-child {
430
+ border-right: none;
431
+ border-bottom: 1px solid var(--border-color);
432
+ }
433
+
434
+ .tp-header {
435
+ flex-direction: column;
436
+ }
437
+
438
+ .dataset-info {
439
+ flex-direction: column;
440
+ text-align: center;
441
+ }
442
+
443
+ .dataset-stats {
444
+ justify-content: center;
445
+ }
446
+ }
447
+ </style>
448
+ </head>
449
+ <body>
450
+ <!-- Particles Background -->
451
+ <div class="particles-container">
452
+ <div class="particle"></div>
453
+ <div class="particle"></div>
454
+ <div class="particle"></div>
455
+ <div class="particle"></div>
456
+ <div class="particle"></div>
457
+ </div>
458
+
459
+ <!-- Navigation -->
460
+ <nav class="navbar">
461
+ <a href="index.html" class="navbar-brand">
462
+ <div class="brand-logo">🧠</div>
463
+ <span>ML Academy</span>
464
+ </a>
465
+ <div class="navbar-nav">
466
+ <a href="index.html" class="nav-link">
467
+ <span class="nav-icon">🏠</span>
468
+ <span>Accueil</span>
469
+ </a>
470
+ <a href="cours.html" class="nav-link">
471
+ <span class="nav-icon">📚</span>
472
+ <span>Cours</span>
473
+ </a>
474
+ <a href="tp.html" class="nav-link active">
475
+ <span class="nav-icon">💻</span>
476
+ <span>TPs</span>
477
+ </a>
478
+ <a href="feedback.html" class="nav-link">
479
+ <span class="nav-icon">💬</span>
480
+ <span>Contact</span>
481
+ </a>
482
+ </div>
483
+ <div class="nav-badge">
484
+ <div class="dot"></div>
485
+ <span>Google Colab Ready</span>
486
+ </div>
487
+ </nav>
488
+
489
+ <!-- Page Wrapper -->
490
+ <div class="page-wrapper">
491
+ <!-- Hero -->
492
+ <section class="tp-hero">
493
+ <div class="tp-hero-label">Travaux Pratiques</div>
494
+ <h1 class="tp-hero-title">💻 Notebooks Guidés</h1>
495
+ <p class="tp-hero-subtitle">
496
+ 6 TPs complets sur des datasets réels de Kaggle. Exécutez directement sur Google Colab,
497
+ aucune installation requise.
498
+ </p>
499
+ <div class="tp-hero-badges">
500
+ <span class="badge badge-primary">📊 6 Notebooks</span>
501
+ <span class="badge badge-success">☁️ Google Colab</span>
502
+ <span class="badge badge-secondary">📈 Datasets Kaggle</span>
503
+ <span class="badge badge-accent">0 Installation</span>
504
+ </div>
505
+ </section>
506
+
507
+ <!-- TP Container -->
508
+ <div class="tp-container">
509
+
510
+ <!-- TP 1: Titanic -->
511
+ <div class="tp-card scroll-animate">
512
+ <div class="tp-header">
513
+ <div class="tp-badge titanic">TP-1</div>
514
+ <div class="tp-header-content">
515
+ <h2 class="tp-title">Survie sur le Titanic — Classification</h2>
516
+ <div class="tp-meta">
517
+ <span class="badge badge-primary">⏱️ 30 min</span>
518
+ <span class="badge badge-secondary">Classification</span>
519
+ <span class="badge badge-success">Scikit-learn</span>
520
+ <span class="badge badge-accent">Pandas</span>
521
+ </div>
522
+ <p class="tp-description">
523
+ Prédire la survie des passagers du Titanic à partir de leurs caractéristiques
524
+ (âge, sexe, classe, etc.). Le dataset classique pour débuter en ML.
525
+ </p>
526
+ </div>
527
+ <a href="https://colab.research.google.com/drive/1TqBXWkU3XbX7QzvVv9ZqZqZqZqZqZqZq" target="_blank" class="tp-colab-btn">
528
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
529
+ <path d="M16.9 4.8C14.4 2.4 10.7 1.7 7.5 3.1L10 5.6c1.8-.4 3.8 0 5.2 1.4 2.3 2.3 2.3 6 0 8.3-1.4 1.4-3.4 1.9-5.2 1.5L7.5 19.2c3.2 1.3 6.9.6 9.4-1.8 3.4-3.4 3.4-9.2 0-12.6zm-9.8.8L4.8 8c-.8 1.2-1.2 2.6-1.2 4s.4 2.8 1.2 4l2.3-2.3c-.4-.5-.7-1.1-.8-1.7H8V9.9H6.3c.1-.6.4-1.2.8-1.7z"/>
530
+ </svg>
531
+ Ouvrir dans Colab
532
+ </a>
533
+ </div>
534
+
535
+ <div class="tp-body">
536
+ <div class="dataset-info">
537
+ <div class="dataset-icon">🚢</div>
538
+ <div class="dataset-content">
539
+ <div class="dataset-name">Dataset : Titanic - Machine Learning from Disaster</div>
540
+ <a href="https://www.kaggle.com/competitions/titanic" target="_blank" class="dataset-link">
541
+ 🔗 kaggle.com/competitions/titanic
542
+ </a>
543
+ </div>
544
+ <div class="dataset-stats">
545
+ <div class="dataset-stat">
546
+ <div class="dataset-stat-value">891</div>
547
+ <div class="dataset-stat-label">Lignes</div>
548
+ </div>
549
+ <div class="dataset-stat">
550
+ <div class="dataset-stat-value">12</div>
551
+ <div class="dataset-stat-label">Colonnes</div>
552
+ </div>
553
+ </div>
554
+ </div>
555
+
556
+ <div class="tp-goals">
557
+ <div class="tp-goal-box">
558
+ <div class="tp-goal-label">🎯 Objectif</div>
559
+ <p class="tp-goal-text">
560
+ Construire un modèle de classification binaire pour prédire si un passager
561
+ a survécu ou non au naufrage du Titanic.
562
+ </p>
563
+ </div>
564
+ <div class="tp-goal-box">
565
+ <div class="tp-goal-label">✅ Résultat attendu</div>
566
+ <p class="tp-goal-text">
567
+ Accuracy > <strong>80%</strong> sur l'ensemble de test.
568
+ Analyse de l'importance des features.
569
+ </p>
570
+ </div>
571
+ </div>
572
+
573
+ <h3 class="concepts-title">🧠 Concepts utilisés</h3>
574
+ <div class="concepts-grid">
575
+ <div class="concept-item">
576
+ <div class="concept-name">Prétraitement</div>
577
+ <div class="concept-desc">Gestion des valeurs manquantes</div>
578
+ </div>
579
+ <div class="concept-item">
580
+ <div class="concept-name">Encodage</div>
581
+ <div class="concept-desc">Variables catégorielles</div>
582
+ </div>
583
+ <div class="concept-item">
584
+ <div class="concept-name">Feature Engineering</div>
585
+ <div class="concept-desc">Création de nouvelles features</div>
586
+ </div>
587
+ <div class="concept-item">
588
+ <div class="concept-name">Random Forest</div>
589
+ <div class="concept-desc">Classification</div>
590
+ </div>
591
+ <div class="concept-item">
592
+ <div class="concept-name">Cross-Validation</div>
593
+ <div class="concept-desc">Évaluation robuste</div>
594
+ </div>
595
+ <div class="concept-item">
596
+ <div class="concept-name">Grid Search</div>
597
+ <div class="concept-desc">Optimisation hyperparamètres</div>
598
+ </div>
599
+ </div>
600
+
601
+ <h3 class="steps-title">📋 Étapes du TP</h3>
602
+ <div class="steps-list">
603
+ <div class="step-item">
604
+ <div class="step-dot">1</div>
605
+ <div class="step-content">
606
+ <div class="step-title">Exploration des données</div>
607
+ <div class="step-desc">
608
+ Charger le dataset, analyser la distribution des variables,
609
+ identifier les valeurs manquantes et les outliers.
610
+ </div>
611
+ </div>
612
+ </div>
613
+ <div class="step-item">
614
+ <div class="step-dot">2</div>
615
+ <div class="step-content">
616
+ <div class="step-title">Prétraitement</div>
617
+ <div class="step-desc">
618
+ Remplir les valeurs manquantes, encoder les variables catégorielles
619
+ (Sex, Embarked), créer des features (FamilySize, IsAlone).
620
+ </div>
621
+ </div>
622
+ </div>
623
+ <div class="step-item">
624
+ <div class="step-dot">3</div>
625
+ <div class="step-content">
626
+ <div class="step-title">Modélisation</div>
627
+ <div class="step-desc">
628
+ Entraîner plusieurs modèles : Logistic Regression, Random Forest,
629
+ Gradient Boosting. Comparer leurs performances.
630
+ </div>
631
+ <div class="expected-output">
632
+ <div class="expected-label">Résultats attendus</div>
633
+ <div class="expected-text">
634
+ Random Forest: 82% accuracy<br>
635
+ Feature importance: Sex > Pclass > Age > Fare
636
+ </div>
637
+ </div>
638
+ </div>
639
+ </div>
640
+ </div>
641
+ </div>
642
+ </div>
643
+
644
+ <!-- TP 2: House Prices -->
645
+ <div class="tp-card scroll-animate">
646
+ <div class="tp-header">
647
+ <div class="tp-badge housing">TP-2</div>
648
+ <div class="tp-header-content">
649
+ <h2 class="tp-title">Prix des Maisons — Régression Avancée</h2>
650
+ <div class="tp-meta">
651
+ <span class="badge badge-primary">⏱️ 45 min</span>
652
+ <span class="badge badge-secondary">Régression</span>
653
+ <span class="badge badge-success">XGBoost</span>
654
+ <span class="badge badge-accent">Feature Engineering</span>
655
+ </div>
656
+ <p class="tp-description">
657
+ Prédire le prix de vente des maisons à Ames, Iowa. Un problème de régression
658
+ riche en features avec beaucoup de prétraitement nécessaire.
659
+ </p>
660
+ </div>
661
+ <a href="https://colab.research.google.com/drive/1TqBXWkU3XbX7QzvVv9ZqZqZqZqZqZqZq" target="_blank" class="tp-colab-btn">
662
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
663
+ <path d="M16.9 4.8C14.4 2.4 10.7 1.7 7.5 3.1L10 5.6c1.8-.4 3.8 0 5.2 1.4 2.3 2.3 2.3 6 0 8.3-1.4 1.4-3.4 1.9-5.2 1.5L7.5 19.2c3.2 1.3 6.9.6 9.4-1.8 3.4-3.4 3.4-9.2 0-12.6zm-9.8.8L4.8 8c-.8 1.2-1.2 2.6-1.2 4s.4 2.8 1.2 4l2.3-2.3c-.4-.5-.7-1.1-.8-1.7H8V9.9H6.3c.1-.6.4-1.2.8-1.7z"/>
664
+ </svg>
665
+ Ouvrir dans Colab
666
+ </a>
667
+ </div>
668
+
669
+ <div class="tp-body">
670
+ <div class="dataset-info">
671
+ <div class="dataset-icon">🏠</div>
672
+ <div class="dataset-content">
673
+ <div class="dataset-name">Dataset : House Prices - Advanced Regression Techniques</div>
674
+ <a href="https://www.kaggle.com/competitions/house-prices-advanced-regression-techniques" target="_blank" class="dataset-link">
675
+ 🔗 kaggle.com/competitions/house-prices
676
+ </a>
677
+ </div>
678
+ <div class="dataset-stats">
679
+ <div class="dataset-stat">
680
+ <div class="dataset-stat-value">1460</div>
681
+ <div class="dataset-stat-label">Lignes</div>
682
+ </div>
683
+ <div class="dataset-stat">
684
+ <div class="dataset-stat-value">81</div>
685
+ <div class="dataset-stat-label">Colonnes</div>
686
+ </div>
687
+ </div>
688
+ </div>
689
+
690
+ <div class="tp-goals">
691
+ <div class="tp-goal-box">
692
+ <div class="tp-goal-label">🎯 Objectif</div>
693
+ <p class="tp-goal-text">
694
+ Prédire le prix de vente des maisons avec le plus faible RMSE possible
695
+ en utilisant 79 features explicatives.
696
+ </p>
697
+ </div>
698
+ <div class="tp-goal-box">
699
+ <div class="tp-goal-label">✅ Résultat attendu</div>
700
+ <p class="tp-goal-text">
701
+ RMSE <strong>&lt; 30,000$</strong> sur log-transformed prices.
702
+ Top 20% du leaderboard Kaggle.
703
+ </p>
704
+ </div>
705
+ </div>
706
+
707
+ <h3 class="concepts-title">🧠 Concepts utilisés</h3>
708
+ <div class="concepts-grid">
709
+ <div class="concept-item">
710
+ <div class="concept-name">Outlier Detection</div>
711
+ <div class="concept-desc">Détection et traitement</div>
712
+ </div>
713
+ <div class="concept-item">
714
+ <div class="concept-name">Skewness</div>
715
+ <div class="concept-desc">Transformation log</div>
716
+ </div>
717
+ <div class="concept-item">
718
+ <div class="concept-name">Correlation Analysis</div>
719
+ <div class="concept-desc">Matrice de corrélation</div>
720
+ </div>
721
+ <div class="concept-item">
722
+ <div class="concept-name">XGBoost</div>
723
+ <div class="concept-desc">Gradient boosting</div>
724
+ </div>
725
+ <div class="concept-item">
726
+ <div class="concept-name">Stacking</div>
727
+ <div class="concept-desc">Ensemble de modèles</div>
728
+ </div>
729
+ <div class="concept-item">
730
+ <div class="concept-name">K-Fold CV</div>
731
+ <div class="concept-desc">Validation croisée</div>
732
+ </div>
733
+ </div>
734
+
735
+ <h3 class="steps-title">📋 Étapes du TP</h3>
736
+ <div class="steps-list">
737
+ <div class="step-item">
738
+ <div class="step-dot">1</div>
739
+ <div class="step-content">
740
+ <div class="step-title">Analyse exploratoire avancée</div>
741
+ <div class="step-desc">
742
+ Visualiser la distribution des prix, identifier les outliers,
743
+ analyser les corrélations entre features et prix.
744
+ </div>
745
+ </div>
746
+ </div>
747
+ <div class="step-item">
748
+ <div class="step-dot">2</div>
749
+ <div class="step-content">
750
+ <div class="step-title">Feature Engineering intensif</div>
751
+ <div class="step-desc">
752
+ Créer des features composites (TotalSF, HouseAge),
753
+ regrouper les catégories rares, transformer les variables skewed.
754
+ </div>
755
+ </div>
756
+ </div>
757
+ <div class="step-item">
758
+ <div class="step-dot">3</div>
759
+ <div class="step-content">
760
+ <div class="step-title">Modélisation avancée</div>
761
+ <div class="step-desc">
762
+ XGBoost, LightGBM, Random Forest en stacking.
763
+ Optimisation des hyperparamètres avec Optuna.
764
+ </div>
765
+ <div class="expected-output">
766
+ <div class="expected-label">Résultats attendus</div>
767
+ <div class="expected-text">
768
+ XGBoost: RMSE = 0.12 (log scale)<br>
769
+ Feature importance: OverallQual > GrLivArea > GarageCars
770
+ </div>
771
+ </div>
772
+ </div>
773
+ </div>
774
+ </div>
775
+ </div>
776
+ </div>
777
+
778
+ <!-- TP 3: Iris -->
779
+ <div class="tp-card scroll-animate">
780
+ <div class="tp-header">
781
+ <div class="tp-badge iris">TP-3</div>
782
+ <div class="tp-header-content">
783
+ <h2 class="tp-title">Classification Iris — Introduction au ML</h2>
784
+ <div class="tp-meta">
785
+ <span class="badge badge-primary">⏱️ 20 min</span>
786
+ <span class="badge badge-secondary">Classification</span>
787
+ <span class="badge badge-success">Débutant</span>
788
+ <span class="badge badge-accent">Visualisation</span>
789
+ </div>
790
+ <p class="tp-description">
791
+ Le dataset classique pour la classification multi-classe.
792
+ Identifier l'espèce d'iris à partir des mesures des pétales et sépales.
793
+ </p>
794
+ </div>
795
+ <a href="https://colab.research.google.com/drive/1TqBXWkU3XbX7QzvVv9ZqZqZqZqZqZqZq" target="_blank" class="tp-colab-btn">
796
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
797
+ <path d="M16.9 4.8C14.4 2.4 10.7 1.7 7.5 3.1L10 5.6c1.8-.4 3.8 0 5.2 1.4 2.3 2.3 2.3 6 0 8.3-1.4 1.4-3.4 1.9-5.2 1.5L7.5 19.2c3.2 1.3 6.9.6 9.4-1.8 3.4-3.4 3.4-9.2 0-12.6zm-9.8.8L4.8 8c-.8 1.2-1.2 2.6-1.2 4s.4 2.8 1.2 4l2.3-2.3c-.4-.5-.7-1.1-.8-1.7H8V9.9H6.3c.1-.6.4-1.2.8-1.7z"/>
798
+ </svg>
799
+ Ouvrir dans Colab
800
+ </a>
801
+ </div>
802
+
803
+ <div class="tp-body">
804
+ <div class="dataset-info">
805
+ <div class="dataset-icon">🌸</div>
806
+ <div class="dataset-content">
807
+ <div class="dataset-name">Dataset : Iris Flower Classification</div>
808
+ <a href="https://www.kaggle.com/datasets/uciml/iris" target="_blank" class="dataset-link">
809
+ 🔗 kaggle.com/datasets/uciml/iris
810
+ </a>
811
+ </div>
812
+ <div class="dataset-stats">
813
+ <div class="dataset-stat">
814
+ <div class="dataset-stat-value">150</div>
815
+ <div class="dataset-stat-label">Lignes</div>
816
+ </div>
817
+ <div class="dataset-stat">
818
+ <div class="dataset-stat-value">5</div>
819
+ <div class="dataset-stat-label">Colonnes</div>
820
+ </div>
821
+ </div>
822
+ </div>
823
+
824
+ <div class="tp-goals">
825
+ <div class="tp-goal-box">
826
+ <div class="tp-goal-label">🎯 Objectif</div>
827
+ <p class="tp-goal-text">
828
+ Classifier les iris en 3 espèces (Setosa, Versicolor, Virginica)
829
+ à partir de 4 features numériques.
830
+ </p>
831
+ </div>
832
+ <div class="tp-goal-box">
833
+ <div class="tp-goal-label">✅ Résultat attendu</div>
834
+ <p class="tp-goal-text">
835
+ Accuracy de <strong>95%+</strong>. Visualisation des frontières de décision.
836
+ </p>
837
+ </div>
838
+ </div>
839
+
840
+ <h3 class="concepts-title">🧠 Concepts utilisés</h3>
841
+ <div class="concepts-grid">
842
+ <div class="concept-item">
843
+ <div class="concept-name">KNN</div>
844
+ <div class="concept-desc">K-Nearest Neighbors</div>
845
+ </div>
846
+ <div class="concept-item">
847
+ <div class="concept-name">SVM</div>
848
+ <div class="concept-desc">Support Vector Machine</div>
849
+ </div>
850
+ <div class="concept-item">
851
+ <div class="concept-name">Decision Boundary</div>
852
+ <div class="concept-desc">Visualisation</div>
853
+ </div>
854
+ <div class="concept-item">
855
+ <div class="concept-name">PCA</div>
856
+ <div class="concept-desc">Réduction de dimension</div>
857
+ </div>
858
+ <div class="concept-item">
859
+ <div class="concept-name">Pairplot</div>
860
+ <div class="concept-desc">Visualisation multi-variables</div>
861
+ </div>
862
+ <div class="concept-item">
863
+ <div class="concept-name">Confusion Matrix</div>
864
+ <div class="concept-desc">Évaluation détaillée</div>
865
+ </div>
866
+ </div>
867
+
868
+ <h3 class="steps-title">📋 Étapes du TP</h3>
869
+ <div class="steps-list">
870
+ <div class="step-item">
871
+ <div class="step-dot">1</div>
872
+ <div class="step-content">
873
+ <div class="step-title">Visualisation exploratoire</div>
874
+ <div class="step-desc">
875
+ Pairplot pour voir les relations entre features,
876
+ boxplots par espèce pour identifier les patterns.
877
+ </div>
878
+ </div>
879
+ </div>
880
+ <div class="step-item">
881
+ <div class="step-dot">2</div>
882
+ <div class="step-content">
883
+ <div class="step-title">Comparaison des algorithmes</div>
884
+ <div class="step-desc">
885
+ KNN, SVM, Decision Tree, Random Forest.
886
+ Comparer accuracy et temps d'entraînement.
887
+ </div>
888
+ </div>
889
+ </div>
890
+ <div class="step-item">
891
+ <div class="step-dot">3</div>
892
+ <div class="step-content">
893
+ <div class="step-title">Visualisation des frontières</div>
894
+ <div class="step-desc">
895
+ Tracer les frontières de décision en 2D après PCA.
896
+ Comprendre comment chaque algorithme sépare les classes.
897
+ </div>
898
+ <div class="expected-output">
899
+ <div class="expected-label">Résultats attendus</div>
900
+ <div class="expected-text">
901
+ SVM: 98% accuracy<br>
902
+ Setosa parfaitement séparable, Virginica/Versicolor plus proches
903
+ </div>
904
+ </div>
905
+ </div>
906
+ </div>
907
+ </div>
908
+ </div>
909
+ </div>
910
+
911
+ <!-- TP 4: Energy Consumption -->
912
+ <div class="tp-card scroll-animate">
913
+ <div class="tp-header">
914
+ <div class="tp-badge energy">TP-4</div>
915
+ <div class="tp-header-content">
916
+ <h2 class="tp-title">Consommation Énergétique — Séries Temporelles</h2>
917
+ <div class="tp-meta">
918
+ <span class="badge badge-primary">⏱️ 40 min</span>
919
+ <span class="badge badge-secondary">Time Series</span>
920
+ <span class="badge badge-success">LSTM</span>
921
+ <span class="badge badge-accent">TensorFlow</span>
922
+ </div>
923
+ <p class="tp-description">
924
+ Prédire la consommation électrique d'un bâtiment à partir de données
925
+ temporelles. Introduction aux LSTM et aux prédictions séquentielles.
926
+ </p>
927
+ </div>
928
+ <a href="https://colab.research.google.com/drive/1TqBXWkU3XbX7QzvVv9ZqZqZqZqZqZqZq" target="_blank" class="tp-colab-btn">
929
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
930
+ <path d="M16.9 4.8C14.4 2.4 10.7 1.7 7.5 3.1L10 5.6c1.8-.4 3.8 0 5.2 1.4 2.3 2.3 2.3 6 0 8.3-1.4 1.4-3.4 1.9-5.2 1.5L7.5 19.2c3.2 1.3 6.9.6 9.4-1.8 3.4-3.4 3.4-9.2 0-12.6zm-9.8.8L4.8 8c-.8 1.2-1.2 2.6-1.2 4s.4 2.8 1.2 4l2.3-2.3c-.4-.5-.7-1.1-.8-1.7H8V9.9H6.3c.1-.6.4-1.2.8-1.7z"/>
931
+ </svg>
932
+ Ouvrir dans Colab
933
+ </a>
934
+ </div>
935
+
936
+ <div class="tp-body">
937
+ <div class="dataset-info">
938
+ <div class="dataset-icon">⚡</div>
939
+ <div class="dataset-content">
940
+ <div class="dataset-name">Dataset : ASHRAE - Great Energy Predictor III</div>
941
+ <a href="https://www.kaggle.com/c/ashrae-energy-prediction" target="_blank" class="dataset-link">
942
+ 🔗 kaggle.com/c/ashrae-energy-prediction
943
+ </a>
944
+ </div>
945
+ <div class="dataset-stats">
946
+ <div class="dataset-stat">
947
+ <div class="dataset-stat-value">20M+</div>
948
+ <div class="dataset-stat-label">Lignes</div>
949
+ </div>
950
+ <div class="dataset-stat">
951
+ <div class="dataset-stat-value">1449</div>
952
+ <div class="dataset-stat-label">Bâtiments</div>
953
+ </div>
954
+ </div>
955
+ </div>
956
+
957
+ <div class="tp-goals">
958
+ <div class="tp-goal-box">
959
+ <div class="tp-goal-label">🎯 Objectif</div>
960
+ <p class="tp-goal-text">
961
+ Prédire la consommation énergétique horaire de bâtiments
962
+ à partir de données météo et historiques.
963
+ </p>
964
+ </div>
965
+ <div class="tp-goal-box">
966
+ <div class="tp-goal-label">✅ Résultat attendu</div>
967
+ <p class="tp-goal-text">
968
+ RMSE <strong>&lt; 100</strong> sur la consommation normalisée.
969
+ Capture des patterns journaliers et saisonniers.
970
+ </p>
971
+ </div>
972
+ </div>
973
+
974
+ <h3 class="concepts-title">🧠 Concepts utilisés</h3>
975
+ <div class="concepts-grid">
976
+ <div class="concept-item">
977
+ <div class="concept-name">Time Series</div>
978
+ <div class="concept-desc">Traitement séquentiel</div>
979
+ </div>
980
+ <div class="concept-item">
981
+ <div class="concept-name">LSTM</div>
982
+ <div class="concept-desc">Réseaux récurrents</div>
983
+ </div>
984
+ <div class="concept-item">
985
+ <div class="concept-name">Seasonality</div>
986
+ <div class="concept-desc">Patterns saisonniers</div>
987
+ </div>
988
+ <div class="concept-item">
989
+ <div class="concept-name">Windowing</div>
990
+ <div class="concept-desc">Fenêtres glissantes</div>
991
+ </div>
992
+ <div class="concept-item">
993
+ <div class="concept-name">Early Stopping</div>
994
+ <div class="concept-desc">Arrêt automatique</div>
995
+ </div>
996
+ <div class="concept-item">
997
+ <div class="concept-name">TensorBoard</div>
998
+ <div class="concept-desc">Visualisation training</div>
999
+ </div>
1000
+ </div>
1001
+
1002
+ <h3 class="steps-title">📋 Étapes du TP</h3>
1003
+ <div class="steps-list">
1004
+ <div class="step-item">
1005
+ <div class="step-dot">1</div>
1006
+ <div class="step-content">
1007
+ <div class="step-title">Analyse temporelle</div>
1008
+ <div class="step-desc">
1009
+ Visualiser les patterns horaires, journaliers, hebdomadaires.
1010
+ Identifier la saisonnalité et les tendances.
1011
+ </div>
1012
+ </div>
1013
+ </div>
1014
+ <div class="step-item">
1015
+ <div class="step-dot">2</div>
1016
+ <div class="step-content">
1017
+ <div class="step-title">Feature Engineering temporel</div>
1018
+ <div class="step-desc">
1019
+ Créer des features temporelles (hour, day_of_week, month),
1020
+ lags (valeurs précédentes), rolling statistics.
1021
+ </div>
1022
+ </div>
1023
+ </div>
1024
+ <div class="step-item">
1025
+ <div class="step-dot">3</div>
1026
+ <div class="step-content">
1027
+ <div class="step-title">Modélisation LSTM</div>
1028
+ <div class="step-desc">
1029
+ Construire un modèle LSTM avec Keras.
1030
+ Entraînement avec early stopping et learning rate scheduling.
1031
+ </div>
1032
+ <div class="expected-output">
1033
+ <div class="expected-label">Résultats attendus</div>
1034
+ <div class="expected-text">
1035
+ LSTM: RMSE = 85 sur test set<br>
1036
+ Capture des pics de consommation matin/soir
1037
+ </div>
1038
+ </div>
1039
+ </div>
1040
+ </div>
1041
+ </div>
1042
+ </div>
1043
+ </div>
1044
+
1045
+ <!-- TP 5: MNIST -->
1046
+ <div class="tp-card scroll-animate">
1047
+ <div class="tp-header">
1048
+ <div class="tp-badge mnist">TP-5</div>
1049
+ <div class="tp-header-content">
1050
+ <h2 class="tp-title">Reconnaissance de Chiffres — Deep Learning</h2>
1051
+ <div class="tp-meta">
1052
+ <span class="badge badge-primary">⏱️ 35 min</span>
1053
+ <span class="badge badge-secondary">CNN</span>
1054
+ <span class="badge badge-success">Computer Vision</span>
1055
+ <span class="badge badge-accent">Keras</span>
1056
+ </div>
1057
+ <p class="tp-description">
1058
+ Classification d'images de chiffres manuscrits (0-9) avec des réseaux de neurones convolutifs (CNN).
1059
+ Introduction au Computer Vision.
1060
+ </p>
1061
+ </div>
1062
+ <a href="https://colab.research.google.com/drive/1TqBXWkU3XbX7QzvVv9ZqZqZqZqZqZqZq" target="_blank" class="tp-colab-btn">
1063
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
1064
+ <path d="M16.9 4.8C14.4 2.4 10.7 1.7 7.5 3.1L10 5.6c1.8-.4 3.8 0 5.2 1.4 2.3 2.3 2.3 6 0 8.3-1.4 1.4-3.4 1.9-5.2 1.5L7.5 19.2c3.2 1.3 6.9.6 9.4-1.8 3.4-3.4 3.4-9.2 0-12.6zm-9.8.8L4.8 8c-.8 1.2-1.2 2.6-1.2 4s.4 2.8 1.2 4l2.3-2.3c-.4-.5-.7-1.1-.8-1.7H8V9.9H6.3c.1-.6.4-1.2.8-1.7z"/>
1065
+ </svg>
1066
+ Ouvrir dans Colab
1067
+ </a>
1068
+ </div>
1069
+
1070
+ <div class="tp-body">
1071
+ <div class="dataset-info">
1072
+ <div class="dataset-icon">🔢</div>
1073
+ <div class="dataset-content">
1074
+ <div class="dataset-name">Dataset : MNIST Handwritten Digits</div>
1075
+ <a href="https://www.kaggle.com/datasets/hojjatk/mnist-dataset" target="_blank" class="dataset-link">
1076
+ 🔗 kaggle.com/datasets/hojjatk/mnist-dataset
1077
+ </a>
1078
+ </div>
1079
+ <div class="dataset-stats">
1080
+ <div class="dataset-stat">
1081
+ <div class="dataset-stat-value">70K</div>
1082
+ <div class="dataset-stat-label">Images</div>
1083
+ </div>
1084
+ <div class="dataset-stat">
1085
+ <div class="dataset-stat-value">28×28</div>
1086
+ <div class="dataset-stat-label">Pixels</div>
1087
+ </div>
1088
+ </div>
1089
+ </div>
1090
+
1091
+ <div class="tp-goals">
1092
+ <div class="tp-goal-box">
1093
+ <div class="tp-goal-label">🎯 Objectif</div>
1094
+ <p class="tp-goal-text">
1095
+ Classifier les images de chiffres manuscrits (0-9)
1096
+ avec un CNN et atteindre >99% d'accuracy.
1097
+ </p>
1098
+ </div>
1099
+ <div class="tp-goal-box">
1100
+ <div class="tp-goal-label">✅ Résultat attendu</div>
1101
+ <p class="tp-goal-text">
1102
+ Accuracy de <strong>99%+</strong> sur le test set.
1103
+ Visualisation des filtres appris par le CNN.
1104
+ </p>
1105
+ </div>
1106
+ </div>
1107
+
1108
+ <h3 class="concepts-title">🧠 Concepts utilisés</h3>
1109
+ <div class="concepts-grid">
1110
+ <div class="concept-item">
1111
+ <div class="concept-name">CNN</div>
1112
+ <div class="concept-desc">Convolutional Neural Network</div>
1113
+ </div>
1114
+ <div class="concept-item">
1115
+ <div class="concept-name">Conv2D</div>
1116
+ <div class="concept-desc">Couches de convolution</div>
1117
+ </div>
1118
+ <div class="concept-item">
1119
+ <div class="concept-name">MaxPooling</div>
1120
+ <div class="concept-desc">Réduction spatiale</div>
1121
+ </div>
1122
+ <div class="concept-item">
1123
+ <div class="concept-name">Dropout</div>
1124
+ <div class="concept-desc">Régularisation</div>
1125
+ </div>
1126
+ <div class="concept-item">
1127
+ <div class="concept-name">BatchNorm</div>
1128
+ <div class="concept-desc">Normalisation</div>
1129
+ </div>
1130
+ <div class="concept-item">
1131
+ <div class="concept-name">Data Augmentation</div>
1132
+ <div class="concept-desc">Augmentation données</div>
1133
+ </div>
1134
+ </div>
1135
+
1136
+ <h3 class="steps-title">📋 Étapes du TP</h3>
1137
+ <div class="steps-list">
1138
+ <div class="step-item">
1139
+ <div class="step-dot">1</div>
1140
+ <div class="step-content">
1141
+ <div class="step-title">Exploration des images</div>
1142
+ <div class="step-desc">
1143
+ Visualiser des exemples de chaque chiffre,
1144
+ analyser la distribution des classes.
1145
+ </div>
1146
+ </div>
1147
+ </div>
1148
+ <div class="step-item">
1149
+ <div class="step-dot">2</div>
1150
+ <div class="step-content">
1151
+ <div class="step-title">Construction du CNN</div>
1152
+ <div class="step-desc">
1153
+ Architecture: Conv2D → MaxPool → Conv2D → MaxPool →
1154
+ Flatten → Dense → Dropout → Output (10 classes).
1155
+ </div>
1156
+ </div>
1157
+ </div>
1158
+ <div class="step-item">
1159
+ <div class="step-dot">3</div>
1160
+ <div class="step-content">
1161
+ <div class="step-title">Entraînement et évaluation</div>
1162
+ <div class="step-desc">
1163
+ Entraînement avec data augmentation,
1164
+ visualisation des prédictions erronées.
1165
+ </div>
1166
+ <div class="expected-output">
1167
+ <div class="expected-label">Résultats attendus</div>
1168
+ <div class="expected-text">
1169
+ CNN: 99.2% accuracy<br>
1170
+ Erreurs principalement sur 4/9 et 3/8 similaires
1171
+ </div>
1172
+ </div>
1173
+ </div>
1174
+ </div>
1175
+ </div>
1176
+ </div>
1177
+ </div>
1178
+
1179
+ <!-- TP 6: Sentiment Analysis -->
1180
+ <div class="tp-card scroll-animate">
1181
+ <div class="tp-header">
1182
+ <div class="tp-badge sentiment">TP-6</div>
1183
+ <div class="tp-header-content">
1184
+ <h2 class="tp-title">Analyse de Sentiment — NLP</h2>
1185
+ <div class="tp-meta">
1186
+ <span class="badge badge-primary">⏱️ 40 min</span>
1187
+ <span class="badge badge-secondary">NLP</span>
1188
+ <span class="badge badge-success">Embeddings</span>
1189
+ <span class="badge badge-accent">Transformers</span>
1190
+ </div>
1191
+ <p class="tp-description">
1192
+ Classifier les avis IMDB comme positifs ou négatifs.
1193
+ Introduction au NLP et aux word embeddings avec les Transformers.
1194
+ </p>
1195
+ </div>
1196
+ <a href="https://colab.research.google.com/drive/1TqBXWkU3XbX7QzvVv9ZqZqZqZqZqZqZq" target="_blank" class="tp-colab-btn">
1197
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
1198
+ <path d="M16.9 4.8C14.4 2.4 10.7 1.7 7.5 3.1L10 5.6c1.8-.4 3.8 0 5.2 1.4 2.3 2.3 2.3 6 0 8.3-1.4 1.4-3.4 1.9-5.2 1.5L7.5 19.2c3.2 1.3 6.9.6 9.4-1.8 3.4-3.4 3.4-9.2 0-12.6zm-9.8.8L4.8 8c-.8 1.2-1.2 2.6-1.2 4s.4 2.8 1.2 4l2.3-2.3c-.4-.5-.7-1.1-.8-1.7H8V9.9H6.3c.1-.6.4-1.2.8-1.7z"/>
1199
+ </svg>
1200
+ Ouvrir dans Colab
1201
+ </a>
1202
+ </div>
1203
+
1204
+ <div class="tp-body">
1205
+ <div class="dataset-info">
1206
+ <div class="dataset-icon">🎬</div>
1207
+ <div class="dataset-content">
1208
+ <div class="dataset-name">Dataset : IMDB Movie Reviews</div>
1209
+ <a href="https://www.kaggle.com/datasets/lakshmi25npathi/imdb-dataset-of-50k-movie-reviews" target="_blank" class="dataset-link">
1210
+ 🔗 kaggle.com/datasets/lakshmi25npathi/imdb-dataset
1211
+ </a>
1212
+ </div>
1213
+ <div class="dataset-stats">
1214
+ <div class="dataset-stat">
1215
+ <div class="dataset-stat-value">50K</div>
1216
+ <div class="dataset-stat-label">Avis</div>
1217
+ </div>
1218
+ <div class="dataset-stat">
1219
+ <div class="dataset-stat-value">2</div>
1220
+ <div class="dataset-stat-label">Classes</div>
1221
+ </div>
1222
+ </div>
1223
+ </div>
1224
+
1225
+ <div class="tp-goals">
1226
+ <div class="tp-goal-box">
1227
+ <div class="tp-goal-label">🎯 Objectif</div>
1228
+ <p class="tp-goal-text">
1229
+ Classifier les avis de films comme positifs ou négatifs
1230
+ en utilisant des embeddings et un LSTM ou BERT.
1231
+ </p>
1232
+ </div>
1233
+ <div class="tp-goal-box">
1234
+ <div class="tp-goal-label">✅ Résultat attendu</div>
1235
+ <p class="tp-goal-text">
1236
+ Accuracy de <strong>90%+</strong> avec LSTM,
1237
+ <strong>95%+</strong> avec BERT fine-tuning.
1238
+ </p>
1239
+ </div>
1240
+ </div>
1241
+
1242
+ <h3 class="concepts-title">🧠 Concepts utilisés</h3>
1243
+ <div class="concepts-grid">
1244
+ <div class="concept-item">
1245
+ <div class="concept-name">Tokenization</div>
1246
+ <div class="concept-desc">Découpage en tokens</div>
1247
+ </div>
1248
+ <div class="concept-item">
1249
+ <div class="concept-name">Word Embeddings</div>
1250
+ <div class="concept-desc">Word2Vec, GloVe</div>
1251
+ </div>
1252
+ <div class="concept-item">
1253
+ <div class="concept-name">LSTM pour NLP</div>
1254
+ <div class="concept-desc">Séquences de texte</div>
1255
+ </div>
1256
+ <div class="concept-item">
1257
+ <div class="concept-name">Attention</div>
1258
+ <div class="concept-desc">Mécanisme d'attention</div>
1259
+ </div>
1260
+ <div class="concept-item">
1261
+ <div class="concept-name">BERT</div>
1262
+ <div class="concept-desc">Transformers pré-entraînés</div>
1263
+ </div>
1264
+ <div class="concept-item">
1265
+ <div class="concept-name">Hugging Face</div>
1266
+ <div class="concept-desc">Bibliothèque transformers</div>
1267
+ </div>
1268
+ </div>
1269
+
1270
+ <h3 class="steps-title">📋 Étapes du TP</h3>
1271
+ <div class="steps-list">
1272
+ <div class="step-item">
1273
+ <div class="step-dot">1</div>
1274
+ <div class="step-content">
1275
+ <div class="step-title">Prétraitement du texte</div>
1276
+ <div class="step-desc">
1277
+ Nettoyage (HTML, ponctuation), tokenization,
1278
+ padding/truncation pour avoir des séquences de même longueur.
1279
+ </div>
1280
+ </div>
1281
+ </div>
1282
+ <div class="step-item">
1283
+ <div class="step-dot">2</div>
1284
+ <div class="step-content">
1285
+ <div class="step-title">Embeddings et LSTM</div>
1286
+ <div class="step-desc">
1287
+ Couche d'embedding apprenable + LSTM bidirectionnel
1288
+ + couche dense de sortie.
1289
+ </div>
1290
+ </div>
1291
+ </div>
1292
+ <div class="step-item">
1293
+ <div class="step-dot">3</div>
1294
+ <div class="step-content">
1295
+ <div class="step-title">Fine-tuning BERT (bonus)</div>
1296
+ <div class="step-desc">
1297
+ Utiliser un modèle BERT pré-entraîné via Hugging Face,
1298
+ fine-tuner sur les avis IMDB.
1299
+ </div>
1300
+ <div class="expected-output">
1301
+ <div class="expected-label">Résultats attendus</div>
1302
+ <div class="expected-text">
1303
+ LSTM: 88% accuracy<br>
1304
+ BERT fine-tuned: 94% accuracy
1305
+ </div>
1306
+ </div>
1307
+ </div>
1308
+ </div>
1309
+ </div>
1310
+ </div>
1311
+ </div>
1312
+
1313
+ <!-- CTA -->
1314
+ <div class="tp-cta scroll-animate">
1315
+ <div class="tp-cta-icon" style="width: 60px; height: 60px; background: linear-gradient(135deg, var(--success), #059669); border-radius: var(--radius-lg); display: flex; align-items: center; justify-content: center; font-size: 1.5rem; font-weight: 700; color: white; margin: 0 auto var(--space-md);">OK</div>
1316
+ <h2 class="tp-cta-title">TPs termines ?</h2>
1317
+ <p class="tp-cta-text">
1318
+ Felicitations ! Vous avez maintenant une solide experience pratique
1319
+ en Machine Learning. Continuez avec le cours theorique ou posez vos questions.
1320
+ </p>
1321
+ <div class="cta-buttons" style="display: flex; gap: var(--space-md); justify-content: center; flex-wrap: wrap;">
1322
+ <a href="cours.html" class="btn btn-primary btn-lg">Retour aux cours</a>
1323
+ <a href="feedback.html" class="btn btn-outline btn-lg">Poser une question</a>
1324
+ </div>
1325
+ </div>
1326
+
1327
+ </div>
1328
+
1329
+ <!-- Author Footer -->
1330
+ <footer class="footer" style="background: var(--bg-secondary); border-top: 1px solid var(--border-color); padding: var(--space-xl); text-align: center;">
1331
+ <div style="display: flex; justify-content: center; gap: var(--space-xl); flex-wrap: wrap; margin-bottom: var(--space-md);">
1332
+ <a href="mailto:imadmaalouf02@gmail.com" style="display: flex; align-items: center; gap: var(--space-sm); color: var(--text-secondary); text-decoration: none; font-size: 0.9rem;">
1333
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor"><path d="M20 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 4l-8 5-8-5V6l8 5 8-5v2z"/></svg>
1334
+ imadmaalouf02@gmail.com
1335
+ </a>
1336
+ <a href="https://github.com/imadmaalouf02" target="_blank" style="display: flex; align-items: center; gap: var(--space-sm); color: var(--text-secondary); text-decoration: none; font-size: 0.9rem;">
1337
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/></svg>
1338
+ GitHub
1339
+ </a>
1340
+ <a href="https://huggingface.co/spaces/MAALOOUF/ML_Training" target="_blank" style="display: flex; align-items: center; gap: var(--space-sm); color: var(--text-secondary); text-decoration: none; font-size: 0.9rem;">
1341
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 17.93c-3.95-.49-7-3.85-7-7.93 0-.62.08-1.21.21-1.79L9 15v1c0 1.1.9 2 2 2v1.93zm6.9-2.54c-.26-.81-1-1.39-1.9-1.39h-1v-3c0-.55-.45-1-1-1H8v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41c2.93 1.19 5 4.06 5 7.41 0 2.08-.8 3.97-2.1 5.39z"/></svg>
1342
+ Hugging Face Space
1343
+ </a>
1344
+ </div>
1345
+ </footer>
1346
+
1347
+ <!-- Footer -->
1348
+ <footer class="footer">
1349
+ <p class="footer-text">
1350
+ ML Academy — Travaux Pratiques —
1351
+ <span class="footer-brand">GE-MCI 4A</span> — 2025/2026
1352
+ </p>
1353
+ <p class="footer-text" style="margin-top: var(--space-sm);">
1354
+ Datasets : Kaggle · Execution : Google Colab · Notebooks : Python
1355
+ </p>
1356
+ <p class="footer-text" style="margin-top: var(--space-sm); font-size: 0.75rem; color: var(--text-muted);">
1357
+ Formateur : Imad Maalouf
1358
+ </p>
1359
+ </footer>
1360
+ </div>
1361
+
1362
+ <!-- Scripts -->
1363
+ <script src="js/shared.js"></script>
1364
+ <script>
1365
+ // Scroll animations
1366
+ const observerOptions = {
1367
+ threshold: 0.1,
1368
+ rootMargin: '0px 0px -50px 0px'
1369
+ };
1370
+
1371
+ const observer = new IntersectionObserver((entries) => {
1372
+ entries.forEach(entry => {
1373
+ if (entry.isIntersecting) {
1374
+ entry.target.classList.add('visible');
1375
+ }
1376
+ });
1377
+ }, observerOptions);
1378
+
1379
+ document.querySelectorAll('.scroll-animate').forEach(el => {
1380
+ observer.observe(el);
1381
+ });
1382
+
1383
+ // Stagger animation for cards
1384
+ document.querySelectorAll('.tp-card').forEach((card, index) => {
1385
+ card.style.animationDelay = `${index * 0.15}s`;
1386
+ });
1387
+ </script>
1388
+ </body>
1389
+ </html>