Método Científico (Incompleto)
Juntando o método científico com o conceito de causalidade
Resultados Esperados
- Entender como testes de hipótese ligam com causalidade
- Entender o método científico
Sumário
#In:
# -*- coding: utf8
from scipy import stats as ss
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
#In:
plt.style.use('seaborn-colorblind')
plt.rcParams['figure.figsize'] = (16, 10)
plt.rcParams['axes.labelsize'] = 20
plt.rcParams['axes.titlesize'] = 20
plt.rcParams['legend.fontsize'] = 20
plt.rcParams['xtick.labelsize'] = 20
plt.rcParams['ytick.labelsize'] = 20
plt.rcParams['lines.linewidth'] = 4
#In:
plt.ion()
#In:
def despine(ax=None):
if ax is None:
ax = plt.gca()
# Hide the right and top spines
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
# Only show ticks on the left and bottom spines
ax.yaxis.set_ticks_position('left')
ax.xaxis.set_ticks_position('bottom')
Introdução
Aqui, vamos brincar um pouco com dados onde posso falar algo de causalidade. Isto é, foi feito um experimento controlado e randomizado. Note que minha ferramenta é a mesma de antes, permutação, porém a forma que os dados foram coletados mudara. Esta é a diferença.
Abaixo tenho uma função simples que permuta uma coluna de um dataframe. Vamos usar ela para implementar o nosso teste de permutação. Este exemplo é bem similar ao teste de permutação já feito. Use o mesmo para revisar!
#In:
def permuta(df, coluna):
'''
Permuta um dataframe com base e uma coluna categórica.
Este código é mais lento pois cria uma cópia.
Parâmetros
----------
df: o dataframe
coluna: uma coluna categórica
Retorna
-------
um novo df permutado
'''
novo = df.copy() # Cópia dos dados
dados = df[coluna].copy() # Copia da coluna, evitar um warning pandas. Deve ter forma melhor de fazer.
np.random.shuffle(dados) # Faz o shuffle
novo[coluna] = dados # Faz overwrite da coluna
return novo
Dados
O DataFrame consiste de dois grupos. Um de controle, outro de tratamento. No primeiro, foi medicado placebo. No segundo, foi utilizado um novo medicamento. Quando o resultado é 1, dizemos que houve melhoria nos pacientes.
#In:
df = pd.read_csv('https://media.githubusercontent.com/media/icd-ufmg/material/master/aulas/13-CausalidadeRCT/bta.csv')
df.head()
Group | Result | |
---|---|---|
0 | Control | 1.0 |
1 | Control | 1.0 |
2 | Control | 0.0 |
3 | Control | 0.0 |
4 | Control | 0.0 |
#In:
control = df.query('Group == "Control"')
control.head()
Group | Result | |
---|---|---|
0 | Control | 1.0 |
1 | Control | 1.0 |
2 | Control | 0.0 |
3 | Control | 0.0 |
4 | Control | 0.0 |
#In:
medicados = df.query('Group != "Control"')
medicados.head()
Group | Result | |
---|---|---|
16 | Treatment | 1.0 |
17 | Treatment | 1.0 |
18 | Treatment | 1.0 |
19 | Treatment | 1.0 |
20 | Treatment | 1.0 |
Ao somar o resultado de cada caso, vejo quantos melhoraram. Note que o valor é bem maior nos medicados.
#In:
control['Result'].sum()
2.0
#In:
medicados['Result'].sum()
9.0
Como os dados são 1/0, a média aqui vira uma proporção. Cada observação, $x_i \in {0, 1}$. 0 é quando não temos um efeito positivo e 1 quando temos.
\[\sum_{i=1}^{N} x_i/n\]#In:
control['Result'].mean()
0.125
#In:
medicados['Result'].mean()
0.6
Aqui tenho o efeito nos dados reais, mensurados em abs.
#In:
abs(medicados['Result'].mean() - control['Result'].mean())
0.475
#In:
tobs = abs(medicados['Result'].mean() - control['Result'].mean())
#In:
tobs
0.475
Dados permutados
#In:
p1 = permuta(df, 'Group')
p1.head()
Group | Result | |
---|---|---|
0 | Control | 1.0 |
1 | Control | 1.0 |
2 | Treatment | 0.0 |
3 | Treatment | 0.0 |
4 | Control | 0.0 |
#In:
p1.query('Group == "Control"').mean()
Result 0.4375
dtype: float64
#In:
p1.query('Group == "Treatment"').mean()
Result 0.266667
dtype: float64
#In:
df.head()
Group | Result | |
---|---|---|
0 | Control | 1.0 |
1 | Control | 1.0 |
2 | Control | 0.0 |
3 | Control | 0.0 |
4 | Control | 0.0 |
Teste de Permutação abaixo.
#In:
valores = []
for _ in range(10000):
novo = permuta(df, 'Group')
controle = novo.query('Group == "Control"')['Result']
medicados = novo.query('Group != "Control"')['Result']
valores.append(abs(controle.mean() - medicados.mean()))
#In:
valores = np.array(valores)
#In:
valores
array([0.34583333, 0.0875 , 0.04166667, ..., 0.04166667, 0.3 ,
0.21666667])
#In:
bins = np.arange(0.15, 0.75, 0.05)
print(bins)
plt.hist(valores, bins=10, edgecolor='k')
plt.ylabel('# de Permutações')
plt.xlabel('Diferança Absoluta ao Permutar')
plt.plot([tobs], [0], 'ro', ms=15)
despine()
[0.15 0.2 0.25 0.3 0.35 0.4 0.45 0.5 0.55 0.6 0.65 0.7 ]
#In:
valor_p = (valores > tobs).mean()
valor_p
0.0011
Diferença de outros exemplos
Neste exemplo foi feito uma intervenção. Isto é, medicamos parte dos dados. Não estamos observando dados apenas. Por isto um exemplo como este é causal, vemos um efeito real em um experimento controlado! Mais importante do que isto, em 2011 foi averiguado que este pequeno estudo é um dos mais corretos quando se trata de dor crônica lombar! O ferramental aqui foram testes simples + uma boa amostra!