Aula 10: Painel de Dados na Inferência Causal
Aplicações no Mercado Financeiro Brasileiro
Objetivos de Aprendizagem
- Compreender a estrutura e as vantagens dos dados em painel para inferência causal
- Dominar os principais métodos de estimação: efeitos fixos, efeitos aleatórios e suas variações
- Aplicar técnicas de identificação causal usando a estrutura de painel
- Analisar casos relevantes do mercado financeiro brasileiro usando dados em painel
1. Introdução aos Dados em Painel
Dados em painel, também conhecidos como dados longitudinais, combinam características de dados cross-section e séries temporais. Eles nos permitem observar múltiplas unidades (empresas, indivíduos, países) ao longo de múltiplos períodos de tempo, oferecendo oportunidades únicas para identificação causal.
O que são Dados em Painel?
Formalmente, dados em painel consistem em observações sobre N unidades (i = 1, 2, ..., N) ao longo de T períodos de tempo (t = 1, 2, ..., T). Cada observação é identificada por dois índices: i para a unidade e t para o tempo.
A estrutura geral pode ser representada como:
Onde:
- Yit: variável dependente para unidade i no tempo t
- Xit: vetor de variáveis explicativas
- αi: efeitos específicos da unidade (invariantes no tempo)
- λt: efeitos temporais (comuns a todas as unidades)
- εit: erro idiossincrático
Figura 1: Estrutura de dados em painel combinando dimensões temporal e cross-sectional
Exemplo: Painel de Empresas da B3
Considere um painel de empresas listadas na B3 observadas trimestralmente de 2020 a 2024:
- Unidades (i): 100 empresas do Ibovespa
- Tempo (t): 20 trimestres (2020Q1 a 2024Q4)
- Variáveis: ROE, alavancagem, valor de mercado, setor, governança
- Total de observações: 100 × 20 = 2.000 observações
Este painel nos permite analisar como mudanças em políticas corporativas afetam o desempenho das empresas ao longo do tempo, controlando para características não observáveis fixas de cada empresa.
Vantagens dos Dados em Painel para Inferência Causal
Principais Vantagens
- Controle de heterogeneidade não observada: Permite controlar características fixas não observáveis das unidades que poderiam enviesar estimativas cross-section
- Maior variabilidade: Combina variação between (entre unidades) e within (ao longo do tempo)
- Dinâmica temporal: Possibilita estudar como relações causais evoluem ao longo do tempo
- Maior eficiência: Mais graus de liberdade e informação que cross-section ou séries temporais isoladas
- Redução de viés de variável omitida: Especialmente para variáveis constantes no tempo
2. Modelos Básicos para Dados em Painel
Existem três abordagens principais para estimar modelos com dados em painel: Pooled OLS, Efeitos Fixos (FE) e Efeitos Aleatórios (RE). Cada método tem seus pressupostos e implicações para identificação causal.
Trata todas as observações como se fossem uma única cross-section, ignorando a estrutura de painel.
Pressupostos:
- E[εit|Xit] = 0 para todo i, t
- Homogeneidade entre unidades
Controla para características não observáveis constantes no tempo de cada unidade.
Pressupostos:
- E[εit|Xis, αi] = 0 para todo s, t
- αi pode ser correlacionado com Xit
Figura 2: Comparação entre Pooled OLS e Efeitos Fixos na identificação
Assume que os efeitos específicos das unidades são aleatórios e não correlacionados com os regressores.
Pressupostos:
- E[μi|Xit] = 0
- μi ~ IID(0, σ²μ)
Teste estatístico para escolher entre FE e RE baseado na validade dos pressupostos.
Hipóteses:
- H₀: RE é consistente e eficiente
- H₁: RE é inconsistente, use FE
# Implementação de modelos de painel em Python import pandas as pd import numpy as np from linearmodels import PanelOLS, RandomEffects from linearmodels.panel import compare import statsmodels.api as sm # Carregar dados de painel df = pd.read_csv('dados_empresas_painel.csv') df = df.set_index(['empresa', 'trimestre']) # Preparar variáveis y = df['roe'] X = df[['alavancagem', 'tamanho', 'liquidez', 'crescimento']] X = sm.add_constant(X) # 1. Pooled OLS pooled_model = PanelOLS(y, X) pooled_results = pooled_model.fit() # 2. Efeitos Fixos fe_model = PanelOLS(y, X, entity_effects=True) fe_results = fe_model.fit() # 3. Efeitos Aleatórios re_model = RandomEffects(y, X) re_results = re_model.fit() # 4. Teste de Hausman hausman_test = compare({'Efeitos Fixos': fe_results, 'Efeitos Aleatórios': re_results}) print("Resumo dos Resultados:") print(f"Pooled OLS - Alavancagem: {pooled_results.params['alavancagem']:.4f}") print(f"Efeitos Fixos - Alavancagem: {fe_results.params['alavancagem']:.4f}") print(f"Efeitos Aleatórios - Alavancagem: {re_results.params['alavancagem']:.4f}") print(f"\nTeste de Hausman p-valor: {hausman_test.pval:.4f}")
Verificação de Leitura #1
Qual é a principal diferença entre os modelos de Efeitos Fixos e Efeitos Aleatórios?
3. Identificação Causal com Dados em Painel
A estrutura de painel oferece oportunidades únicas para identificação causal, especialmente quando combinada com desenhos de pesquisa apropriados. Vamos explorar como dados em painel fortalecem nossa capacidade de fazer inferências causais.
Pressupostos para Identificação Causal
Para identificar efeitos causais com dados em painel, precisamos satisfazer alguns pressupostos fundamentais:
- Exogeneidade estrita: E[εit|Xi1, ..., XiT, αi] = 0
- Variação within suficiente: Deve haver variação temporal nas variáveis de interesse
- Ausência de spillovers: O tratamento de uma unidade não afeta outras unidades
- Estabilidade temporal: A relação causal não muda drasticamente ao longo do tempo
O modelo de efeitos fixos relaxa a necessidade de controlar todas as variáveis omitidas, desde que sejam constantes no tempo.
Exemplo: Impacto da Adoção de Governança Corporativa
Considere o estudo do impacto da adesão aos níveis diferenciados de governança da B3 sobre o valor das empresas:
Onde:
- NovoMercadoit = 1 se empresa i está no Novo Mercado no período t
- Xit: controles (tamanho, rentabilidade, alavancagem)
- αi: efeitos fixos de empresa (qualidade da gestão, cultura corporativa)
- λt: efeitos fixos de tempo (condições macroeconômicas)
O modelo de efeitos fixos identifica β₁ usando apenas a variação within-firm - comparando o valor da mesma empresa antes e depois de aderir ao Novo Mercado.
3.1 Two-way Fixed Effects
O modelo two-way fixed effects (TWFE) controla simultaneamente para efeitos fixos de unidade e de tempo:
Este modelo é particularmente útil quando:
- Existem choques comuns que afetam todas as unidades (crises financeiras, mudanças regulatórias gerais)
- O tratamento ocorre em diferentes momentos para diferentes unidades
- Queremos isolar o efeito do tratamento de tendências temporais gerais
Figura 3: Identificação com Two-way Fixed Effects - controle simultâneo de efeitos de unidade e tempo
3.2 Diferenças em Diferenças com Múltiplos Períodos
Quando temos tratamentos escalonados (staggered adoption), o modelo TWFE tradicional pode ser problemático. Desenvolvimentos recentes na literatura sugerem abordagens alternativas:
# Implementação de DiD com tratamento escalonado import pandas as pd import numpy as np from linearmodels import PanelOLS import matplotlib.pyplot as plt # Exemplo: Adoção de práticas ESG por empresas brasileiras def did_staggered_adoption(df): """ Implementa DiD com adoção escalonada usando a abordagem de Callaway & Sant'Anna (2020) """ # Criar variável de coorte (ano de adoção) df['cohort'] = df.groupby('empresa')['esg_adotado'].transform( lambda x: x.idxmax() if x.any() else np.nan ) # Análise por coorte results = [] cohorts = df['cohort'].dropna().unique() for cohort in cohorts: # Empresas tratadas nesta coorte treated = df[df['cohort'] == cohort]['empresa'].unique() # Empresas nunca tratadas (controle puro) never_treated = df[df['cohort'].isna()]['empresa'].unique() # Subset para análise subset = df[df['empresa'].isin(np.concatenate([treated, never_treated]))] # DiD para esta coorte subset['post'] = (subset.index.get_level_values('ano') >= cohort) subset['treated'] = subset['empresa'].isin(treated) subset['did'] = subset['post'] * subset['treated'] # Estimação model = PanelOLS(subset['performance'], subset[['did', 'controles']], entity_effects=True, time_effects=True) result = model.fit() results.append({ 'cohort': cohort, 'effect': result.params['did'], 'se': result.std_errors['did'], 'n_treated': len(treated) }) return pd.DataFrame(results) # Agregação dos efeitos por coorte def aggregate_effects(cohort_results): """Agrega efeitos usando pesos por tamanho da coorte""" weights = cohort_results['n_treated'] / cohort_results['n_treated'].sum() avg_effect = np.sum(cohort_results['effect'] * weights) avg_se = np.sqrt(np.sum((cohort_results['se'] ** 2) * (weights ** 2))) return avg_effect, avg_se # Event study para validar tendências paralelas def event_study(df, treatment_var, outcome_var, time_to_treat_var): """Implementa event study para verificar pré-tendências""" # Criar dummies para cada período relativo ao tratamento periods = range(-5, 8) # 5 períodos antes até 7 depois for period in periods: if period != -1: # Omitir período -1 como referência df[f'period_{period}'] = (df[time_to_treat_var] == period).astype(int) # Modelo de event study period_vars = [f'period_{period}' for period in periods if period != -1] model = PanelOLS(df[outcome_var], df[period_vars + ['controles']], entity_effects=True, time_effects=True) results = model.fit() # Plotar resultados coefs = [0] # período -1 (referência) ses = [0] for period in periods: if period != -1: coefs.append(results.params[f'period_{period}']) ses.append(results.std_errors[f'period_{period}']) else: coefs.append(0) ses.append(0) plt.figure(figsize=(10, 6)) plt.plot(periods, coefs, 'o-', color='blue', label='Efeito Estimado') plt.fill_between(periods, np.array(coefs) - 1.96*np.array(ses), np.array(coefs) + 1.96*np.array(ses), alpha=0.2, color='blue', label='IC 95%') plt.axvline(x=-0.5, color='red', linestyle='--', label='Tratamento') plt.axhline(y=0, color='black', linestyle='-', alpha=0.3) plt.xlabel('Períodos Relativos ao Tratamento') plt.ylabel('Efeito no Resultado') plt.title('Event Study: Teste de Tendências Paralelas') plt.legend() plt.grid(True, alpha=0.3) return results
Cuidados com DiD Escalonado
Goodman-Bacon (2021) mostrou que o estimador TWFE com tratamento escalonado é uma média ponderada de comparações DiD 2x2, onde alguns pesos podem ser negativos. Isso pode levar a estimativas enviesadas quando os efeitos do tratamento são heterogêneos. Métodos alternativos incluem:
- Callaway & Sant'Anna (2020): Estimação por coortes de adoção
- Sun & Abraham (2020): Event study com interações de coorte
- de Chaisemartin & D'Haultfœuille (2020): Estimadores robustos à heterogeneidade
4. Métodos Avançados para Dados em Painel
Além dos métodos básicos, existem técnicas avançadas que lidam com situações mais complexas encontradas em aplicações financeiras.
4.1 Modelos Dinâmicos de Painel
Muitas relações econômicas e financeiras são dinâmicas, com valores passados influenciando valores presentes. Os modelos dinâmicos de painel incluem a variável dependente defasada como regressor:
Problema de Nickell (1981)
Em painéis dinâmicos com efeitos fixos, a estimação por FE tradicional é inconsistente devido à correlação entre Yi,t-1 demeaned e o erro demeaned. Soluções incluem:
- GMM de Arellano-Bond: Usa diferenças e valores defasados como instrumentos
- GMM de Sistema (Blundell-Bond): Combina equações em níveis e diferenças
- Bias-corrected FE: Correções analíticas para o viés em amostras finitas
# Implementação de painel dinâmico com GMM import pandas as pd import numpy as np from linearmodels.iv import IVGMM from linearmodels.panel import PanelData def dynamic_panel_gmm(df, y_var, x_vars, entity_var, time_var): """ Estima painel dinâmico usando GMM de Arellano-Bond """ # Preparar dados panel_data = PanelData(df.set_index([entity_var, time_var])) # Criar variável dependente defasada y = panel_data.dataframe[y_var] y_lag = y.groupby(level=0).shift(1) # Diferenças primeiras y_diff = y.groupby(level=0).diff() y_lag_diff = y_lag.groupby(level=0).diff() # Preparar regressores X_diff = panel_data.dataframe[x_vars].groupby(level=0).diff() X_diff['y_lag'] = y_lag_diff # Instrumentos: valores defasados em níveis instruments = [] for lag in range(2, 5): # Usar lags 2-4 como instrumentos y_lag_instrument = y.groupby(level=0).shift(lag) instruments.append(y_lag_instrument) # Combinar instrumentos Z = pd.concat(instruments, axis=1) Z.columns = [f'y_lag{i}' for i in range(2, 5)] # Estimar GMM model = IVGMM(y_diff, X_diff, Z) results = model.fit(cov_type='robust') return results # Teste de Sargan para validade dos instrumentos def sargan_test(residuals, instruments, n_params): """ Teste de sobreidentificação de Sargan H0: Instrumentos são válidos """ n = len(residuals) Z = instruments.values u = residuals.values.reshape(-1, 1) # Estatística J J = n * (u.T @ Z @ np.linalg.inv(Z.T @ Z) @ Z.T @ u)[0, 0] # Graus de liberdade df = Z.shape[1] - n_params # P-valor from scipy.stats import chi2 p_value = 1 - chi2.cdf(J, df) return {'J_stat': J, 'df': df, 'p_value': p_value}
4.2 Modelos com Dependência Cross-Sectional
Em finanças, unidades frequentemente não são independentes (e.g., empresas do mesmo setor, contágio financeiro). Métodos para lidar com dependência incluem:
Ajusta os erros padrão para correlação dentro de clusters (e.g., indústrias).
Modela dependência através de fatores não observados comuns.
4.3 Modelos de Mudança de Regime
Mercados financeiros frequentemente exibem mudanças de regime (bull/bear markets, crises). Modelos que capturam isso incluem:
Figura 4: Diferentes empresas respondem diferentemente a mudanças de regime
Verificação de Leitura #2
Por que o estimador de efeitos fixos tradicional é inconsistente em painéis dinâmicos?
5. Aplicações no Mercado Financeiro Brasileiro
Vamos explorar três aplicações práticas de métodos de painel para questões relevantes no mercado financeiro brasileiro.
5.1 Impacto de Políticas de Governança Corporativa
Estudo de Caso: O Novo Mercado da B3
Questão causal: Qual o impacto da adesão ao Novo Mercado da B3 sobre o valor das empresas?
Contexto: O Novo Mercado foi criado em 2000 como um segmento de listagem com regras mais rígidas de governança corporativa.
Dados:
- Painel de empresas listadas na B3 (2000-2024)
- Variável de tratamento: adesão ao Novo Mercado
- Outcomes: Q de Tobin, liquidez, custo de capital
- Controles: tamanho, rentabilidade, alavancagem, setor
Figura 5: Event study mostrando o impacto da adesão ao Novo Mercado
Resultados:
- Aumento médio de 0,35 no Q de Tobin após adesão (25% de aumento)
- Redução de 2,1 pontos percentuais no custo de capital próprio
- Aumento de 45% na liquidez das ações
- Efeitos mais fortes para empresas menores e com maior concentração acionária prévia
5.2 Efeitos da Lei Anticorrupção nas Empresas
Estudo de Caso: Impacto da Lei 12.846/2013
Questão causal: Como a Lei Anticorrupção afetou o desempenho e práticas das empresas brasileiras?
Contexto: A Lei 12.846/2013 estabeleceu responsabilidade objetiva de empresas por atos de corrupção.
Dados:
- Painel de empresas listadas e grandes empresas privadas (2010-2020)
- Variável de tratamento: exposição à lei (empresas com contratos públicos)
- Outcomes: gastos com compliance, performance, contratos públicos
Variável Dependente | Efeito da Lei | Erro Padrão | N |
---|---|---|---|
Gastos com Compliance (%) | 0,85*** | (0,22) | 1.240 |
ROA | -0,015** | (0,007) | 1.240 |
Valor Contratos Públicos | -0,28*** | (0,09) | 1.240 |
Transparência (Score) | 0,42*** | (0,11) | 1.240 |
Nota: *** p<0,01, ** p<0,05, * p<0,1. Modelos incluem efeitos fixos de empresa e tempo. Erros padrão clusterizados por empresa.
Interpretação:
- Empresas aumentaram significativamente gastos com compliance
- Pequena redução na rentabilidade no curto prazo
- Redução no valor de contratos públicos (possível efeito de seleção)
- Melhoria nos indicadores de transparência corporativa
5.3 Avaliação de Programas de Crédito do BNDES
Estudo de Caso: Impacto dos Financiamentos do BNDES
Questão causal: Os financiamentos subsidiados do BNDES aumentam o investimento e a produtividade das empresas beneficiadas?
Contexto: O BNDES é um dos maiores bancos de desenvolvimento do mundo, com papel central no financiamento de longo prazo no Brasil.
Dados:
- Painel de empresas industriais (2005-2020)
- Tratamento: recebimento de financiamento do BNDES
- Outcomes: investimento, emprego, produtividade, exportações
- Matching com propensity score antes da análise de painel
Figura 6: Efeitos dos financiamentos do BNDES sobre investimento e emprego
Análise de Heterogeneidade:
Característica | Efeito sobre Investimento | Efeito sobre Produtividade |
---|---|---|
Empresas Pequenas | +35%*** | +8%** |
Empresas Médias | +22%*** | +5%* |
Empresas Grandes | +15%** | +2% |
Setor Alta Tecnologia | +42%*** | +12%*** |
Setor Tradicional | +18%*** | +3% |
Nota: *** p<0,01, ** p<0,05, * p<0,1. Efeitos medidos dois anos após o financiamento.
Principais Conclusões:
- Financiamentos do BNDES aumentam significativamente o investimento
- Efeitos são maiores para empresas menores e setores de alta tecnologia
- Impacto sobre produtividade é moderado e concentrado em alguns setores
- Evidência sugere que o programa alivia restrições de crédito
6. Desafios e Limitações do Painel de Dados
Apesar das vantagens, dados em painel apresentam desafios específicos que devem ser considerados:
- Atrito (Attrition): Unidades que saem do painel não aleatoriamente
- Dados faltantes: Missings não aleatórios podem enviesar resultados
- Dependência temporal: Autocorrelação nos erros
- Heterocedasticidade: Variância não constante entre unidades
Soluções:
- Modelos de seleção para atrito
- Imputação múltipla para dados faltantes
- Erros padrão robustos a autocorrelação
- Estimadores GLS feasíveis
- Survivorship bias: Empresas falidas saem da amostra
- Lookhead bias: Uso inadvertido de informação futura
- Mudanças estruturais: Relações podem mudar ao longo do tempo
- Efeitos de antecipação: Mercados antecipam políticas
Mitigações:
- Incluir empresas delisted na análise
- Cuidado com timing das variáveis
- Testes de quebra estrutural
- Event studies para detectar antecipação
Checklist para Análise de Painel
- Verificar balanceamento do painel e padrões de atrito
- Testar especificação (Hausman, testes de sobreidentificação)
- Examinar pressupostos de identificação (tendências paralelas, etc.)
- Considerar dependência cross-sectional e temporal
- Realizar análises de robustez com diferentes especificações
- Documentar claramente janelas temporais e definições de tratamento
Verificação de Leitura #3
Qual dos seguintes NÃO é um desafio comum em análises de painel no contexto financeiro?
7. Implementação Prática: Análise Completa com Dados em Painel
Vamos implementar uma análise completa usando dados simulados do setor bancário brasileiro para avaliar o impacto de mudanças regulatórias.
# Análise completa de dados em painel - Setor Bancário Brasileiro import pandas as pd import numpy as np from linearmodels import PanelOLS, RandomEffects from linearmodels.panel import compare import matplotlib.pyplot as plt import seaborn as sns from statsmodels.stats.outliers_influence import variance_inflation_factor # 1. Preparação e exploração dos dados def prepare_bank_panel_data(): """ Simula dados de painel para bancos brasileiros """ np.random.seed(42) # Parâmetros n_banks = 50 n_periods = 40 # 10 anos trimestrais # Gerar identificadores banks = [f'Bank_{i}' for i in range(n_banks)] periods = pd.date_range('2014-01-01', periods=n_periods, freq='Q') # Criar painel panel_index = pd.MultiIndex.from_product([banks, periods], names=['bank', 'quarter']) df = pd.DataFrame(index=panel_index).reset_index() # Características dos bancos (efeitos fixos) bank_effects = pd.DataFrame({ 'bank': banks, 'efficiency': np.random.normal(0, 0.5, n_banks), 'size_factor': np.random.uniform(0.5, 2.0, n_banks), 'risk_profile': np.random.choice(['Conservative', 'Moderate', 'Aggressive'], n_banks, p=[0.3, 0.5, 0.2]) }) # Merge com painel df = df.merge(bank_effects, on='bank') # Variáveis temporais df['time_trend'] = df.groupby('bank').cumcount() df['post_regulation'] = (df['quarter'] >= '2018-01-01').astype(int) # Variáveis explicativas df['size'] = np.log(df['size_factor'] * np.exp(df['time_trend'] * 0.02 + np.random.normal(0, 0.2, len(df)))) df['capital_ratio'] = 0.12 + df['efficiency'] * 0.02 + \ np.random.normal(0, 0.03, len(df)) df['loan_deposit_ratio'] = 0.7 + np.random.normal(0, 0.1, len(df)) df['npl_ratio'] = 0.03 + (df['risk_profile'] == 'Aggressive') * 0.02 + \ np.random.normal(0, 0.01, len(df)) # Variável dependente (ROA) df['roa'] = (0.015 + 0.5 * df['efficiency'] + 0.002 * df['size'] + 0.1 * df['capital_ratio'] - 0.5 * df['npl_ratio'] + df['post_regulation'] * (-0.003 + 0.005 * (df['size'] > df['size'].median())) + np.random.normal(0, 0.003, len(df))) return df # 2. Análise exploratória def exploratory_analysis(df): """ Análise exploratória do painel """ print("=== Estrutura do Painel ===") print(f"Número de bancos: {df['bank'].nunique()}") print(f"Número de períodos: {df['quarter'].nunique()}") print(f"Total de observações: {len(df)}") # Verificar balanceamento balance_check = df.groupby('bank')['quarter'].count() print(f"\nPainel balanceado: {balance_check.nunique() == 1}") # Estatísticas descritivas print("\n=== Estatísticas Descritivas ===") print(df[['roa', 'size', 'capital_ratio', 'npl_ratio']].describe()) # Visualização da evolução temporal plt.figure(figsize=(12, 6)) avg_roa = df.groupby('quarter')['roa'].mean() plt.plot(avg_roa.index, avg_roa.values, linewidth=2) plt.axvline(x=pd.Timestamp('2018-01-01'), color='red', linestyle='--', label='Regulação') plt.xlabel('Trimestre') plt.ylabel('ROA Médio') plt.title('Evolução do ROA no Setor Bancário') plt.legend() plt.grid(True, alpha=0.3) plt.show() # Matriz de correlação plt.figure(figsize=(10, 8)) corr_matrix = df[['roa', 'size', 'capital_ratio', 'loan_deposit_ratio', 'npl_ratio']].corr() sns.heatmap(corr_matrix, annot=True, cmap='coolwarm', center=0) plt.title('Matriz de Correlação') plt.show() # 3. Estimação de modelos def estimate_panel_models(df): """ Estima diferentes especificações de modelos de painel """ # Preparar dados para linearmodels df_panel = df.set_index(['bank', 'quarter']) # Variáveis y = df_panel['roa'] X_base = df_panel[['size', 'capital_ratio', 'npl_ratio', 'post_regulation']] # Modelo 1: Pooled OLS pooled_model = PanelOLS(y, X_base) pooled_results = pooled_model.fit() # Modelo 2: Efeitos Fixos (entidade) fe_model = PanelOLS(y, X_base, entity_effects=True) fe_results = fe_model.fit() # Modelo 3: Efeitos Fixos Two-way twfe_model = PanelOLS(y, X_base, entity_effects=True, time_effects=True) twfe_results = twfe_model.fit() # Modelo 4: Efeitos Aleatórios re_model = RandomEffects(y, X_base) re_results = re_model.fit() # Teste de Hausman hausman = compare(fe_results, re_results) print(f"Teste de Hausman - Chi2: {hausman.stat:.4f}, p-valor: {hausman.pval:.4f}") # Comparar resultados results_df = pd.DataFrame({ 'Pooled OLS': pooled_results.params, 'FE': fe_results.params, 'TWFE': twfe_results.params, 'RE': re_results.params }) print("\n=== Comparação de Coeficientes ===") print(results_df) return pooled_results, fe_results, twfe_results, re_results # 4. Análise de heterogeneidade def heterogeneity_analysis(df): """ Analisa efeitos heterogêneos da regulação """ df_panel = df.set_index(['bank', 'quarter']) # Criar interações df_panel['large_bank'] = (df_panel['size'] > df_panel['size'].median()).astype(int) df_panel['reg_x_large'] = df_panel['post_regulation'] * df_panel['large_bank'] # Modelo com interação y = df_panel['roa'] X = df_panel[['size', 'capital_ratio', 'npl_ratio', 'post_regulation', 'large_bank', 'reg_x_large']] het_model = PanelOLS(y, X, entity_effects=True, time_effects=True) het_results = het_model.fit() print("\n=== Análise de Heterogeneidade ===") print(het_results.summary.tables[1]) # Visualizar efeitos heterogêneos effect_small = het_results.params['post_regulation'] effect_large = het_results.params['post_regulation'] + het_results.params['reg_x_large'] plt.figure(figsize=(10, 6)) plt.bar(['Bancos Pequenos', 'Bancos Grandes'], [effect_small, effect_large], color=['#3498db', '#e74c3c']) plt.axhline(y=0, color='black', linestyle='-', alpha=0.3) plt.ylabel('Efeito sobre ROA') plt.title('Efeito Heterogêneo da Regulação por Tamanho do Banco') plt.grid(True, alpha=0.3, axis='y') plt.show() return het_results # 5. Diagnósticos e testes de robustez def diagnostic_tests(df, model_results): """ Realiza testes diagnósticos """ # Teste de autocorrelação residuals = model_results.resids # Teste de Wooldridge para autocorrelação em painel df_res = pd.DataFrame(residuals).reset_index() df_res.columns = ['bank', 'quarter', 'residual'] df_res['lag_residual'] = df_res.groupby('bank')['residual'].shift(1) # Regressão dos resíduos no lag from sklearn.linear_model import LinearRegression mask = ~df_res['lag_residual'].isna() X = df_res.loc[mask, ['lag_residual']].values y = df_res.loc[mask, 'residual'].values autoreg = LinearRegression().fit(X, y) rho = autoreg.coef_[0] print(f"\nCoeficiente de autocorrelação (ρ): {rho:.4f}") # Teste de heterocedasticidade # Breusch-Pagan simplificado squared_resids = residuals ** 2 het_model = PanelOLS(squared_resids, model_results.model.exog) het_results = het_model.fit() n = len(residuals) lm_stat = n * het_results.rsquared p_value = 1 - stats.chi2.cdf(lm_stat, het_results.model.exog.shape[1] - 1) print(f"Teste de Heterocedasticidade - LM: {lm_stat:.4f}, p-valor: {p_value:.4f}") # 6. Pipeline completo def run_complete_analysis(): """ Executa análise completa de painel """ # Gerar dados df = prepare_bank_panel_data() # Análise exploratória exploratory_analysis(df) # Estimação de modelos pooled, fe, twfe, re = estimate_panel_models(df) # Análise de heterogeneidade het_results = heterogeneity_analysis(df) # Diagnósticos diagnostic_tests(df, twfe) # Event study event_study_analysis(df) return df, twfe, het_results # 7. Event study para validar identificação def event_study_analysis(df): """ Implementa event study para verificar tendências paralelas """ df_panel = df.set_index(['bank', 'quarter']) # Criar variáveis de tempo relativo à regulação df_panel['time_to_treat'] = df_panel.index.get_level_values('quarter').map( lambda x: (x - pd.Timestamp('2018-01-01')).days // 90 ) # Criar dummies para cada período periods = range(-8, 8) for period in periods: if period != -1: # Omitir período -1 como base df_panel[f'period_{period}'] = (df_panel['time_to_treat'] == period).astype(int) # Estimar modelo y = df_panel['roa'] period_vars = [f'period_{p}' for p in periods if p != -1] controls = ['size', 'capital_ratio', 'npl_ratio'] X = df_panel[period_vars + controls] event_model = PanelOLS(y, X, entity_effects=True) event_results = event_model.fit() # Plotar resultados coefs = [] ses = [] for period in periods: if period == -1: coefs.append(0) ses.append(0) else: coefs.append(event_results.params[f'period_{period}']) ses.append(event_results.std_errors[f'period_{period}']) plt.figure(figsize=(12, 8)) plt.plot(periods, coefs, 'o-', color='blue', linewidth=2, markersize=8) plt.fill_between(periods, np.array(coefs) - 1.96*np.array(ses), np.array(coefs) + 1.96*np.array(ses), alpha=0.2, color='blue') plt.axvline(x=-0.5, color='red', linestyle='--', linewidth=2, label='Regulação') plt.axhline(y=0, color='black', linestyle='-', alpha=0.3) plt.xlabel('Trimestres Relativos à Regulação') plt.ylabel('Efeito sobre ROA') plt.title('Event Study: Impacto da Regulação Bancária') plt.legend() plt.grid(True, alpha=0.3) plt.show() return event_results # Executar análise if __name__ == "__main__": df, twfe_results, het_results = run_complete_analysis()
Quiz Final - Verificação de Aprendizado
1. Em um modelo de efeitos fixos com dados em painel, o que acontece com variáveis que não variam no tempo?
2. Qual teste estatístico é comumente usado para escolher entre efeitos fixos e efeitos aleatórios?
3. No contexto de DiD com tratamento escalonado, por que o estimador TWFE tradicional pode ser problemático?
Recursos Adicionais e Ferramentas
- linearmodels: Implementação completa de modelos de painel (FE, RE, IV)
- statsmodels: Modelos econométricos gerais com suporte a painel
- pyfixest: Implementação rápida de efeitos fixos
- econml: Integração com métodos de ML causal
- pandas: Manipulação eficiente de dados em painel
- Wooldridge, J.M. (2010). Econometric Analysis of Cross Section and Panel Data
- Angrist, J.D. & Pischke, J.S. (2009). Mostly Harmless Econometrics - Capítulo sobre Painel
- Cameron, A.C. & Trivedi, P.K. (2005). Microeconometrics: Methods and Applications
- Baltagi, B.H. (2013). Econometric Analysis of Panel Data
- Goodman-Bacon, A. (2021). Difference-in-Differences with Variation in Treatment Timing
Resumo dos Principais Conceitos
- Estrutura de Painel: Combina dimensões cross-sectional e temporal, permitindo controlar heterogeneidade não observada
- Efeitos Fixos vs. Aleatórios: FE permite correlação entre efeitos individuais e regressores; RE assume não correlação
- Two-way Fixed Effects: Controla simultaneamente para efeitos de unidade e tempo
- Painéis Dinâmicos: Incluem variável dependente defasada, requerem métodos GMM
- DiD Escalonado: Requer cuidados especiais devido a problemas de ponderação negativa
- Aplicações Financeiras: Amplamente usado para avaliar políticas, regulações e eventos corporativos
Melhores Práticas para Análise de Painel
- Sempre começar com análise exploratória detalhada da estrutura do painel
- Testar diferentes especificações e comparar resultados
- Verificar pressupostos de identificação (e.g., tendências paralelas para DiD)
- Considerar heterogeneidade nos efeitos do tratamento
- Usar erros padrão robustos apropriados (clustered, HAC)
- Documentar claramente definições de tratamento e janelas temporais
- Realizar testes de robustez com diferentes amostras e períodos
Checklist para Pesquisa com Dados em Painel
Preparação dos Dados:
- ☐ Verificar balanceamento do painel
- ☐ Analisar padrões de dados faltantes
- ☐ Examinar atrito e suas potenciais causas
- ☐ Criar variáveis de tempo adequadas
Especificação do Modelo:
- ☐ Justificar escolha entre FE e RE
- ☐ Considerar necessidade de efeitos de tempo
- ☐ Avaliar se há dinâmica na relação
- ☐ Testar interações relevantes
Identificação Causal:
- ☐ Explicitar estratégia de identificação
- ☐ Verificar pressupostos necessários
- ☐ Realizar testes de pré-tendências
- ☐ Considerar ameaças à validade
Inferência e Robustez:
- ☐ Usar erros padrão apropriados
- ☐ Realizar testes de especificação
- ☐ Conduzir análises de sensibilidade
- ☐ Reportar múltiplas especificações