Método Científico (Incompleto)

Juntando o método científico com o conceito de causalidade

Resultados Esperados

  1. Entender como testes de hipótese ligam com causalidade
  2. Entender o método científico

Sumário

  1. Introdução
  2. Dados
  3. Dados permutados
  4. Teste de Permutação abaixo.
  5. Diferença de outros exemplos

#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()
GroupResult
0Control1.0
1Control1.0
2Control0.0
3Control0.0
4Control0.0
#In: 
control = df.query('Group == "Control"')
control.head()
GroupResult
0Control1.0
1Control1.0
2Control0.0
3Control0.0
4Control0.0
#In: 
medicados = df.query('Group != "Control"')
medicados.head()
GroupResult
16Treatment1.0
17Treatment1.0
18Treatment1.0
19Treatment1.0
20Treatment1.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()
GroupResult
0Control1.0
1Control1.0
2Treatment0.0
3Treatment0.0
4Control0.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()
GroupResult
0Control1.0
1Control1.0
2Control0.0
3Control0.0
4Control0.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 ]

png

#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!