Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

180 minut | poziom podstawowy | Python/Jupyter | praca w parach

Tym razem jesteśmy analitykami opinii publicznej! Wykorzystamy autentyczną ankietę CBOS z grudnia 2017 roku (Aktualne problemy i wydarzenia, nr 331; 925 respondentów), ankietę StudentSurvey (do testów średnich i rang) oraz historyczne dane Student’s Sleep (próby sparowane).

A pisze kod, B pilnuje hipotez, założeń i interpretacji. Po każdym zadaniu zamieniacie się rolami. Pola None to miejsca do samodzielnego uzupełnienia; wskazówki otwierają się po kliknięciu.

Źródła danych: student_survey_lock5.csv, sleep_paired.csv oraz CBOS SPSS; dokumentacja CBOS znajduje się w repozytorium. Linki do surowych plików pozwalają korzystać z danych także po pobraniu samego notebooka — bez ręcznego pobierania.

Pakiety: numpy, pandas, matplotlib, scipy, statsmodels, pyreadstat, ipywidgets. Jeśli czegoś brakuje, uruchom w oddzielnej komórce Jupyter: %pip install pyreadstat statsmodels ipywidgets.

Rozkład czasu: 0–45 jedna średnia i testy kierunkowe; 45–60 CBOS: jedna proporcja; 60–70 przerwa; 70–105 niezależne średnie / rangi; 105–135 próby sparowane; 135–155 CBOS: zależności; 155–170 KDE; 170–180 podsumowanie.

Ankieta: 362 odpowiedzi; sleep: 10 par
Collecting pyreadstat
  Downloading pyreadstat-1.3.7-cp313-cp313-macosx_11_0_arm64.whl.metadata (1.2 kB)
