Test chi-kwadrat niezależności
Sprawdź, czy dwie zmienne kategorialne są niezależne, używając chi2_contingency na tabeli częstości utworzonej za pomocą crosstab.
Test chi-kwadrat niezależności to bezpłatna lekcja Pandas & NumPy Academy na CoddyKit. To lekcja 3 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Pandas & NumPy Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Pandas & NumPy Academy zawiera 4 lekcji w sumie.
Badanie zależności między zmiennymi kategorialnymi
Test niezależności chi-kwadrat sprawdza, czy dwie zmienne kategorialne są statystycznie niezależne, czy też występuje między nimi zależność. Na przykład: „Czy rezygnacja klienta z usługi jest niezależna od poziomu subskrypcji?” albo „Czy preferencje dotyczące produktu są niezależne od grupy wiekowej?”. W przeciwieństwie do testów t, które porównują średnie liczbowe, testy chi-kwadrat porównują zaobserwowane liczebności w tabeli kontyngencji z liczebnościami, których oczekiwalibyśmy, gdyby zmienne były niezależne.
Tworzenie tabeli kontyngencji za pomocą Pandas
Tabela kontyngencji (nazywana także tabelą krzyżową) przedstawia liczbę obserwacji dla każdej kombinacji dwóch zmiennych kategorialnych. pd.crosstab(df['var1'], df['var2']) tworzy tę tabelę bezpośrednio z obiektu DataFrame. Każda komórka zawiera liczbę obserwacji, w których kategoria wiersza i kategoria kolumny występują jednocześnie. Jest to dane wejściowe dla scipy.stats.chi2_contingency().
import pandas as pd
import numpy as np
np.random.seed(0)
df = pd.DataFrame({
'subscription': np.random.choice(['free', 'basic', 'pro'], 300),
'churned': np.random.choice(['yes', 'no'], 300, p=[0.3, 0.7])
})
# Build contingency table
ct = pd.crosstab(df['subscription'], df['churned'])
print(ct)
print()
print('Row totals:', ct.sum(axis=1).to_dict())Uruchamianie chi2_contingency()
scipy.stats.chi2_contingency(observed) przyjmuje zaobserwowaną tabelę kontyngencji (jako tablicę NumPy lub obiekt Pandas DataFrame) i zwraca cztery wartości: statystykę chi-kwadrat, wartość p, liczbę stopni swobody oraz tabelę oczekiwanych liczebności. Hipoteza zerowa ma postać H₀: the two variables are independent. Jeśli p ≤ 0.05, odrzucamy niezależność i stwierdzamy, że występuje statystycznie istotna zależność.
import pandas as pd
import numpy as np
from scipy import stats
np.random.seed(0)
df = pd.DataFrame({
'tier': np.random.choice(['free', 'basic', 'pro'], 300),
'churned': np.random.choice(['yes', 'no'], 300, p=[0.3, 0.7])
})
ct = pd.crosstab(df['tier'], df['churned'])
chi2, p, dof, expected = stats.chi2_contingency(ct)
print(f'Chi-squared: {chi2:.3f}')
print(f'p-value: {p:.4f}')
print(f'Degrees of freedom: {dof}')
print('Association significant?', 'Yes' if p < 0.05 else 'No')Zrozumienie oczekiwanych liczebności
Oczekiwane liczebności przedstawiają to, jak wyglądałyby liczebności w komórkach, gdyby obie zmienne były całkowicie niezależne. Dla każdej komórki expected = (row_total × column_total) / grand_total. Statystyka chi-kwadrat mierzy sumę kwadratów różnic między liczebnościami zaobserwowanymi i oczekiwanymi, znormalizowaną przez liczebności oczekiwane. Duża wartość chi-kwadrat oznacza silne odchylenie zaobserwowanych liczebności od niezależności, a mała oznacza, że dane są zgodne z niezależnością.
import pandas as pd
import numpy as np
from scipy import stats
observed = pd.DataFrame({
'converted': [50, 30],
'not_converted': [150, 170]
}, index=['variant', 'control'])
chi2, p, dof, expected = stats.chi2_contingency(observed)
print('Observed:')
print(observed)
print()
print('Expected (under independence):')
print(pd.DataFrame(expected,
index=observed.index,
columns=observed.columns).round(1))Stopnie swobody w teście chi-kwadrat
Dla tabeli kontyngencji z r wierszami i c kolumnami liczba stopni swobody wynosi df = (r-1) × (c-1). Tabela 2×2 ma df=1, a tabela 3×4 ma df=6. Wartość krytyczna rozkładu chi-kwadrat rośnie wraz z liczbą stopni swobody: dla df=1 przy α=0.05 wartość krytyczna wynosi około 3.84, a dla df=6 przy α=0.05 około 12.6. Funkcja chi2_contingency obsługuje to automatycznie, ale znajomość wzoru pomaga zrozumieć, dlaczego w przypadku większych tabel uzyskanie istotności wymaga większych wartości statystyki chi-kwadrat.
from scipy import stats
# Critical values of chi-squared for alpha=0.05
for df in [1, 2, 3, 4, 6, 9]:
critical = stats.chi2.ppf(0.95, df=df)
print(f'df={df}: critical value = {critical:.3f}')Założenie minimalnej oczekiwanej liczebności
Test chi-kwadrat jest wiarygodny tylko wtedy, gdy wszystkie oczekiwane liczebności wynoszą co najmniej 5 (niektóre źródła dopuszczają co najmniej 1, o ile nie więcej niż 20% wartości jest mniejszych od 5). Małe oczekiwane liczebności sprawiają, że przybliżenie chi-kwadrat jest niedokładne. Gdy to założenie nie jest spełnione, w przypadku tabel 2×2 należy użyć dokładnego testu Fishera (scipy.stats.fisher_exact()) albo połączyć rzadkie kategorie, aby zwiększyć oczekiwane liczebności. Zawsze należy sprawdzić macierz oczekiwanych liczebności zwróconą przez chi2_contingency.
import numpy as np
from scipy import stats
# Table with small expected counts
observed = np.array([[2, 3], [100, 95]])
chi2, p, dof, expected = stats.chi2_contingency(observed)
print('Expected frequencies:')
print(expected)
print('Min expected:', expected.min())
if expected.min() < 5:
print('Warning: Expected frequency < 5. Use Fisher\'s exact test.')
odds_ratio, p_fisher = stats.fisher_exact(observed)
print(f'Fisher\'s exact p: {p_fisher:.4f}')Dokładny test Fishera dla małych prób
scipy.stats.fisher_exact(table) oblicza dokładne prawdopodobieństwo uzyskania danej tabeli 2×2 (lub tabeli o jeszcze bardziej ekstremalnych wartościach) przy założeniu hipotezy zerowej o niezależności, bez stosowania przybliżeń. Test ten jest zawsze poprawny, niezależnie od liczebności próby czy liczebności w komórkach — wartość p jest dokładna, a nie przybliżona. Wadą jest koszt obliczeniowy: funkcja wylicza wszystkie możliwe tabele, przez co działa wolno przy dużych sumach. W przypadku tabel 2×2, w których dowolna liczebność w komórce jest mniejsza od 5, zawsze należy wybrać dokładny test Fishera zamiast testu chi-kwadrat.
import numpy as np
from scipy import stats
# Small clinical trial: treatment vs. outcome
observed = np.array([
[3, 12], # treated: 3 improved, 12 did not
[1, 18] # control: 1 improved, 18 did not
])
odds_ratio, p = stats.fisher_exact(observed, alternative='two-sided')
print(f'Odds ratio: {odds_ratio:.3f}')
print(f'p-value: {p:.4f}')
print('Association significant?', 'Yes' if p < 0.05 else 'No')Pomiar siły zależności: V Craméra
Podobnie jak d Cohena w przypadku testów t, sama statystyka chi-kwadrat nie mierzy siły zależności — jej wartość rośnie wraz z liczebnością próby. V Craméra normalizuje statystykę chi-kwadrat do skali od 0 do 1: 0 oznacza brak zależności, a 1 — doskonałą zależność. V = sqrt(chi2 / (n × min(r-1, c-1))). Wytyczne: < 0.1 oznacza słabą zależność, 0.1–0.3 umiarkowaną, a > 0.3 silną. Aby uzyskać pełny obraz, zawsze należy podawać V Craméra razem z wartością p.
import pandas as pd
import numpy as np
from scipy import stats
np.random.seed(0)
df = pd.DataFrame({
'tier': np.random.choice(['free', 'basic', 'pro'], 500),
'churn': np.random.choice(['yes', 'no'], 500, p=[0.3, 0.7])
})
ct = pd.crosstab(df['tier'], df['churn'])
chi2, p, dof, _ = stats.chi2_contingency(ct)
n = ct.sum().sum()
min_dim = min(ct.shape[0]-1, ct.shape[1]-1)
cramers_v = np.sqrt(chi2 / (n * min_dim))
print(f'chi2={chi2:.3f}, p={p:.4f}')
print(f'Cramer\'s V: {cramers_v:.4f}')
print('Association strength:', 'strong' if cramers_v > 0.3 else 'moderate' if cramers_v > 0.1 else 'weak')Test chi-kwadrat zgodności
Innym zastosowaniem chi-kwadratu jest test zgodności: sprawdza on, czy zaobserwowane liczebności odpowiadają zakładanemu rozkładowi. Na przykład: „Czy wyniki rzutów kostką mają rozkład jednostajny?” albo „Czy ruch na naszej stronie internetowej odpowiada oczekiwanemu rozkładowi według dni tygodnia?”. Proszę użyć scipy.stats.chisquare(f_obs, f_exp), gdzie f_exp oznacza oczekiwane liczebności. Hipoteza zerowa mówi, że dane są zgodne ze wskazanym rozkładem.
import numpy as np
from scipy import stats
# Observed: counts for each weekday over 70 weeks
observed = np.array([980, 1050, 1020, 1080, 1120, 850, 900])
# Expected: uniform distribution
expected = np.full(7, observed.sum() / 7)
chi2, p = stats.chisquare(f_obs=observed, f_exp=expected)
print('Observed:', observed)
print('Expected (uniform):', expected.round(0))
print(f'chi2={chi2:.3f}, p={p:.4f}')
print('Uniform?', 'Yes' if p > 0.05 else 'No - some days significantly busier')Używanie pd.crosstab z normalizacją
Podczas prezentowania wyników testu chi-kwadrat warto pokazywać proporcje zamiast surowych liczebności, aby czytelnicy mogli zobaczyć względną zależność. pd.crosstab(var1, var2, normalize='index') pokazuje proporcje wierszy (jaka część każdej kategorii wiersza przypada na poszczególne kolumny). normalize='columns' pokazuje proporcje kolumn. Wizualne porównanie tych proporcji przed wykonaniem testu pomaga przewidzieć kierunek zależności i zinterpretować wynik w odpowiednim kontekście.
import pandas as pd
import numpy as np
np.random.seed(0)
df = pd.DataFrame({
'tier': np.random.choice(['free', 'basic', 'pro'], 300),
'churned': np.random.choice(['yes', 'no'], 300, p=[0.3, 0.7])
})
# Row-proportions: churn rate within each tier
prop_table = pd.crosstab(df['tier'], df['churned'], normalize='index')
print('Churn rate by tier:')
print((prop_table * 100).round(1))Test chi-kwadrat w testach A/B
Test chi-kwadrat jest standardowym testem dla współczynników konwersji w testach A/B. Należy utworzyć tabelę kontyngencji 2×2, w której wiersze oznaczają (grupę kontrolną, wariant), a kolumny (konwersję, brak konwersji). Test chi-kwadrat informuje, czy współczynnik konwersji różni się istotnie między grupami. W przypadku dużych prób jest to równoważne testowi z dla dwóch proporcji. Dla małych prób (gdy dowolna oczekiwana liczebność jest < 5) należy zamiast niego użyć dokładnego testu Fishera.
import numpy as np
from scipy import stats
# A/B test: control vs. variant, conversions vs. non-conversions
control_conv = 45
control_total = 500
variant_conv = 63
variant_total = 500
contingency = np.array([
[control_conv, control_total - control_conv],
[variant_conv, variant_total - variant_conv]
])
chi2, p, dof, expected = stats.chi2_contingency(contingency)
print(f'Control rate: {control_conv/control_total:.1%}')
print(f'Variant rate: {variant_conv/variant_total:.1%}')
print(f'p-value: {p:.4f}')
print('Variant significantly better?', 'Yes' if p < 0.05 else 'No')Szybkie sprawdzenie
Sprawdź swoją wiedzę na temat koncepcji analizy danych omówionych w tej lekcji.
Podsumowanie lekcji
W tej lekcji poznał(a) Pan/Pani: pd.crosstab() + chi2_contingency() służą do sprawdzania, czy dwie zmienne kategorialne są niezależne, na podstawie porównania liczebności zaobserwowanych i oczekiwanych; dokładny test Fishera jest bezpieczną alternatywą, gdy oczekiwane liczebności są mniejsze od 5; a V Craméra mierzy siłę zależności niezależnie od liczebności próby. W następnej części porównamy średnie w trzech lub większej liczbie grup za pomocą ANOVA i testów post hoc.
Ucz się Python dzięki korepetycjom AI — za darmo
Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.
- Kursy
- 30
- Lekcje
- 120
Często zadawane pytania
Czy lekcja „Test chi-kwadrat niezależności” jest bezpłatna?
Tak — pełny tekst „Test chi-kwadrat niezależności” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Pandas & NumPy Academy, przejdź na CoddyKit PRO. Kurs Pandas & NumPy Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „Test chi-kwadrat niezależności”?
Sprawdź, czy dwie zmienne kategorialne są niezależne, używając chi2_contingency na tabeli częstości utworzonej za pomocą crosstab. Ćwiczysz Pandas & NumPy Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć Pandas & NumPy Academy?
Nie wymagamy żadnego doświadczenia. Pandas & NumPy Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 3 z 4.
Ile czasu zajmuje lekcja „Test chi-kwadrat niezależności”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji Pandas & NumPy Academy?
Tak. Każda lekcja Pandas & NumPy Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Statystyki opisowe i testowanie normalności
- Testy t do porównywania średnich
- Test chi-kwadrat niezależności
- ANOVA i testy post-hoc