DISCLAIMER: THIS IS STILL WORK IN PROGRESS
Em pleno ano eleitoral diversos candidatos aos governos estaduais e presidência da república tratram do tema Educação. É comum que candidatos usem um indicador como o IDEB para avaliar seus próprios desempenhos e de oponentes ao mesmo tempo em que propostas para melhorar esse indicador são veículadas, como construção de novas escolas, contratação de professores, etc. Nossa opinião é que num país de terceiro mundo como o Brasil mesmo outros fatores não diretamente ligados a educação, como violência ou renda possuem uma relação com o desempenho do IDEB; neste notebook buscamos mensurar o impacto que fatores socio-econômicos desempenham nos resultados do IDEB estadual.
Para tal usaremos as seguintes fontes públicas:
Idealmente deveríamos trabalhar com dados de todos os fatores como sendo do mesmo período (ano de 2015) e essa é uma melhoria que pretendemos realizar no futuro.
In [1]:
import pandas as pd
import numpy as np
import scipy as sp
import seaborn as sns
import statsmodels.api as sm
import scikits.bootstrap as bootstrap
import matplotlib.pyplot as plt
import warnings
import patsy
import folium
from statsmodels.formula.api import ols, rlm
%matplotlib inline
sns.set(color_codes=True)
warnings.filterwarnings('ignore')
In [2]:
df = pd.read_csv('IDEB.csv', sep=';', encoding='ansi')
df
Out[2]:
In [3]:
df.describe()
Out[3]:
In [4]:
plt.figure()
sns.distplot(df["IDEB_AI"], hist=False, rug=True, label="IDEB_AI")
sns.distplot(df["IDEB_AF"], hist=False, rug=True, label="IDEB_AF")
Out[4]:
Como vimos nas estatísticas descritivas a média dos dados do IDEB Anos Iniciais (IDEB AI) são superiores que a média do IDEB Anos Finais (IDEB AF), respectivamente 5.11 e 4.00. Porém a diferença entre essas médias é estatisticamente signifcante? Vamos calcular um intervalo de confiança de 95% para essas médias e exibir o resultado:
In [5]:
ci_mean_ideb_ai = bootstrap.ci(data=df["IDEB_AI"], alpha=0.05)
ci_mean_ideb_af = bootstrap.ci(data=df["IDEB_AF"], alpha=0.05)
fig, ax = plt.subplots()
ax.plot(["IDEB_AI", "IDEB_AI"], ci_mean_ideb_ai, label="IDEB_AI")
ax.plot(["IDEB_AF", "IDEB_AF"], ci_mean_ideb_af, label="IDEB_AF")
ax.legend()
plt.show()
A falta de intersecção nos intervalos acima mostra que para o intervalo de confiança escolhido (95%) a diferença entre as médias é estatisticamente significante.
In [6]:
g = sns.catplot(y='IDEB_AI', x='Ano', kind='violin', inner=None, data=df)
sns.swarmplot(y='IDEB_AI', x='Ano', color='k', size=3, data=df, ax=g.ax)
sns.lmplot(data=df, y='IDEB_AI', x='Ano')
Out[6]:
In [ ]:
In [7]:
#https://github.com/python-visualization/folium/tree/master/examples/data
for t in ("AI", "AF"):
for year in range(2007, 2018, 2):
m = folium.Map(location=[-16, -55], zoom_start=4, tiles='cartodbpositron')
state_data = df[df['Ano']==year][["UF", "IDEB_"+t]]
m.choropleth(
geo_data=open('uf.json', encoding="latin-1").read(),
name='choropleth',
data=state_data,
columns=['UF', 'IDEB_'+t],
key_on='feature.id',
fill_color='YlGn',
fill_opacity=0.7,
line_opacity=0.2,
legend_name='IDEB {} ({})'.format(t, year)
)
folium.LayerControl().add_to(m)
m.save(outfile="UF_{}_{}.html".format(t, year))
In [8]:
from IPython.display import IFrame
IFrame(src='uf_AI_2017.html', width=500, height=600)
Out[8]:
In [9]:
df['IDEB_AI_STD'] = 0.0
df['IDEB_AF_STD'] = 0.0
df['PE_MA2_STD'] = 0.0
df['TH_MA2_STD'] = 0.0
In [10]:
for year in range(2007, 2018, 2):
ideb_ai_year = df[df['Ano']==year]['IDEB_AI']
ideb_af_year = df[df['Ano']==year]['IDEB_AF']
pe_ma2_year = df[df['Ano']==year]['PE_MA2']
th_ma2_year = df[df['Ano']==year]['TH_MA2']
pe_ma4_year = df[df['Ano']==year]['PE_MA4']
th_ma4_year = df[df['Ano']==year]['TH_MA4']
df.loc[df['Ano']==year, 'IDEB_AI_STD'] = (ideb_ai_year - ideb_ai_year.mean()) / ideb_ai_year.std()
df.loc[df['Ano']==year, 'IDEB_AF_STD'] = (ideb_af_year - ideb_af_year.mean()) / ideb_af_year.std()
df.loc[df['Ano']==year, 'PE_MA2_STD'] = (pe_ma2_year - pe_ma2_year.mean() ) / pe_ma2_year.std()
df.loc[df['Ano']==year, 'TH_MA2_STD'] = (th_ma2_year - th_ma2_year.mean() ) / th_ma2_year.std()
df.loc[df['Ano']==year, 'PE_MA4_STD'] = (pe_ma4_year - pe_ma4_year.mean() ) / pe_ma4_year.std()
df.loc[df['Ano']==year, 'TH_MA4_STD'] = (th_ma4_year - th_ma4_year.mean() ) / th_ma4_year.std()
df.tail()
Out[10]:
In [11]:
sns.lmplot(data=df, y='IDEB_AI_STD', x='Ano')
Out[11]:
In [12]:
g = sns.catplot(y='IDEB_AF', x='Ano', kind='violin', inner=None, data=df)
sns.swarmplot(y='IDEB_AF', x='Ano', color='k', size=3, data=df, ax=g.ax)
sns.lmplot(data=df, y='IDEB_AF', x='Ano')
Out[12]:
In [13]:
from IPython.display import IFrame
IFrame(src='UF_AF_2017.html', width=500, height=600)
Out[13]:
In [14]:
sns.lmplot(data=df, y='IDEB_AF_STD', x='Ano')
Out[14]:
Nota-se que em tanto nos Anos Iniciais como nos Anos Finais existe um trend de crescimento da mediana das notas a cada ano, bem como uma progressiva expansão do range de distribuição de notas bem como uma ligeira migração da densidade para cima.
In [15]:
plt.figure()
sns.kdeplot(df["PE_MA2"], bw=1.5, label="% Pobreza Extrema MA(2)")
sns.kdeplot(df["PE_MA4"], bw=1.5, label="% Pobreza Extrema MA(4)")
Out[15]:
In [16]:
sns.catplot(y='PE_MA2', x='Ano', kind='box', data=df)
Out[16]:
In [17]:
sns.catplot(y='PE_MA4', x='Ano', kind='box', data=df)
Out[17]:
In [ ]:
In [18]:
plt.figure()
sns.distplot(df["TH_MA2"], hist=False, rug=True, label="Homicídios/1000 hab MA(2)")
sns.distplot(df["TH_MA4"], hist=False, rug=True, label="Homicídios/1000 hab MA(4)")
Out[18]:
In [19]:
sns.catplot(y='TH_MA2', x='Ano', kind='box', data=df)
Out[19]:
In [20]:
sns.catplot(y='TH_MA4', x='Ano', kind='box', data=df)
Out[20]:
In [ ]:
In [21]:
plt.figure()
sns.lmplot(data=df, x="PE_MA2", y="IDEB_AI_STD")
sns.lmplot(data=df, x="PE_MA2", y="IDEB_AI_STD", hue="Ano")
sns.lmplot(data=df, x="PE_MA4", y="IDEB_AI_STD", hue="Ano")
sns.lmplot(data=df, x="TH_MA2", y="IDEB_AI_STD")
sns.lmplot(data=df, x="TH_MA2", y="IDEB_AI_STD", hue="Ano")
sns.lmplot(data=df, x="TH_MA4", y="IDEB_AI_STD", hue="Ano")
Out[21]:
In [22]:
formula = "IDEB_AI ~ TH_MA2 * PE_MA2"
model = ols(formula, df).fit()
model.summary()
Out[22]:
In [23]:
formula = "IDEB_AI_STD ~ TH_MA2 * PE_MA2"
model = ols(formula, df).fit()
model.summary()
Out[23]:
In [24]:
formula = "IDEB_AI_STD ~ TH_MA2_STD * PE_MA2_STD"
model = ols(formula, df).fit()
model.summary()
Out[24]:
In [25]:
resids = {'year':[]}
l = []
for year in range(2007, 2018, 2):
l.append(model.resid.values[df["Ano"]==year].tolist())
for i in range(len(l[0])):
resids['year'].append(year)
resids['residual'] = [item for sublist in l for item in sublist]
df_resids = pd.DataFrame.from_dict(resids)
df_resids.plot.scatter(x='year', y='residual', c='DarkBlue')
Out[25]:
In [ ]:
In [ ]:
In [ ]:
In [26]:
formula = "IDEB_AI ~ TH_MA4 * PE_MA4"
model = ols(formula, df).fit()
model.summary()
Out[26]:
In [27]:
formula = "IDEB_AI_STD ~ TH_MA4 * PE_MA4"
model = ols(formula, df).fit()
model.summary()
Out[27]:
In [28]:
formula = "IDEB_AI_STD ~ TH_MA4_STD * PE_MA4_STD"
model = ols(formula, df).fit()
model.summary()
Out[28]:
In [29]:
resids = {'year':[]}
l = []
for year in range(2007, 2018, 2):
l.append(model.resid.values[df["Ano"]==year].tolist())
for i in range(len(l[0])):
resids['year'].append(year)
resids['residual'] = [item for sublist in l for item in sublist]
df_resids = pd.DataFrame.from_dict(resids)
df_resids.plot.scatter(x='year', y='residual', c='DarkBlue')
Out[29]:
In [ ]:
In [ ]:
In [30]:
formula = "IDEB_AF_STD ~ TH_MA2 * PE_MA2"
model = ols(formula, df).fit()
model.summary()
Out[30]:
In [31]:
formula = "IDEB_AF_STD ~ TH_MA4_STD * PE_MA4_STD"
model = ols(formula, df).fit()
model.summary()
Out[31]:
In [ ]:
In [32]:
from pymc3 import *
In [39]:
with Model() as unpooled_model:
# Priors
#sigma = HalfCauchy('sigma', beta=10., testval=1.)
#intercept = Normal('Intercept', 0., sd=20.)
#beta_pe = Normal('beta_pe', 0., sd=20.)
#beta_th = Normal('beta_th', 0., sd=20.)
#beta_peth = Normal('beta_peth', 0., sd=30.)
# Model
#ideb = intercept + beta_pe * df.PE_MA2_STD.values + beta_th * df.TH_MA2_STD.values + beta_peth * df.TH_MA2_STD.values * df.PE_MA2_STD.values
# Likelihood
#likelihood = Normal('y', mu=ideb, sd=sigma, observed=df.IDEB_AI_STD)
GLM.from_formula("IDEB_AF_STD ~ TH_MA2_STD * PE_MA2_STD", df)
# Inference
trace = sample(1000, tune=500, cores=3)
In [63]:
plt.figure(figsize=(7,7))
traceplot(trace,
lines={k: v['mean'] for k, v in pm.summary(traces[-1000:]).iterrows()})
plt.tight_layout()
In [61]:
years = sorted(df.Ano.unique())
year_idx = df.Ano.values - 2007
year_idx = list(map(lambda x: x//2, year_idx))
n_years = len(years)
#print(n_years, year_idx)
with Model() as hmodel:
# Hyper-Priors
sigma_intercept = HalfCauchy('sigma_intercept', 2.)
sigma_pe = HalfCauchy('sigma_pe', 2.)
sigma_th = HalfCauchy('sigma_th', 2.)
sigma_peth = HalfCauchy('sigma_peth', 2.)
mu_intercept = Normal('mu_intercept', mu=0., sd=4)
mu_pe = Normal('mu_pe', mu=-0.3, sd=2)
mu_th = Normal('mu_th', mu=-0.5, sd=2)
mu_peth = Normal('mu_peth', mu=-0.2, sd=2)
# Priors
intercept = Normal('intercept', mu=mu_intercept, sd=sigma_intercept, shape=n_years)
beta_pe = Normal('beta_pe', mu=mu_pe, sd=sigma_pe, shape=n_years)
beta_th = Normal('beta_th', mu=mu_th, sd=sigma_th, shape=n_years)
beta_peth = Normal('beta_peth', mu=mu_peth, sd=sigma_peth, shape=n_years)
eps = HalfCauchy('eps', 2.)
# Model
ideb = intercept[year_idx] + beta_pe[year_idx] * df.PE_MA2_STD.values + beta_th[year_idx] * df.TH_MA2_STD.values + beta_peth[year_idx] * df.TH_MA2_STD.values * df.PE_MA2_STD.values
# Likelihood
likelihood = Normal('y', mu=ideb, sd=eps, observed=df.IDEB_AI_STD)
# Inference
trace = sample(500, tune=200, cores=1)
In [66]:
plt.figure(figsize=(7,7))
traceplot(trace,
lines={k: v['mean'] for k, v in summary(trace[-300:]).iterrows()})
plt.tight_layout()
In [ ]:
In [ ]:
A análise realizada aqui nos fornece evidências que o impacto de fatores sócio-econômicos possuem num indicador como o IDEB dentro das unidades da federação Brasileira. Esses impactos podem ser até mesmo maiores que os fatores diretamente ligados a educação, principalmente nos anos iniciais.
In [ ]: