Collider bias: Jak filtrování dat vytváří falešné korelace
Kollider je proměnná C, na kterou vedou příčinné cesty z A a B: A → C ← B. Podmínění podle C (filtrace nebo stratifikace) otevírá falešnou souvislost mezi A a B.
Příklady z praxe:
- Věk → Používání → Kvalita (přeživší předměty se zdají kvalitnější).
- Inteligence → Přijetí na VŠ → Bohatství rodičů (mezi studenty bohatší vypadají méně inteligentní).
- Talent → Úspěch → Pracovitost (úspěšní talentovaní se zdají lenivější).
V data science to vede ke špatným modelům: gradient boosting na filtrovaných datech dědí tento bias.
Simulace na rovnoměrných datech
Generujeme 1000 bodů A a B z uniform(0,100), nezávislé. Kollider flag = (A > 50) | (B > 50).
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns
from statsmodels.nonparametric.smoothers_lowess import lowess
NUMBER_OF_VALUES = 1000
A_RANGE = (0, 100)
B_RANGE = (0, 100)
A_THRESHOLD = 50
B_THRESHOLD = 50
a = np.random.uniform(*A_RANGE, NUMBER_OF_VALUES)
b = np.random.uniform(*B_RANGE, NUMBER_OF_VALUES)
data = pd.DataFrame({'a': a, 'b': b})
data['flag'] = (data['a'] > A_THRESHOLD) | (data['b'] > B_THRESHOLD)
print(f"Korelace mezi A a B: {data['a'].corr(data['b']):.2f}")
print(f"Korelace tam, kde flag je pravdivý: {data[data['flag']]['a'].corr(data[data['flag']]['b']):.2f}")
Výsledek:
- Celková výběrka: corr ≈ 0,00
- Filtrovaná: corr ≈ -0,34
Vizualizace scatterplotu ukazuje, jak odstranění "nevyživších" bodů (modré) posouvá trend dolů.
sns.scatterplot(data=data, x='a', y='b', hue='flag', palette={True: 'red', False: 'blue'}, alpha=0.5)
sns.regplot(data=data, x='a', y='b', scatter=False, color='black')
plt.show()
Po filtrování dává lmplot záporný sklon: pravý horní úhel "vyprázdněl", rovnováha je narušena.
Realistický scénář: normální rozdělení
Přecházíme na np.random.normal: A ~ N(50,5), B ~ N(30,5). Pravděpodobnostní kollider: normalizujeme, selection_prob = max(a_norm, b_norm)*1.5, clip(0,1), flag = rand < prob.
a = np.random.normal(loc=50, scale=5, size=NUMBER_OF_VALUES)
b = np.random.normal(loc=30, scale=5, size=NUMBER_OF_VALUES)
normal_data = pd.DataFrame({'a': a, 'b': b})
a_norm = (normal_data['a'] - normal_data['a'].min()) / (normal_data['a'].max() - normal_data['a'].min() + 1e-6)
b_norm = (normal_data['b'] - normal_data['b'].min()) / (normal_data['b'].max() - normal_data['b'].min() + 1e-6)
selection_prob = np.maximum(a_norm, b_norm) * 1.5
selection_prob = np.clip(selection_prob, 0, 1)
normal_data['flag'] = np.random.random(len(normal_data)) < selection_prob
print(f"Korelace ve celém datasetu: {normal_data['a'].corr(normal_data['b']):.2f}")
print(f"Korelace, když je flag pravdivý: {normal_data[normal_data['flag']]['a'].corr(normal_data[normal_data['flag']]['b']):.2f}")
Výsledek:
- Celková: corr ≈ 0,03
- Filtrovaná: corr ≈ -0,09
Efekt je slabší, ale významný v A/B testech, farmách nebo ML.
Jak se v analýze vyhnout
- Kreslete DAG: příčinné grafy (directed acyclic graphs) odhalují kolider.
- Ne-filtrujte podle výsledku: analyzujte celou populaci nebo použijte IPCW (inverse probability censoring weighting).
- Zkontrolujte korelace: porovnejte před a po stratifikaci.
- Nástrojové proměnné: pro příčinný závěr.
- Bayesovské sítě: explicitně modelují závislosti.
Důležité informace
- Collider bias vzniká při podmínění na společné příčině – vytváří falešnou zápornou korelaci.
- Simulace na uniform dává corr -0,34, na normal -0,09; efekt se škáluje.
- Souvisí s chybou přeživšího, Berksónovým paradoxem, selekčním biasem.
- Kontrola: nakreslete DAG před filtrováním.
- V ML: filtrovaná data → zkreslené modely, podhodnocení/přehodnocení funkcí.
— Editorial Team
Zatím žádné komentáře.