Requirement already satisfied: narwhals>=2.10.1 in /opt/miniconda3/lib/python3.13/site-packages (from pyreadstat) (2.27.1)
Requirement already satisfied: numpy in /opt/miniconda3/lib/python3.13/site-packages (from pyreadstat) (2.5.2)
Downloading pyreadstat-1.3.7-cp313-cp313-macosx_11_0_arm64.whl (804 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 804.8/804.8 kB 16.1 MB/s eta 0:00:00
Installing collected packages: pyreadstat
Successfully installed pyreadstat-1.3.7
Note: you may need to restart the kernel to use updated packages.

Nowy zbiór: CBOS bez ręcznego pobierania

Wczytamy plik .sav z GitHuba oraz etykiety pytań z SPSS. W razie kłopotów z modułem odczytu, zainstaluj go komendą %pip install pyreadstat w osobnej komórce i ponownie uruchom poniższą.

CBOS: 925 respondentów, 189 zmiennych
— q24 — 1. Czy, ogólnie rzecz biorąc, sytuacja w naszym kraju zmierza w dobrym czy też w złym kierunku?
{1.0: 'W dobrym', 2.0: 'W złym', 7.0: 'Trudno powiedzieć', 8.0: 'Odmowa odpowiedzi'}
— q25 — 2. A jak Pan(i) sądzi, czy w ciągu najbliższego roku sytuacja w Polsce poprawi się, pogorszy czy też się nie zmieni?
{1.0: 'Zdecydowanie poprawi się', 2.0: 'Raczej poprawi się', 3.0: 'Nie zmieni się', 4.0: 'Raczej pogorszy się', 5.0: 'Zdecydowanie pogorszy się', 7.0: 'Trudno powiedzieć', 8.0: 'Odmowa odpowiedzi'}
— plec — Płeć respondenta
{1.0: 'Mężczyzna', 2.0: 'Kobieta'}

0–45 min. Case study A: jedna średnia

W ankiecie Exercise oznacza deklarowaną liczbę godzin aktywności fizycznej na tydzień.

Pytanie: czy przeciętnie jest to 8,5 godziny tygodniowo? Próg 8,5 godziny to wartość dydaktyczna, nie oficjalna rekomendacja.

H₀: μ = 8,5. Najpierw zapisz H₁, dopiero potem patrz na wyniki.

n = 361 średnia = 9.05 odchylenie = 5.74
<Figure size 800x370 with 1 Axes>

Zadanie 1. Test t dla jednej średniej — DWUSTRONNY

H₁: μ ≠ 8,5. Zastosuj funkcję dla jednej próby.

Założenia: niezależni respondenci; pomiar ilościowy; przy mniejszej próbie w przybliżeniu normalny rozkład i brak bardzo silnych odstających. Przy n≈361 test t bywa odporny na umiarkowaną nienormalność, ale warto ocenić obserwacje odstające.

TtestResult(statistic=np.float64(1.8336163648790507), pvalue=np.float64(0.03376819130590094), df=np.int64(360))
Błąd standardowy średniej = 0.302
💡 Podpowiedź 1: funkcja

stats.ttest_1samp()

🔎 Podpowiedź 2: argumenty

stats.ttest_1samp(exercise, popmean=8.5, alternative=“two-sided”)

Zadanie 2. Test JEDNOSTRONNY — prawostronny

Gdy przed obejrzeniem danych zakładamy kierunek dodatni, H₁: μ > 8,5. Przy H₁: μ < 8,5 otrzymalibyśmy test lewostronny.

W testach jednostronnych nie dzielimy mechanicznie każdego p przez dwa. Kierunek statystyki musi być zgodny z H₁.

Uzupełnij test_right
💡 Podpowiedź 1: funkcja

stats.ttest_1samp()

🔎 Podpowiedź 2: argumenty

Podaj alternative=“greater”. Dla H₁: μ < 8,5 użyłbyś alternative=“less”.

(np.float64(-4.776084989332397), np.float64(8.937043693949779e-07))

Interaktywny eksperyment: jeden ogon czy dwa?

Poniższy kod rysuje dokładnie te same dane i tę samą statystykę t, ale inaczej definiuje obszar p-value. Przed uruchomieniem przewidź, czy wnioski przy α = 0,05 będą identyczne.

Loading...

W parach: zapisz obie hipotezy H₁ i obydwa p-value. Czy wolno wybrać test prawostronny dopiero po tym, jak test dwustronny okazał się nieistotny? Dlaczego nie?

45–60 min. Case study B — CBOS: czy Polacy byli optymistami?

W grudniu 2017 r. CBOS zapytał: „Czy, ogólnie rzecz biorąc, sytuacja w naszym kraju zmierza w dobrym czy też w złym kierunku?” (q24).

Najpierw obejrzyj odpowiedzi. Nie licz „trudno powiedzieć” jako „nie” — to osobna kategoria! W ćwiczeniu rozważamy wyłącznie osoby, które wskazały jednoznacznie „dobry” lub „zły” kierunek.

Zadanie 3 (para): sprawdź, czy udział opinii „w dobrym kierunku” różnił się od 50% (wartość odniesienia jest dydaktyczna, nie historyczna). Sformułuj H₀ i H₁. Dlaczego test powinien być dwustronny, jeśli wcześniej nie określiliśmy kierunku?

Liczebności surowych odpowiedzi:
q24
1.0    432
2.0    345
7.0    145
8.0      3
Name: count, dtype: int64
Ważne odpowiedzi: 777 | „dobry”: 432 | udział: 0.556
Uzupełnij wywołanie testu.
💡 Podpowiedź 1: gotowa funkcja

Użyj proportions_ztest() z statsmodels.stats.proportion.

🔎 Podpowiedź 2: argumenty

Potrzebujesz: count=k_dobry, nobs=n_opinie, value=0.5, alternative='two-sided'. Aby użyć wariancji z hipotezy zerowej, dodaj prop_var=0.5.

Pytanie do dyskusji: co stałoby się z oszacowaniem odsetka, gdyby odpowiedzi „trudno powiedzieć” omyłkowo włączyć do mianownika?

Interpretacja i ograniczenia: wynik opisuje grudzień 2017 r., nie dzisiejsze nastroje. Przybliżenie normalne w prostym teście Z wymaga dostatecznych liczności i niezależnych obserwacji; CBOS ma również wagi ankietowe (WAGA, wagaDUZA) i własny schemat doboru. Nasz nieważony test jest ćwiczeniem metody, nie odtworzeniem oficjalnego wnioskowania CBOS.

W parach: zapisz jednym zdaniem, czym jest p-value i czego na pewno nie oznacza. Czy z istotności statystycznej wynika automatycznie duże znaczenie społeczne?

60–70 min. Przerwa

70–105 min. Case study C: dwie niezależne średnie

Porównamy tygodniowy czas oglądania TV przez kobiety (F) i mężczyzn (M). Są to dwa rozłączne zbiory respondentów.

<Figure size 800x370 with 1 Axes>
n: 169 192 średnie: 5.236686390532545 7.619791666666667

Zadanie 3. Welch

H₀: μF = μM; H₁: μF ≠ μM. Test Welcha nie wymaga równości wariancji.

Założenia: niezależność osób, dane ilościowe, brak silnych obserwacji wpływowych; w małych próbach także przybliżona normalność. Czy dane TV są prawoskośne?

Uzupełnij result_welch
💡 Podpowiedź 1: funkcja

stats.ttest_ind()

🔎 Podpowiedź 2: argumenty

stats.ttest_ind(tv_f, tv_m, equal_var=False) — Welch.

Diagnostyka i alternatywa

Nie traktuj Shapiro jako automatycznej bramki. Niezależność pochodzi z projektu badania. Mann–Whitney jest zamiennikiem badającym inne aspekty rozkładów, nie zawsze same mediany.

Shapiro F: ShapiroResult(statistic=np.float64(0.8316548109545009), pvalue=np.float64(1.1080814246073763e-12))
Shapiro M: ShapiroResult(statistic=np.float64(0.8427904665842125), pvalue=np.float64(3.95506403534183e-13))
Levene: LeveneResult(statistic=np.float64(12.681801445178488), pvalue=np.float64(0.000418966330848194))
<Figure size 900x350 with 2 Axes>

Zadanie 4. Mann–Whitney: porównanie rozkładów

Uzupełnij result_mw
💡 Podpowiedź 1: funkcja

stats.mannwhitneyu()

🔎 Podpowiedź 2: argumenty

stats.mannwhitneyu(tv_f, tv_m, alternative=“two-sided”)

105–135 min. Case study D: dwie obserwacje tej samej osoby

Historyczny Student’s Sleep: dodatkowe godziny snu pod wpływem leku 1 i leku 2. Jedna linia na wykresie to ta sama osoba — dane sparowane.

<Figure size 800x370 with 1 Axes>
Średnia różnica lek 2 - lek 1: 1.58
Shapiro różnic: ShapiroResult(statistic=np.float64(0.8298713319287947), pvalue=np.float64(0.0333416086303077))

Zadanie 5. Test t dla par

H₀: średnia różnica D=drug2−drug1 wynosi 0.

Założenia: poprawne parowanie, niezależność par, przy małym n w przybliżeniu normalny rozkład RÓŻNIC. Nie wymagamy normalności obu kolumn osobno.

Uzupełnij result_paired
💡 Podpowiedź 1: funkcja

stats.ttest_rel()

🔎 Podpowiedź 2: argumenty

stats.ttest_rel(drug2, drug1)

Zadanie 6. Wilcoxon

Alternatywa oparta na rangach |D| i ich znakach. Typowa interpretacja centrum różnic wymaga ich symetrii; uwaga na zera i remisy.

Uzupełnij result_wilcoxon
💡 Podpowiedź 1: funkcja

stats.wilcoxon()

🔎 Podpowiedź 2: argumenty

stats.wilcoxon(diff)

135–155 min. Case study E — CBOS: czy kobiety i mężczyźni oceniali przyszłość inaczej?

Pytanie q25: „Czy w ciągu najbliższego roku sytuacja w Polsce poprawi się, pogorszy czy też się nie zmieni?” (zadane w grudniu 2017 r.).

Kodujemy trzy rozłączne kategorie: poprawa (1/2), bez zmian (3), pogorszenie (4/5). Odpowiedzi 7/8 (nie wiem/odmowa) usuwamy. Następnie porównujemy odpowiedzi według płci (plec: 1 – mężczyzna, 2 – kobieta).

Wasze wyzwanie: najpierw obejrzyjcie wykres procentowy. Czy wizualna różnica jest wystarczającą podstawą do stwierdzenia zależności?

Liczności:
Loading...
<Figure size 850x320 with 1 Axes>

Zadanie 7. Test niezależności χ²

H₀: płeć i kategoria prognozy są niezależne. H₁: występuje zależność.

  1. Użyj jednej gotowej funkcji scipy.stats do przetestowania niezależności.

  2. Sprawdź najmniejszą liczność oczekiwaną.

  3. Oceń wielkość efektu — V Craméra (wzór i podpowiedź poniżej).

  4. Napisz, dlaczego istotna zależność nie oznacza, że płeć powoduje określoną odpowiedź.

Chi2ContingencyResult(statistic=np.float64(6.214420257543603), pvalue=np.float64(0.0441), dof=nan, expected_freq=array([[204.81955763, 108.33876601, 149.84167637], [175.18044237, 92.66123399, 128.15832363]]))
💡 Podpowiedź 1: gotowy test

stats.chi2_contingency() z argumentem tab_cbos.

🔎 Podpowiedź 2: co oznacza V Craméra?

(V=\sqrt{\chi^2/(N\min(r-1,c-1))}). W przedziale 0–1: 0 oznacza brak związku; duże wartości oznaczają silniejszy związek. Porównuj wartość także z kontekstem badania.

🧭 A co z testem dwóch proporcji?

Gdy uprościsz zmienną q25 do dwóch kategorii (poprawa versus pozostałe ważne odpowiedzi), porównaj odsetki kobiet i mężczyzn za pomocą proportions_ztest(count=[...,...], nobs=[...,...]). Nie używaj tej samej funkcji do pełnej tabeli 2×3!

155–170 min. Case study F: KDE

Jądrowa estymacja gęstości opisuje kształt rozkładu godzin TV. Nie jest testem hipotez. Bandwidth decyduje o poziomie wygładzania.

<Figure size 800x380 with 1 Axes>

Zadanie 8. Narysuj na jednej osi dwa KDE dla F i M. Zastosuj identyczną regułę wyboru pasma.

Uzupełnij obie funkcje
💡 Podpowiedź 1: funkcja

stats.gaussian_kde()

🔎 Podpowiedź 2: argumenty

stats.gaussian_kde(tv_f, bw_method=“scott”) i osobno dla tv_m.

170–180 min. Zakończenie

W parach uzupełnijcie krótką tabelę: pytanie, hipotezy H₀/H₁, test, założenie, zamiennik, wynik i ograniczenie.

Najważniejsze pytanie: kiedy i dlaczego wolno użyć testu jednostronnego?

ANOVA zostaje na kolejny blok.