Repository navigation
Expand file tree
/
Copy pathcourse_content.py
More file actions
1363 lines (1248 loc) · 52 KB
/
Copy pathcourse_content.py
File metadata and controls
1363 lines (1248 loc) · 52 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# -*- coding: utf-8 -*-
COURSE_DATA = {
1: {
"title": "Moduł 1: Składnia Python w Modelach Ekonomicznych",
"tasks": {
1: {
"title": "Witaj w Pythonie (Hello World & Zmienne)",
"lesson": """
Witaj w Module 1! Zaczynamy od absolutnych podstaw programowania.
Pierwszym krokiem każdego programisty jest napisanie programu, który wita się ze światem ("Hello, World!").
Dodatkowo poznasz pojęcie zmiennych – to jak szufladki w pamięci komputera, w których przechowujemy dane, np. wartości ekonomiczne.
Twoim zadaniem jest zaimplementowanie dwóch funkcji w pliku exercises/module_1/task_1.py:
1. `hello_world()` - funkcja ma zwracać tekst "Hello, World!".
2. `get_gdp_value()` - funkcja ma tworzyć zmienną `gdp` o wartości 1500.0 (liczba zmiennoprzecinkowa) i ją zwracać.
""",
"theory": """
=== Podstawy programowania w Pythonie ===
1. Funkcja print() i zwracanie wartości (return):
Funkcje to wydzielone fragmenty kodu. Słowo kluczowe `return` przekazuje wynik działania funkcji na zewnątrz.
W Pythonie teksty zapisujemy w cudzysłowach (np. "Hello, World!" lub 'Hello, World!').
def przywitanie():
return "Witaj!"
2. Zmienne (Variables) i Typy Danych:
Zmienna to nazwa, pod którą przechowujemy dane. Nazwę zmiennej piszemy małymi literami (np. `gdp` lub `inflacja`).
W Pythonie mamy różne typy danych:
- int (liczby całkowite, np. `rok = 2026`)
- float (liczby rzeczywiste/zmiennoprzecinkowe, np. `gdp = 1500.0`)
- str (tekst, np. `kraj = "Polska"`)
Aby przypisać wartość do zmiennej, używamy znaku `=`:
inflacja = 2.5
return inflacja
""",
"hint": """
Wskazówki implementacyjne:
- `hello_world()`: Wpisz linijkę `return "Hello, World!"`.
- `get_gdp_value()`:
1. Stwórz zmienną: `gdp = 1500.0`
2. Zwróć ją: `return gdp`
""",
"template": """# -*- coding: utf-8 -*-
def hello_world() -> str:
\"\"\"
Zwraca tekst "Hello, World!".
\"\"\"
# TWÓJ KOD TUTAJ
pass
def get_gdp_value() -> float:
\"\"\"
Tworzy zmienną gdp o wartości 1500.0 i ją zwraca.
\"\"\"
# TWÓJ KOD TUTAJ
pass
""",
"exercise_path": "exercises/module_1/task_1.py",
"test_path": ".agents/tests/test_module_1.py"
},
2: {
"title": "Podstawowe Operacje Matematyczne (Model PKB)",
"lesson": """
Wspaniale! Teraz poćwiczymy podstawowe operacje matematyczne.
W ekonomii jednym z podstawowych modeli jest tożsamość PKB (metoda wydatkowa):
PKB = C + I + G + (X - M)
Gdzie:
- C: Konsumpcja (Consumption)
- I: Inwestycje (Investment)
- G: Wydatki rządowe (Government spending)
- X: Eksport (Exports)
- M: Import (Imports)
Różnica (X - M) to eksport netto.
Twoim zadaniem jest uzupełnienie funkcji `calculate_gdp(c, i, g, x, m)` w exercises/module_1/task_2.py, która obliczy i zwróci wartość PKB na podstawie przekazanych parametrów.
""",
"theory": """
=== Operacje matematyczne w Pythonie ===
Python pozwala wykonywać standardowe działania matematyczne:
- dodawanie: `+`
- odejmowanie: `-`
- mnożenie: `*`
- dzielenie: `/`
Kolejność wykonywania działań jest taka sama jak w matematyce. Możesz używać nawiasów okrągłych `()`, aby kontrolować kolejność operacji:
wynik = a + b + c + (d - e)
""",
"hint": """
Wskazówki implementacyjne:
Wewnątrz funkcji `calculate_gdp(c, i, g, x, m)` wpisz linijkę:
`return c + i + g + (x - m)`
""",
"template": """# -*- coding: utf-8 -*-
def calculate_gdp(c: float, i: float, g: float, x: float, m: float) -> float:
\"\"\"
Oblicza PKB ze wzoru: C + I + G + (X - M)
\"\"\"
# TWÓJ KOD TUTAJ
pass
""",
"exercise_path": "exercises/module_1/task_2.py",
"test_path": ".agents/tests/test_module_1_2.py"
},
3: {
"title": "Kalkulator NPV i Wartości Pieniądza w Czasie",
"lesson": """
Teraz jesteś gotowy na trudniejsze zadanie! Wykorzystamy pętle i listy w modelu wartości pieniądza w czasie.
Wzory:
1. Future Value (FV): FV = PV * (1 + r)^n
2. Present Value (PV): PV = FV / (1 + r)^n
3. Net Present Value (NPV): NPV = suma_{t=0}^{N} (CF_t / (1 + r)^t)
gdzie CF_0 to nakład początkowy (wartość ujemna).
Twoim zadaniem jest zaimplementowanie tych trzech funkcji w pliku exercises/module_1/task_3.py.
""",
"theory": """
=== Podstawy składni Pythona dla Modelu NPV ===
1. Pętle (Loops) i Listy (Lists):
Pętla `for` pozwala powtarzać czynności.
Funkcja `enumerate(lista)` zwraca pary: (indeks, wartość).
Przykład:
for t, cf in enumerate(cash_flows):
# t to rok (0, 1, 2...), cf to przepływ w tym roku.
2. Potęgowanie:
W Pythonie potęgowanie zapisujemy jako podwójną gwiazdkę `**`:
mnożnik = (1 + r) ** n
""",
"hint": """
Wskazówki implementacyjne:
- `calculate_fv(pv, r, n)`: Zwróć `pv * ((1 + r) ** n)`.
- `calculate_pv(fv, r, n)`: Zwróć `fv / ((1 + r) ** n)`.
- `calculate_npv(cash_flows, r)`:
1. Stwórz zmienną sumującą: `npv_sum = 0.0`.
2. Użyj pętli: `for t, cf in enumerate(cash_flows):`
3. Dodaj zdyskontowaną wartość do sumy: `npv_sum += cf / ((1 + r) ** t)`.
4. Zwróć `npv_sum`.
""",
"template": """# -*- coding: utf-8 -*-
def calculate_fv(pv: float, r: float, n: int) -> float:
\"\"\"
Oblicza Future Value (Wartość Przyszłą).
\"\"\"
# TWÓJ KOD TUTAJ
pass
def calculate_pv(fv: float, r: float, n: int) -> float:
\"\"\"
Oblicza Present Value (Wartość Obecną).
\"\"\"
# TWÓJ KOD TUTAJ
pass
def calculate_npv(cash_flows: list, r: float) -> float:
\"\"\"
Oblicza Net Present Value (Wartość Bieżącą Netto).
\"\"\"
# TWÓJ KOD TUTAJ
pass
""",
"exercise_path": "exercises/module_1/task_3.py",
"test_path": ".agents/tests/test_module_1_3.py"
}
}
},
2: {
"title": "Moduł 2: Kontrola Przepływu, Słowniki & Serializacja JSON",
"tasks": {
1: {
"title": "Klasyfikacja poziomu dochodów (If-Elif-Else)",
"lesson": """
Witaj w Module 2!
W pracy analityka często musisz grupować dane na podstawie progów wartościowych.
Twoim zadaniem jest napisanie funkcji `classify_income(income)`, która zwróci klasyfikację tekstową:
- Dla dochodu poniżej 30000 -> "Niski"
- Dla dochodu od 30000 do 85000 (wyłącznie) -> "Średni"
- Dla dochodu 85000 i powyżej -> "Wysoki"
Kod uzupełnij w exercises/module_2/task_1.py.
""",
"theory": """
=== Instrukcje warunkowe (if-elif-else) ===
Instrukcje warunkowe sterują przepływem programu na podstawie testów logicznych:
```python
if income < 30000:
return "Niski"
elif income < 85000:
return "Średni"
else:
return "Wysoki"
```
""",
"hint": """
Użyj standardowych operatorów porównania: `<` oraz `>=`. Warunek `elif` sprawdzany jest tylko wtedy, gdy poprzedni `if` był fałszywy.
""",
"template": """# -*- coding: utf-8 -*-
def classify_income(income: float) -> str:
\"\"\"
Klasyfikuje dochód do jednej z trzech kategorii: "Niski", "Średni", "Wysoki".
\"\"\"
# TWÓJ KOD TUTAJ
pass
""",
"exercise_path": "exercises/module_2/task_1.py",
"test_path": ".agents/tests/test_module_2_1.py"
},
2: {
"title": "Zarządzanie kartoteką klientów (Słowniki)",
"lesson": """
Witaj w zadaniu 2.2!
Słowniki (`dict`) w Pythonie przechowują pary klucz-wartość. To fundamentalna struktura przy indeksowaniu danych obiektów biznesowych.
Napisz funkcję `manage_clients(clients, client_id, action, name=None)`, która:
- Dla `action` równego "add": dodaje do słownika `clients` klucz `client_id` z wartością `name` i zwraca słownik.
- Dla `action` równego "remove": usuwa klucz `client_id` ze słownika i zwraca go (usuwaj bezpiecznie za pomocą `.pop()`).
Kod uzupełnij w exercises/module_2/task_2.py.
""",
"theory": """
=== Praca ze słownikami (dict) ===
Słownik to zestaw unikalnych kluczy przypisanych do wartości:
- Dodanie/modyfikacja elementu: `slownik[klucz] = wartosc`
- Bezpieczne usuwanie klucza: `slownik.pop(klucz, domyslna_wartosc)`
""",
"hint": """
Wskazówki implementacyjne:
```python
if action == "add":
clients[client_id] = name
elif action == "remove":
clients.pop(client_id, None)
return clients
```
""",
"template": """# -*- coding: utf-8 -*-
def manage_clients(clients: dict, client_id: int, action: str, name: str = None) -> dict:
\"\"\"
Dodaje lub usuwa klienta ze słownika na podstawie podanej akcji.
\"\"\"
# TWÓJ KOD TUTAJ
pass
""",
"exercise_path": "exercises/module_2/task_2.py",
"test_path": ".agents/tests/test_module_2_2.py"
},
3: {
"title": "Serializacja i Zapis do JSON",
"lesson": """
Witaj w zadaniu 2.3!
JSON to standardowy format wymiany danych biznesowych w Internecie i API.
Napisz funkcję `serialize_and_save(data, filepath)`, która serializuje słownik `data` do formatu JSON i zapisuje go w pliku o ścieżce `filepath`.
Kod uzupełnij w exercises/module_2/task_3.py.
""",
"theory": """
=== Praca z modułem json ===
Python posiada wbudowany moduł `json`:
- `json.dumps(obj)` – zamienia obiekt na ciąg znaków w formacie JSON.
- `json.dump(obj, file)` – zapisuje obiekt bezpośrednio do pliku.
Przykład zapisu do pliku:
```python
with open(filepath, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=4)
```
""",
"hint": """
Zaimportuj `json`. Użyj konstrukcji `with open(filepath, 'w')` do otwarcia pliku w trybie zapisu, a następnie wywołaj `json.dump(data, f)`.
""",
"template": """# -*- coding: utf-8 -*-
import json
def serialize_and_save(data: dict, filepath: str) -> None:
\"\"\"
Zapisuje słownik do pliku w formacie JSON.
\"\"\"
# TWÓJ KOD TUTAJ
pass
""",
"exercise_path": "exercises/module_2/task_3.py",
"test_path": ".agents/tests/test_module_2_3.py"
}
}
},
3: {
"title": "Moduł 3: Wprowadzenie do Pandas & NumPy",
"tasks": {
1: {
"title": "Analiza stóp zwrotu akcji (DataFrame & Series)",
"lesson": """
Witaj w Module 3! Pandas i NumPy to podstawowe narzędzia analityka danych.
Twoim zadaniem jest uzupełnienie funkcji analyze_stock_returns(prices_list) w exercises/module_3/task_1.py.
Funkcja powinna przyjąć listę cen zamknięcia akcji, utworzyć DataFrame, obliczyć stopy zwrotu oraz podstawowe statystyki (średnią i odchylenie standardowe prostych stóp zwrotu).
""",
"theory": """
=== Podstawy Pandas & NumPy dla Analizy Finansowej ===
1. Tworzenie DataFrame:
`df = pd.DataFrame({'price': prices})`
2. Metoda .pct_change():
Oblicza procentową zmianę wartości: `df['price'].pct_change()`
3. Logarytmowanie:
`np.log(df['price'] / df['price'].shift(1))`
4. Statystyki: `.mean()` oraz `.std()`
""",
"hint": """
Utwórz DataFrame ze słownika, wylicz pct_change() i log(), a na koniec stopy średnie i odchylenie standardowe.
""",
"template": """# -*- coding: utf-8 -*-
import pandas as pd
import numpy as np
def analyze_stock_returns(prices: list) -> tuple:
\"\"\"
Tworzy DataFrame z cenami akcji i oblicza stopy zwrotu.
\"\"\"
# TWÓJ KOD TUTAJ
pass
""",
"exercise_path": "exercises/module_3/task_1.py",
"test_path": ".agents/tests/test_module_3_1.py"
},
2: {
"title": "Fuzja danych makro- i mikroekonomicznych (Merge/Join)",
"lesson": """
Witaj w zadaniu 3.2!
Połącz dwa DataFrame'y po kolumnie 'data' z użyciem złączenia typu 'left' (zachowaj wszystkie wiersze z micro_df).
Uzupełnij kod w exercises/module_3/task_2.py.
""",
"theory": """
=== Łączenie tabel w Pandas (pd.merge) ===
Złączenie lewostronne:
`df_merged = pd.merge(df_lewy, df_prawy, on='klucz', how='left')`
""",
"hint": """
Użyj funkcji `pd.merge` z parametrami `on='data'` oraz `how='left'`.
""",
"template": """# -*- coding: utf-8 -*-
import pandas as pd
def merge_macro_micro(micro_df: pd.DataFrame, macro_df: pd.DataFrame) -> pd.DataFrame:
\"\"\"
Łączy micro_df z macro_df po kolumnie 'data' za pomocą left join.
\"\"\"
# TWÓJ KOD TUTAJ
pass
""",
"exercise_path": "exercises/module_3/task_2.py",
"test_path": ".agents/tests/test_module_3_2.py"
},
3: {
"title": "Agregacja i grupowanie portfela inwestycyjnego",
"lesson": """
Witaj w zadaniu 3.3!
Pogrupuj dane portfela inwestycyjnego po kolumnie 'sektor' i oblicz całkowitą wartość ('wartosc') jako sumę oraz średnią stopę zwrotu ('stopa_zwrotu') w każdym sektorze.
Uzupełnij kod w exercises/module_3/task_3.py.
""",
"theory": """
=== Grupowanie danych i agregacja ===
Grupowanie i agregacja w Pandas:
`df.groupby('kolumna').agg({'kolumna_A': 'sum', 'kolumna_B': 'mean'})`
""",
"hint": """
Zastosuj `.groupby('sektor').agg({'wartosc': 'sum', 'stopa_zwrotu': 'mean'})` na obiekcie DataFrame.
""",
"template": """# -*- coding: utf-8 -*-
import pandas as pd
def aggregate_portfolio(portfolio_df: pd.DataFrame) -> pd.DataFrame:
\"\"\"
Grupuje portfolio_df po 'sektor' i oblicza sumę 'wartosc' oraz średnią 'stopa_zwrotu'.
\"\"\"
# TWÓJ KOD TUTAJ
pass
""",
"exercise_path": "exercises/module_3/task_3.py",
"test_path": ".agents/tests/test_module_3_3.py"
}
}
},
4: {
"title": "Moduł 4: Zaawansowane Czyszczenie Danych (Data Wrangling)",
"tasks": {
1: {
"title": "Czyszczenie wskaźników makroekonomicznych",
"lesson": """
Witaj w Module 4!
Oczyść ramkę danych z braków (NaN), błędnych formatów tekstowych i anomalii.
Musisz wczytać CSV, wyczyścić kolumnę 'PKB_usd' (usuwając '$' i ','), zamienić -999.0 w inflacji na np.nan, uzupełnić te braki średnią, a na koniec usunąć wiersze, które posiadają braki w 'Kraj' lub 'PKB_usd'.
Kod uzupełnij w exercises/module_4/task_1.py.
""",
"theory": """
=== Czyszczenie i konwersja danych w Pandas ===
Zastępowanie symboli w napisach: `df['col'].astype(str).str.replace('$', '')`
Rzutowanie na typ numeryczny: `pd.to_numeric(df['col'], errors='coerce')`
Usuwanie pustych wierszy: `df.dropna(subset=['col1', 'col2'])`
""",
"hint": """
Wyczyść tekst, zmień typ, podmień -999.0, fillna średnią, na koniec dropna.
""",
"template": """# -*- coding: utf-8 -*-
import pandas as pd
import numpy as np
def clean_macro_data(file_path: str) -> pd.DataFrame:
\"\"\"
Wczytuje i oczyszcza dane makroekonomiczne z pliku CSV.
\"\"\"
# TWÓJ KOD TUTAJ
pass
""",
"exercise_path": "exercises/module_4/task_1.py",
"test_path": ".agents/tests/test_module_4_1.py"
},
2: {
"title": "Zaawansowana imputacja braków danych (NaN)",
"lesson": """
Witaj w zadaniu 4.2!
Uzupełnij brakujące wartości w kolumnie 'PKB' średnią wartością PKB obliczoną w ramach danej grupy 'kontynent'.
Kod uzupełnij w exercises/module_4/task_2.py.
""",
"theory": """
=== Grupowa imputacja braków ===
Używamy metody transform:
`df['PKB'] = df.groupby('kontynent')['PKB'].transform(lambda x: x.fillna(x.mean()))`
""",
"hint": """
Pogrupuj po kontynencie, pobierz PKB, wywołaj transform z wyrażeniem lambda i przypisz z powrotem.
""",
"template": """# -*- coding: utf-8 -*-
import pandas as pd
def impute_missing_gdp(df: pd.DataFrame) -> pd.DataFrame:
\"\"\"
Uzupełnia braki w kolumnie 'PKB' średnią wartością dla danego kontynentu.
\"\"\"
# TWÓJ KOD TUTAJ
pass
""",
"exercise_path": "exercises/module_4/task_2.py",
"test_path": ".agents/tests/test_module_4_2.py"
},
3: {
"title": "Detekcja anomalii (outliers) za pomocą Z-Score",
"lesson": """
Witaj w zadaniu 4.3!
Znajdź statystyczne outliers w wybranej kolumnie przy użyciu miary Z-Score. Zwróć podzbiór wierszy, dla których |Z-Score| > threshold.
Kod uzupełnij w exercises/module_4/task_3.py.
""",
"theory": """
=== Obliczanie Z-Score ===
`z = (df[column] - df[column].mean()) / df[column].std()`
Filtrowanie: `df[z.abs() > threshold]`
""",
"hint": """
Oblicz średnią i odchylenie standardowe kolumny. Wylicz z-score dla każdego wiersza i przefiltruj ramkę za pomocą metody indeksowania warunkowego.
""",
"template": """# -*- coding: utf-8 -*-
import pandas as pd
def detect_outliers_zscore(df: pd.DataFrame, column: str, threshold: float = 3.0) -> pd.DataFrame:
\"\"\"
Zwraca wiersze df stanowiące wartości odstające (outliers) w kolumnie column.
\"\"\"
# TWÓJ KOD TUTAJ
pass
""",
"exercise_path": "exercises/module_4/task_3.py",
"test_path": ".agents/tests/test_module_4_3.py"
}
}
},
5: {
"title": "Moduł 5: Szeregi Czasowe (Time Series) w Finansach",
"tasks": {
1: {
"title": "Filtrowanie i indeksowanie szeregów czasowych",
"lesson": """
Witaj w Module 5!
Praca z datami to kluczowa umiejętność każdego analityka rynkowego.
Zaimplementuj funkcję `filter_by_date(df, start_date, end_date)`. Funkcja powinna konwertować indeks lub kolumnę 'data' na typ datetime, ustawiać go jako indeks (jeśli nie jest) i zwracać przefiltrowany zakres dat od `start_date` do `end_date` (włącznie).
Kod uzupełnij w exercises/module_5/task_1.py.
""",
"theory": """
=== Praca z datami w Pandas ===
Konwersja na typ datetime: `df['data'] = pd.to_datetime(df['data'])`
Ustawienie indeksu: `df = df.set_index('data')`
Filtrowanie zakresu: `df.loc[start_date:end_date]`
""",
"hint": """
Użyj `pd.to_datetime()`, potem `set_index('data')` i wreszcie przefiltruj przy użyciu `.loc[start_date:end_date]`.
""",
"template": """# -*- coding: utf-8 -*-
import pandas as pd
def filter_by_date(df: pd.DataFrame, start_date: str, end_date: str) -> pd.DataFrame:
\"\"\"
Konwertuje kolumnę 'data' na datetime, ustawia jako indeks i filtruje przedział.
\"\"\"
# TWÓJ KOD TUTAJ
pass
""",
"exercise_path": "exercises/module_5/task_1.py",
"test_path": ".agents/tests/test_module_5_1.py"
},
2: {
"title": "Średnie kroczące w szeregach czasowych",
"lesson": """
Witaj w zadaniu 5.2!
Średnie kroczące (rolling windows) służą do wygładzania wahań i analizy trendu cen.
Napisz funkcję `calculate_rolling_mean(df, window)`, która zwróci serię (Series) zawierającą średnią kroczącą z kolumny 'price' o oknie wielkości `window`.
Kod uzupełnij w exercises/module_5/task_2.py.
""",
"theory": """
=== Metoda .rolling() w Pandas ===
Metoda `.rolling(window=N)` pozwala na agregację w oknach przesuwnych.
Przykład:
`df['price'].rolling(window=5).mean()`
Pierwsze `N-1` wartości będą miały wartość NaN.
""",
"hint": """
Pobierz kolumnę 'price', wywołaj `.rolling(window=window).mean()` i zwróć wynik.
""",
"template": """# -*- coding: utf-8 -*-
import pandas as pd
def calculate_rolling_mean(df: pd.DataFrame, window: int) -> pd.Series:
\"\"\"
Oblicza średnią kroczącą z kolumny 'price' o rozmiarze okna window.
\"\"\"
# TWÓJ KOD TUTAJ
pass
""",
"exercise_path": "exercises/module_5/task_2.py",
"test_path": ".agents/tests/test_module_5_2.py"
},
3: {
"title": "Resampling danych finansowych (Zmiana częstotliwości)",
"lesson": """
Witaj w zadaniu 5.3!
Agregacja szeregów czasowych (resampling) pozwala zmienić np. dane dzienne na dane miesięczne lub roczne.
Napisz funkcję `resample_to_monthly(df)`, która przyjmuje DataFrame z DateTimeIndex, oblicza średnie miesięczne z kolumn liczbowych i zwraca DataFrame o częstotliwości miesięcznej (indeksowany na koniec miesiąca).
Kod uzupełnij w exercises/module_5/task_3.py.
""",
"theory": """
=== Resampling w Pandas ===
Metoda `.resample()` działa podobnie do grupowania, ale po osi czasu:
`df_monthly = df.resample('ME').mean()`
Oznaczenie `'M'` (lub `'ME'`) oznacza agregację miesięczną.
""",
"hint": """
Użyj metody `.resample('ME').mean()` na wejściowej ramce danych.
""",
"template": """# -*- coding: utf-8 -*-
import pandas as pd
def resample_to_monthly(df: pd.DataFrame) -> pd.DataFrame:
\"\"\"
Agreguje dzienne dane w DataFrame do średnich miesięcznych.
\"\"\"
# TWÓJ KOD TUTAJ
pass
""",
"exercise_path": "exercises/module_5/task_3.py",
"test_path": ".agents/tests/test_module_5_3.py"
}
}
},
6: {
"title": "Moduł 6: Praca z Relacyjnymi Bazami Danych (SQL & SQLite)",
"tasks": {
1: {
"title": "Odczyt danych z SQLite bezpośrednio do Pandas",
"lesson": """
Witaj w Module 6!
Większość danych firmowych znajduje się w relacyjnych bazach danych (SQL).
Napisz funkcję `read_sql_data(db_path, query)`, która łączy się z bazą danych SQLite w lokalizacji `db_path`, wykonuje zapytanie `query` i zwraca wynik jako Pandas DataFrame. Pamiętaj o zamknięciu połączenia z bazą!
Kod uzupełnij w exercises/module_6/task_1.py.
""",
"theory": """
=== Odczyt baz danych w Pandas ===
Biblioteka `sqlite3` obsługuje bazy SQLite w Pythonie.
Pandas pozwala odczytać zapytanie bezpośrednio do DataFrame:
```python
import sqlite3
import pandas as pd
conn = sqlite3.connect(db_path)
df = pd.read_sql_query(query, conn)
conn.close()
```
""",
"hint": """
Zaimportuj `sqlite3` oraz `pandas`. Utwórz połączenie za pomocą `sqlite3.connect()`, odczytaj dane za pomocą `pd.read_sql_query()`, zamknij połączenie i zwróć ramkę.
""",
"template": """# -*- coding: utf-8 -*-
import pandas as pd
import sqlite3
def read_sql_data(db_path: str, query: str) -> pd.DataFrame:
\"\"\"
Łączy się z SQLite w db_path, pobiera dane zapytaniem query i zwraca DataFrame.
\"\"\"
# TWÓJ KOD TUTAJ
pass
""",
"exercise_path": "exercises/module_6/task_1.py",
"test_path": ".agents/tests/test_module_6_1.py"
},
2: {
"title": "Eksportowanie danych z Pandas do bazy SQL",
"lesson": """
Witaj w zadaniu 6.2!
Zapisywanie przetworzonych danych do bazy SQL to standardowy krok w procesach ETL.
Napisz funkcję `write_to_sql(df, db_path, table_name)`. Funkcja powinna zapisać DataFrame do tabeli o nazwie `table_name` w bazie danych SQLite pod ścieżką `db_path`. Jeśli tabela istnieje, ma zostać nadpisana. Nie zapisuj indeksu DataFrame.
Kod uzupełnij w exercises/module_6/task_2.py.
""",
"theory": """
=== Zapis do SQL w Pandas ===
Do eksportu służy metoda `.to_sql()`:
`df.to_sql(table_name, conn, if_exists='replace', index=False)`
Parametr `if_exists='replace'` nadpisuje tabelę w bazie danych.
""",
"hint": """
Połącz się z bazą przez `sqlite3.connect()`, wywołaj `df.to_sql(table_name, conn, if_exists='replace', index=False)`, a na koniec zamknij połączenie.
""",
"template": """# -*- coding: utf-8 -*-
import pandas as pd
import sqlite3
def write_to_sql(df: pd.DataFrame, db_path: str, table_name: str) -> None:
\"\"\"
Zapisuje DataFrame do tabeli table_name w bazie danych SQLite.
\"\"\"
# TWÓJ KOD TUTAJ
pass
""",
"exercise_path": "exercises/module_6/task_2.py",
"test_path": ".agents/tests/test_module_6_2.py"
},
3: {
"title": "Raport sprzedaży bezpośrednio z bazy danych SQL",
"lesson": """
Witaj w zadaniu 6.3!
Czasami wydajniej jest agregować dane po stronie silnika SQL zamiast pobierać całą bazę do pamięci Pythona.
Napisz funkcję `get_total_sales_by_product(db_path)`, która łączy się z bazą danych i wykonuje zapytanie SQL sumujące przychody:
`SELECT product, SUM(quantity * price) AS total_sales FROM sales GROUP BY product`
Funkcja ma zwrócić wynik jako listę krotek (wyniki zapytania `cursor.fetchall()`).
Kod uzupełnij w exercises/module_6/task_3.py.
""",
"theory": """
=== Agregacje i Kursory SQL w Pythonie ===
Bez używania Pandas możemy operować bezpośrednio kursorami `sqlite3`:
```python
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
cursor.execute(query)
results = cursor.fetchall() # Zwraca listę krotek
conn.close()
```
""",
"hint": """
Utwórz kursor z połączenia, wykonaj zapytanie SELECT z sumowaniem i grupuj po produkcie, pobierz wyniki za pomocą fetchall(), zamknij bazę i zwróć listę.
""",
"template": """# -*- coding: utf-8 -*-
import sqlite3
def get_total_sales_by_product(db_path: str) -> list:
\"\"\"
Wykonuje zapytanie SQL grupujące i sumujące sprzedaż i zwraca listę krotek.
\"\"\"
# TWÓJ KOD TUTAJ
pass
""",
"exercise_path": "exercises/module_6/task_3.py",
"test_path": ".agents/tests/test_module_6_3.py"
}
}
},
7: {
"title": "Moduł 7: Analiza Statystyczna & Ekonometria (Statsmodels/Scipy)",
"tasks": {
1: {
"title": "Obliczanie macierzy korelacji zmiennych",
"lesson": """
Witaj w Module 7!
Analiza korelacji pozwala sprawdzić, jak silnie powiązane są ze sobą wskaźniki (np. bezrobocie i inflacja).
Napisz funkcję `get_correlations(df)`, która obliczy i zwróci macierz korelacji Pearsona dla wszystkich kolumn liczbowych w DataFrame.
Kod uzupełnij w exercises/module_7/task_1.py.
""",
"theory": """
=== Korelacja w Pandas ===
Metoda `.corr()` w Pandas automatycznie wylicza współczynniki korelacji liniowej:
`correlation_matrix = df.corr(method='pearson')`
Wartości mieszczą się w przedziale [-1, 1].
""",
"hint": """
Po prostu wywołaj `df.corr(method='pearson')` i zwróć tę macierz.
""",
"template": """# -*- coding: utf-8 -*-
import pandas as pd
def get_correlations(df: pd.DataFrame) -> pd.DataFrame:
\"\"\"
Zwraca macierz korelacji Pearsona dla kolumn numerycznych.
\"\"\"
# TWÓJ KOD TUTAJ
pass
""",
"exercise_path": "exercises/module_7/task_1.py",
"test_path": ".agents/tests/test_module_7_1.py"
},
2: {
"title": "Regresja liniowa OLS (Dopasowanie modelu)",
"lesson": """
Witaj w zadaniu 7.2!
Regresja liniowa (Metoda Najmniejszych Kwadratów - OLS) to podstawowe narzędzie ekonometryczne do badania przyczynowo-skutkowego.
Napisz funkcję `run_regression(df, y_col, x_col)`, która dopasuje model OLS, gdzie `y_col` to zmienna objaśniana (np. 'popyt'), a `x_col` to zmienna objaśniająca (np. 'cena'). Dodaj stałą (wyraz wolny) do zmiennej objaśniającej. Funkcja powinna zwracać krotkę `(rsquared, pvalues)` z dopasowanego modelu.
Kod uzupełnij w exercises/module_7/task_2.py.
""",
"theory": """
=== Modelowanie OLS w statsmodels ===
Biblioteka `statsmodels` udostępnia zaawansowaną statystykę:
```python
import statsmodels.api as sm
# Musimy dodać stałą (wyraz wolny) do X
X = sm.add_constant(df[x_col])
y = df[y_col]
model = sm.OLS(y, X).fit()
r2 = model.rsquared
p_vals = model.pvalues # Seria p-value dla stałej i zmiennej X
```
""",
"hint": """
Użyj `sm.add_constant()` na zmiennej niezależnej, zbuduj model `sm.OLS(y, X)`, wywołaj `.fit()` i zwróć `(model.rsquared, model.pvalues)`.
""",
"template": """# -*- coding: utf-8 -*-
import pandas as pd
import statsmodels.api as sm
def run_regression(df: pd.DataFrame, y_col: str, x_col: str) -> tuple:
\"\"\"
Dopasowuje model regresji liniowej OLS i zwraca (R-squared, p-values).
\"\"\"
# TWÓJ KOD TUTAJ
pass
""",
"exercise_path": "exercises/module_7/task_2.py",
"test_path": ".agents/tests/test_module_7_2.py"
},
3: {
"title": "Test t-Studenta dla dwóch prób niezależnych",
"lesson": """
Witaj w zadaniu 7.3!
Test t-Studenta służy do weryfikacji hipotezy, czy średnie w dwóch grupach są statystycznie równe (np. czy nowa strategia marketingowa zwiększyła sprzedaż).
Napisz funkcję `run_t_test(sample1, sample2)`, która przeprowadzi dwustronny test t-Studenta dla dwóch prób niezależnych i zwróci statystykę t oraz wartość p (p-value) jako krotkę `(t_stat, p_value)`.
Kod uzupełnij w exercises/module_7/task_3.py.
""",
"theory": """
=== Testy statystyczne w scipy ===
Moduł `scipy.stats` zawiera implementacje testów:
```python
from scipy import stats
t_stat, p_value = stats.ttest_ind(sample1, sample2)
```
""",
"hint": """
Użyj funkcji `stats.ttest_ind(sample1, sample2)` i zwróć jej wynik.
""",
"template": """# -*- coding: utf-8 -*-
from scipy import stats
def run_t_test(sample1: list, sample2: list) -> tuple:
\"\"\"
Przeprowadza test t-Studenta dla dwóch prób niezależnych i zwraca (t_stat, p_value).
\"\"\"
# TWÓJ KOD TUTAJ
pass
""",
"exercise_path": "exercises/module_7/task_3.py",
"test_path": ".agents/tests/test_module_7_3.py"
},
4: {
"title": "Gęstość i całkowanie numeryczne (SciPy)",
"lesson": """
Witaj w zadaniu 7.4!
Zaimplementuj dwie funkcje:
1. `get_normal_pdf(z)` - zwraca wartość gęstości prawdopodobieństwa standardowego rozkładu normalnego dla punktu `z`.
2. `integrate_normal_density(a, b)` - oblicza i zwraca wartość całki oznaczonej (prawdopodobieństwa) z gęstości standardowego rozkładu normalnego w przedziale od `a` do `b`.
Użyj do tego biblioteki SciPy (`scipy.stats.norm` oraz `scipy.integrate.quad`).
Kod uzupełnij w exercises/module_7/task_4.py.
""",
"theory": """
=== SciPy: Statystyka i Całkowanie ===
Funkcja gęstości rozkładu normalnego (PDF): `scipy.stats.norm.pdf(z)`
Całkowanie numeryczne (quad):
`result, error = scipy.integrate.quad(func, a, b)`
Gdzie `func` to całkowana funkcja.
""",
"hint": "Użyj scipy.stats.norm.pdf w obu funkcjach. W integrate_normal_density przekaż tę funkcję do quad i zwróć tylko pierwszy element wyniku (całkę).",
"template": """# -*- coding: utf-8 -*-
from scipy.stats import norm
from scipy.integrate import quad
def get_normal_pdf(z: float) -> float:
\"\"\"
Zwraca wartość gęstości prawdopodobieństwa standardowego rozkładu normalnego dla z.
\"\"\"
# TWÓJ KOD TUTAJ
pass
def integrate_normal_density(a: float, b: float) -> float:
\"\"\"
Oblicza całkę z gęstości standardowego rozkładu normalnego od a do b.
\"\"\"
# TWÓJ KOD TUTAJ
pass
""",
"exercise_path": "exercises/module_7/task_4.py",
"test_path": ".agents/tests/test_module_7_4.py"
}
}
},
8: {
"title": "Moduł 8: Automatyzacja & Integracja AI (Swarm)",
"tasks": {
1: {
"title": "Cykliczne sprawdzanie i logowanie danych (Scheduler)",
"lesson": """
Witaj w Module 8!
Zaimplementuj prosty harmonogram zadań w Pythonie.
Funkcja `schedule_data_check(check_func, interval_sec, max_iterations)` powinna cyklicznie wywoływać przekazaną funkcję `check_func` co określony czas (`interval_sec`), maksymalnie `max_iterations` razy, i zwracać listę z wynikami tych uruchomień.
Kod uzupełnij w exercises/module_8/task_1.py.
""",
"theory": """
=== Harmonogram z time.sleep ===
`time.sleep(seconds)` zawiesza działanie wątku na podany czas.
""",
"hint": """
W pętli for wywołaj check_func(), dodaj wynik do listy, a jeśli to nie jest ostatnia iteracja – wywołaj `time.sleep(interval_sec)`.
""",
"template": """# -*- coding: utf-8 -*-
import time
def schedule_data_check(check_func, interval_sec: int, max_iterations: int) -> list:
\"\"\"
Cyklicznie wywołuje check_func co interval_sec, max_iterations razy.
Zwraca listę wyników.
\"\"\"
# TWÓJ KOD TUTAJ
pass
""",
"exercise_path": "exercises/module_8/task_1.py",
"test_path": ".agents/tests/test_module_8_1.py"
},
2: {
"title": "Delegowanie zadań do wyspecjalizowanych subagentów",
"lesson": """
Witaj w zadaniu 8.2!
Zaimplementuj prosty router żądań w architekturze wieloagentowej. Funkcja `delegate_to_subagent(user_request)` analizuje tekst:
- Jeśli żądanie zawiera słowa 'statystyka' lub 'analiza': zwraca "Delegowano do: Agent Statystyczny".
- Jeśli żądanie zawiera słowa 'wykres' lub 'wizualizacja': zwraca "Delegowano do: Agent Wizualizacji".
- W pozostałych przypadkach: zwraca "Delegowano do: General Agent".
Kod uzupełnij w exercises/module_8/task_2.py.
""",
"theory": """
=== Rutowanie intencji ===
Używamy `.lower()` oraz dopasowania cząstkowego w tekście (operator `in`).
""",
"hint": """
Sprawdź obecność "statyst" lub "analiz", a także "wykres" lub "wizualiz".
""",
"template": """# -*- coding: utf-8 -*-
def delegate_to_subagent(user_request: str) -> str:
\"\"\"
Kieruje żądanie user_request do odpowiedniego agenta pomocniczego.
\"\"\"
# TWÓJ KOD TUTAJ
pass
""",
"exercise_path": "exercises/module_8/task_2.py",
"test_path": ".agents/tests/test_module_8_2.py"
},
3: {
"title": "Automatyczny Report Builder",
"lesson": """
Witaj w zadaniu 8.3!
Ostatnim krokiem analizy jest sformułowanie i zapisanie raportu końcowego do pliku.
Napisz funkcję `build_economic_report(data_summary, filepath)`. Funkcja powinna utworzyć tekstowy raport na podstawie słownika `data_summary` i zapisać go w pliku `filepath`.
Słownik `data_summary` zawiera klucze: 'tytul', 'autor', 'wynik'.
Plik powinien mieć format dokładnie taki:
Raport: <tytul>
Autor: <autor>
Wynik: <wynik>
Kod uzupełnij w exercises/module_8/task_3.py.
""",
"theory": """
=== Zapis tekstowy i szablony ===
Zapis pliku w Pythonie:
```python
with open(filepath, 'w', encoding='utf-8') as f:
f.write(report_string)
```
""",
"hint": """
Sformatuj ciąg znaków pobierając wartości ze słownika:
`report = f"Raport: {data_summary['tytul']}\\nAutor: {data_summary['autor']}\\nWynik: {data_summary['wynik']}"`
Zapisz go do pliku `filepath`.
""",
"template": """# -*- coding: utf-8 -*-
def build_economic_report(data_summary: dict, filepath: str) -> None:
\"\"\"
Tworzy sformatowany raport tekstowy na podstawie data_summary i zapisuje go w pliku.
\"\"\"
# TWÓJ KOD TUTAJ
pass
""",
"exercise_path": "exercises/module_8/task_3.py",
"test_path": ".agents/tests/test_module_8_3.py"
}
}
},
9: {
"title": "Moduł 9: Zaawansowane APIs i Jakość Danych w Ekonomii",
"tasks": {
1: {
"title": "Integracja z API DBnomics",
"lesson": """
Witaj w zadaniu 9.1!
Twoim zadaniem jest pobranie serii czasowej bezpośrednio z oficjalnego Web API platformy DBnomics.
DBnomics to otwarta platforma agregująca miliony szeregów czasowych, z której korzystają instytucje takie jak OECD czy Banque de France.
Napisz funkcję `get_dbnomics_series(series_id)`.
Funkcja powinna wysłać zapytanie GET pod adres API DBnomics:
`https://api.dbnomics.world/v22/series/{series_id}?format=json`
i wyekstrahować dane z pobranego JSON-a.
Zwróć listę słowników, gdzie każdy słownik ma klucze `period` (str) oraz `value` (float lub None).
Zgodnie z "non-opinionated" filozofią DBnomics, jeśli wartość `value` w JSON wynosi `"NA"` lub jest pusta/None, zachowaj ją jako `None` (nie interpoluj brakujących danych!).
W przypadku błędu połączenia lub braku serii, zwróć pustą listę `[]`.
Kod uzupełnij w exercises/module_9/task_1.py.
""",
"theory": """
=== DBnomics Web API ===
API DBnomics zwraca dane w formacie JSON. Struktura odpowiedzi dla serii czasowej zawiera:
`data['series']['docs']` - lista słowników, z których każdy reprezentuje pojedynczą obserwację.
Każda obserwacja zawiera klucz `period` (np. "2023-01") oraz `value` (która może być float, None lub napisem "NA").