Cookies, sessions e formulários na web. Navegue na internet com o R!

Autores: Leonardo Sangali Barone e Rogério Jerônimo Barbosa

Imagem1

Este post é baseado no Tutorial 8 do curso de Web Scraping com R, ofertado no programa MQ da UFMG. É parte de um conjunto de materiais sobre o assunto, todos eles disponíveis nesta página do GitHub aqui.

Ensinaremos aqui como coletar e raspar conteúdos de páginas da internet que contém um formulário. E utilizaremos como exemplo o buscador do Google. Mecanismos de busca (Google, DuckDuckGo, etc) têm formulários nas suas páginas iniciais. Portais de notícia ou de Legislativos têm formulários de busca (como o que usamos manualmente no caso da Folha de São Paulo). Por vezes, mesmo para “passar” de página nos deparamos com um formulário.

Vamos ensinar então como preencher um formulário, enviá-lo ao servidor da página e capturar sua resposta.

Cookies e Sessions

Guarde bem essas duas palavras: cookies e sessions. Elas representam conceitos fundamentais para uma adequada compreensão sobre o funcionamento da internet, dos navegadores – e importantíssimos para a raspagem de dados ( Web Scraping ) de certas páginas.

Cookies são pequenos arquivos de texto que guardam informações necessárias para a sua navegação. Por exemplo: se você vai até o site do IBGE e escolhe a opção de vê-lo na versão em inglês, como o IBGE sabe que a partir dali todas as próximas páginas e opções também deverão ser apresentadas em inglês? No momento em que você clicou naquela opção, o seu navegador automaticamente baixou um arquivo que guarda características e opções que serão usadas novamente depois. Frequentemente, é também por meio de cookies que são guardadas informações sobre o que está na sua “cesta de compras”, quando você marca produtos que deseja adquirir num site de vendas. Cookies são muito úteis e importantes – essenciais para a navegação.

Até agora, quando queremos raspar dados de uma lista com várias páginas de resultado, fizemos sempre alterações na própria URL, informando o número da página que desejamos acessar. Mas nem sempre isso é possível, pois nem todos os sites guardam no próprio endereço a informação sobre o número da página em que estamos. Não raro, essa informação está guardada num cookie! Sim, um pequeno arquivo de texto, guardado em algum lugar do seu próprio computador, traz informações que serão dinamicamente acessadas por seu navegador e atualizadas.

Talvez você já tenha ouvido algo bastante ruim sobre cookies por aí… dizendo até que são usados por hackers etc. A história é mais complicada do que isso… A princípio, somente o site que gerou o cookie pode consultá-lo para saber sobre suas opções. Mas, às vezes, esse site pode passar essas informações para outro (várias empresas são associadas, certo?). Então, quando você vai até a Amazon e escolhe alguns produtos para sua cesta, pode ser que, algum tempo depois você veja aqueles mesmos itens num anúncio na página do Google ou até de outro lugar. Provavelmente aquela informação estava num cookie e a Amazon pode ter liberado o acesso para outra empresa. O objetivo, é tornar sua navegação mais customizada e personalizada, oferecendo para você apenas o que é relevante. As empresas querem vender para você aquilo que você realmente tem probabilidade de comprar…

Este pequeno vídeo aqui (em inglês) traz um bom resumo e panorama sobre o que são cookies. Quer algo um pouquinho mais técnico? Veja este curto vídeo aqui então.

“Roubar” informações de cookies é possível. Mas não é isso o que está ocorrendo quando você visita um site e os anúncios de coisas que você já viu estão lá. Quer saber mais sobre roubo de Cookies? Veja este vídeo aqui.

Cookies, no entanto, devem ser pequenos. Afinal, são informações continuamente trocadas entre você (cliente) e o computador que armazena o site no qual você navega (servidor). Se ele fosse um arquivo grande, o fluxo de uploads e downloads seriam muito intenso e a navegação se tornaria muito mais lenta. Por esta razão, existem sessions, que servem para guardar conteúdos maiores.

Sessions são a relação estabelecida entre o servidor (o site) e o cliente (o seu navegador). Um arquivo ou um conjunto de arquivos guardam um complexo de informações sobre você – que vão muito além da capacidade dos cookies (que usualmente não podem ultrapassar 4kb). Essas informações podem estar guardadas tanto localmente (no seu próprio coputador) como remotamente (no servidor). Se estiverem guardadas localmente, a navegação é geralmente mais rápida – visto que você não precisa trocar requisições usualmente com o servidor.

Entenda as sessions como uma espécie de “conta” que você abre no servidor (dessas contas que uma pessoa pode abrir num estabelecimento de comércio e que guardam suas informações e interações). E os cookies são usados nesse caso apenas como uma espécie de ID (seu cartão de identidade) para registrar você frente ao servidor.

Quando você loga na sua conta de e-mail, está abrindo uma session. Está dizendo ao seu navegador para estabelecer essa relação duradoura com o servidor (o site do Gmail, por exemplo). Assim, quando você navega dentro do seu email, não precisa a todo momento fazer o login de novo. Suas informações estão guardadas nesse conjunto de arquivos que representa a session. E cookies serão frequentemente usados, para mostrar ao site do Gmail o seu ID.

Quer saber mais sobre sessions? Neste vídeo (em inglês) há uma rápida e intuitiva apresentação.

 

rvest, formulários e Google

Agora, com aqueles dois conceitos na ponta da língua – cookies e sessions – vamos passar às nossas análises.

Vamos começar carregando o pacotes rvest e outros pacotes convenientes:

library(rvest)  # para raspar as páginas
library(dplyr)  # para usarmos do pipe (e outras funções convenientes)
library(tibble) # para usarmos tibbles, ao invés de data.frames 

Vamos explorar o buscador do Google. Isso mesmo, vamos fazer uma busca no Google a partir do R! O buscador do Google é constituído basicamente de um campo de texto que deve ser preenchido e enviado de volta ao servidor. Quando temos que informar qualquer tipo de informação e enviar de volta (mesmo que seja apenas marcar uma opção de “ok”), estamos preenchendo um formulário.

Este é justamente um caso em que termemos estabelecer uma conexão com o servidor. O Google exige o estabelecimento de uma session – e isso é feito antes mesmo de capturar a página na qual o formulário está.

Utilizamos a função html_session para isso:

google_url     <- "https://www.google.com"
google_session <- html_session(google_url)

Estabelecida a conexão, precisamos conhecer o formulário. Começamos, obviamente, obtendo o código HTML da página do formulário, tal como sempre fizemos. Mas desta vez, ao invés de passar a própria URL da página como argumento principal da função, passamos o objeto que contém as informações da session estabelecida.

Veja: o objeto google_session guarda, além das informações sobre a conexão, também o próprio conteúdo HTML.

read_html(google_session)
## {xml_document}
## <html itemscope="" itemtype="http://schema.org/WebPage" lang="pt-BR">
## [1] <head>\n<meta content="text/html; charset=UTF-8" http-equiv="Content ...
## [2] <body bgcolor="#fff">\n<script nonce="/xD7FQZxN1unWovhhSu33A==">(fun ...

O objeto google_session pode ser alvo de nossas atividades de raspagem e coleta, sem que precisemos executar sobre ele novamente a extração do conteúdo HTML. Esse conteúdo já está lá!

Se quiséssemos raspar todos os links da página, faríamos:

html_nodes(google_session, xpath = "//a") %>% head()
## {xml_nodeset (6)}
## [1] <a class="gb1" href="https://www.google.com.br/imghp?hl=pt-BR&amp;ta ...
## [2] <a class="gb1" href="https://maps.google.com.br/maps?hl=pt-BR&amp;ta ...
## [3] <a class="gb1" href="https://play.google.com/?hl=pt-BR&amp;tab=w8">P ...
## [4] <a class="gb1" href="https://www.youtube.com/?gl=BR&amp;tab=w1">YouT ...
## [5] <a class="gb1" href="https://news.google.com.br/nwshp?hl=pt-BR&amp;t ...
## [6] <a class="gb1" href="https://mail.google.com/mail/?tab=wm">Gmail</a>

Nesse caso, nosso interesse é extrair formulário, isto é o trecho de HTML que contém o campo de busca onde digitamos o que queremos que o Google encontre para nós. Como tabelas em HTML, fomrulários tem suas tags próprias: html <form> e html </form>. E contamos, no pacote rvest, com uma função que extrai uma lista contendo todos os formulários da página:

google_form_list <- html_form(google_session)
google_form_list
## [[1]]
## <form> 'f' (GET /search)
##   <input hidden> 'ie': ISO-8859-1
##   <input hidden> 'hl': pt-BR
##   <input hidden> 'source': hp
##   <input hidden> 'biw': 
##   <input hidden> 'bih': 
##   <input text> 'q': 
##   <input submit> 'btnG': Pesquisa Google
##   <input submit> 'btnI': Estou com sorte
##   <input hidden> 'gbv': 1

O resultado da função html_form é uma lista (observe o [[1]] no topo dos resultados), tal como também ocorria no html_table.

No caso do buscador da Google, há apenas um formulário na página. Com dois colchetes, extraímos então o item que está na primeira posição da lista de formulários.

google_form <- google_form_list[[1]]

class(google_form)
## [1] "form"
google_form
## <form> 'f' (GET /search)
##   <input hidden> 'ie': ISO-8859-1
##   <input hidden> 'hl': pt-BR
##   <input hidden> 'source': hp
##   <input hidden> 'biw': 
##   <input hidden> 'bih': 
##   <input text> 'q': 
##   <input submit> 'btnG': Pesquisa Google
##   <input submit> 'btnI': Estou com sorte
##   <input hidden> 'gbv': 1

Examine o objeto que contém o formulário. Ele é um objeto da classe “form” e podemos observar todos os parâmetros que o compõe, ou seja, tudo aquilo que pode ser preenchido para envio ao servidor, ademais dos botões de submissão.

Vá para o navegador e inspecione a caixa de busca da Google e os botões de busca e “Estou com sorte”. Você observará que cada “campo” do formulário é uma tag “input”. O atributo “type”, define se será oculto (“hidden”), texto (“text”) ou botão de submissão (“submit”). Por sua vez, o atributo “name” dá nome ao campo.

Alguns “inputs” já contêm valores (no atributo “values”). No nosso exemplo, os botões e campos ocultos. Estes últimos jáidentificaram o idioma (“hl”) e o enconding (“ie”) com o qual trabalhamos. Ou seja, o Google já deixou preenchidas partes do formulário!!. É por esta razão que recebemos resultados preferencialmente em português e relacionados a sites brasileiros!

O que nos interesse preencher, obviamente, é o “input” chamado “q”. Em várias ferramentas de busca, “q” (acronismo para “query”) é a caixa de texto onde fazemos a busca.

Vamos, então, preencher o campo “q” com a função set_values:

google_form <- set_values(google_form,
                          'q' = "merenda")

Simples, não? Colocamos o objeto do formulário no primeiro parâmetro da função e os campos a serem preenchidos na sequência, tal como no exemplo.

Reexamine agora o formulário. Você verá que “q” está preenchido:

google_form
## <form> 'f' (GET /search)
##   <input hidden> 'ie': ISO-8859-1
##   <input hidden> 'hl': pt-BR
##   <input hidden> 'source': hp
##   <input hidden> 'biw': 
##   <input hidden> 'bih': 
##   <input text> 'q': merenda
##   <input submit> 'btnG': Pesquisa Google
##   <input submit> 'btnI': Estou com sorte
##   <input hidden> 'gbv': 1

Legal! Agora vamos fazer a submissão do formulário. No buscador da Google, há duas possibilidades de submissão. Vamos usar “Pesquisa Google” e não “Estou com sorte”. Na submit_form, precismos informar a sessão que criamos (conexão com o servidor), o formulário que vamos submeter e o nome do botão de submissão.

Foi por isso, desde o início, que criamos a session! O argumento principal da função do rvest que faz a submissão do formulário requer necessariamente que você informe a session.

Veja o exemplo:

google_submission <- submit_form(session  = google_session, 
                                 form     = google_form, 
                                 submit   = "btnG")

Pronto! Fizemos a submissão do formulário. Notou o argumento submit = "btnG"? Ele é justamente o valor que estava no atributo <input submit> do formulário. Já falamos dele. Dê uma checada. Ele é como se fosse o nosso botão de “OK”, que envia a busca. Temos que informar isso! E note que há duas possibilidades de submissão nesse formulário: a “Pesquisa Google”, que é a busca tradicional, e a “Estou com Sorte”. Essas duas opções também existem no seu navegador.

Como output da submissão, recebemos um resultado, salvo agora no objeto google_submission. Mas que objeto é esse? Nos termos da linguagem R, de que classe ele é?

Ora! Vejamos:

class(google_submission)
## [1] "session"

Ele é uma session! Tal como também era nosso objeto google_session. Isso significa que então nossa relação duradoura com o Google está mantida, nossa conexão está estabelecida. O Google, por meio de cookies e outras informações, têm então memória dos passos anteriores que percorremos até aqui. Sabe que estivemos numa página anterior e que submetemos um termo de busca.

Tudo se passa como se tivessemos digitado algo para pesquisar no google (no caso, “merenda”), e então clicado no botão “Pesquisa Google” ou apertado a tecla Enter. O resultado dessa ação vai ser a navegação até outra página, onde agora estão exibidos os resultados da pesquisa. Você já não está mais na mesma página. Você navegou com o R!! E a página que obtivemos está guardada no objeto que resulta da função submit_form, juntamente com as informações sobre sua conexão (afinal, trata-se de uma session).

Veja:

read_html(google_submission)
## {xml_document}
## <html itemscope="" itemtype="http://schema.org/SearchResultsPage" lang="pt-BR">
## [1] <head>\n<meta content="text/html; charset=UTF-8" http-equiv="Content ...
## [2] <body class="hsrp" bgcolor="#ffffff" marginheight="0" marginwidth="0 ...

Agora basta raspar o resultado como já haviámos feito antes. Como você já sabe, podemos aplicar nossas operações diretamente no objeto que resulta da session, sem a necessidade de utilizar a função read_html.

Faça no seu navegados (fora do R) a mesma busca utilizando o Google. Examine a página, inspecione o código fonte. E então, tente entender o código abaixo:

nodes_resultados <- html_nodes(google_submission, xpath = "//h3/a")

titulos <- html_text(nodes_resultados)
links   <- html_attr(nodes_resultados, name = "href")
links   <- paste0("https://www.google.com", links)

Os títulos dos resultados de busca estão em tags do tipo h3. E as tags ‘a’ são “filhas” (child) das tags dos títulos. Já vimos isso antes várias vezes. Então você já sabe o que fazer. Certo? (se ainda tiver dúvidas, veja os quatro primeiros tutoriais desta série de materiais aqui).

Certo… Mas como você deve saber por sua experiência prática com o buscador, os resultados de uma busca no Google não são exibidos numa única página. Há várias páginas de resultado. Temos que clicar em “Mais” (veja no seu navegador).

Inspecione a estrutura esse link, clicando com o botão direito sobre ele e selecionando a opção “Inspecionar” (ou equivalente) em seu navegador. Você vai notar que a tag ‘a’ desse link traz um atributo “class” com valor igual a “pn”. Então este é, aparentemente, o link em que queremos clicar para ir para as próximas páginas, certo?

Vejamos se esse link existe no nosso objeto do R:

html_nodes(google_submission, xpath = "//a[@class='pn']")
## {xml_nodeset (0)}

Vixe… não existe! Mas como isso é possível!?

Ocorre que a página que está guardada dentro do nosso objeto google_submission não é exatamente idêntica àquela que está no seu navegador. A session aberta entre o Google e o R não é a mesma session entre o Google e seu navegador. Você provavelmente já utilizou o Google várias vezes no seu navegador – e, em algum lugar do seu computador, há cookies e outros arquivos que registraram parte das interações e opções que você selecionou no passado. E a estrutura HTML gerada pelos resultados da busca no Google varia de acordo com isso.

Mas então como saber onde está o nosso link “Mais”, no qual poderíamos clicar para ir para as próximas páginas de resultados?

Uma forma simples de saber é a seguinte.

  1. Extraia o conteúdo HTML da página de resultados com a função read_html.
  2. Usando a função as.character, transforme esse objeto (que pertence simultâneamente às classes xml_document e xml_node) num vetor de tipo character
  3. Usando a função writeLines, salve o conteúdo desse vetor num arquivo de texto com a extensão .html.
  4. Abra esse arquivo salvo por você no navegador e inspecione o link “Mais”

Com isso, garantimos que a página inspecionada é mesmo aquela que foi coletada pelo R, usando de nossa session:

pagina <- read_html(google_submission)
pagina <- as.character(pagina)
writeLines(pagina, "/users/rogerio/desktop/pagina.html")

Inspecionou? Encontrou a tag ‘a’ que contém o link “Mais”? O atributo “class” dessa tag tem valor igual a “fl” e não “pn”, como tínhamos visto antes.

O problema, vejam, é que há muitas tags ‘a’ com html @class="fl":

html_nodes(google_submission, xpath = '//a[@class="fl"]') %>% head()
## {xml_nodeset (6)}
## [1] <a class="fl" href="/search?q=merenda&amp;hl=pt-BR&amp;gbv=1&amp;ie= ...
## [2] <a class="fl" href="/search?q=merenda&amp;hl=pt-BR&amp;gbv=1&amp;ie= ...
## [3] <a class="fl" href="/search?q=merenda&amp;hl=pt-BR&amp;gbv=1&amp;ie= ...
## [4] <a class="fl" href="/search?q=merenda&amp;hl=pt-BR&amp;gbv=1&amp;ie= ...
## [5] <a class="fl" href="/search?q=merenda&amp;hl=pt-BR&amp;gbv=1&amp;ie= ...
## [6] <a class="fl" href="/search?q=merenda&amp;hl=pt-BR&amp;gbv=1&amp;ie= ...

Qual delas queremos? É melhor dar uma inspecionada novamente e sermos mais específicos.

Veja agora abaixo. Que tal isso?

html_nodes(google_submission, xpath = '//td[@class="b"]/a[@class="fl"]')
## {xml_nodeset (1)}
## [1] <a class="fl" href="/search?q=merenda&amp;hl=pt-BR&amp;gbv=1&amp;ie= ...

Parece que deu certo. Temos apenas um resultado. Mas como saber, como ter certeza? É só verificar se de fato o conteúdo da tag é a palavra “Mais”:

link = html_nodes(google_submission, xpath = '//td[@class="b"]/a[@class="fl"]')
html_text(link)
## [1] "Mais"

Viva! Encontramos o link para ir para a próxima página. Haveria, contudo, várias formas de obter esse mesmo link – usando tanto XPath como CSS. Você consegue compreeender a linha abaixo, que gera o mesmo resultado?

html_nodes(google_submission, xpath = "//span[text()='Mais']/..")
## {xml_nodeset (1)}
## [1] <a class="fl" href="/search?q=merenda&amp;hl=pt-BR&amp;gbv=1&amp;ie= ...

Agora temos é que clicar no link e segui-lo, para chegar até a próxima página de resultados. Fazemos isso com a função follow_link():

google_submission_page2 <- follow_link(google_submission, xpath = "//span[text()='Mais']/..")
## Navigating to /search?q=merenda&hl=pt-BR&gbv=1&ie=UTF-8&prmd=ivns&ei=WY9XW8WvFYWGwgTrg7GwBg&start=10&sa=N

Como você pode imaginar, a classe desse objeto é, novamente, uma session:

class(google_submission_page2)
## [1] "session"

Se é uma session, continuamos conectados. Mas agora, estamos na página 2. Então podemos coletar os novos resultados:

nodes_resultados2 <- html_nodes(google_submission_page2, xpath = "//h3/a")

titulos2 <- html_text(nodes_resultados2)
links2   <- html_attr(nodes_resultados2, name = "href")
links2   <- paste0("https://www.google.com", links)

Você está literalmente navegando na internet com o R, clicando em links e até mesmo fazendo pesquisa no Google! Lindo, não?

Que tal fazer um loop para coletar as primeiras 10 páginas de resultado então?

google_url <- "https://www.google.com"

# Estabelecendo a conexão e coletando a primeira página
google_session <- html_session(google_url)

# Raspando o formulário, retirando-o da lista e preenchendo o campo de busca 
google_form <- html_form(google_session)[[1]]
google_form <- set_values(google_form, 
                          'q' = "merenda")

# Submetendo os resultados (usando o botão da "Pesquisa Google", o "btnG")
google_session <- submit_form(session = google_session, 
                              form    = google_form,
                              submit  = "btnG")

data_resultados <- data_frame()
for(i in 1:10){

        print(i)

        # Coletando os nodes dos resultados
        nodes_resultados <- html_nodes(google_session, xpath = "//h3/a")

        # Raspando títulos e links
        titulos <- html_text(nodes_resultados)
        links   <- html_attr(nodes_resultados, name = "href") %>% 
                paste0("https://www.google.com", .)

        # Compilando os resultados num data frame
        data_resultados <- bind_rows(data_resultados,
                                     data_frame(titulos, links))

        # Navegando até a próxima página
        google_session <- follow_link(google_session, xpath = '//span[text()="Mais"]/..')

        # Um tempinho para o navegador respirar, carregar a página (e o Google não nos 
        # bloquear por excesso de requições)
        Sys.sleep(.5)

}

Vejamos agora os nossos links coletados das 10 primeiras páginas de resultados do Google:

data_resultados
## # A tibble: 100 x 2
##    titulos                             links                              
##    <chr>                               <chr>                              
##  1 Sistema Merenda Escolar             https://www.google.com/url?q=http:~
##  2 Merenda  Wikipédia, a enciclopédi~ https://www.google.com/url?q=https~
##  3 Notícias sobre merenda              https://www.google.com/search?q=me~
##  4 Empresas fraudavam licitações de m~ https://www.google.com/url?q=https~
##  5 MERENDA - YouTube                   https://www.google.com/url?q=https~
##  6 Imagens de merenda                  https://www.google.com/search?q=me~
##  7 Cartel desviou mais de R$ 1,6 bi d~ https://www.google.com/url?q=http:~
##  8 Sinônimo de Merenda - Sinônimos     https://www.google.com/url?q=https~
##  9 Merenda Escolar - Ministério da Ed~ https://www.google.com/url?q=http:~
## 10 Crianças tiram foto com merenda e ~ https://www.google.com/url?q=http:~
## # ... with 90 more rows

Decifrando as eleições

CEPESP

As eleições de 2018 já começaram e nós do CEPESP, da FGV, temos um desafio: que tal decifrar as eleições brasileiras? Apresentamos aqui o 1º Desafio CEPESPData -> Decifrando as eleições.

Nosso objetivo é mobilizar programadores, cientistas políticos, economistas, hackers e interessados em geral para a proposição de soluções abertas de visualização e de ferramentas de busca nas bases administradas pelo CEPESPData, além da possibilidade de integração com outras bases de dados públicos.

Entendemos que este é o momento ideal para liberar a criatividade numa base de dados grande e muito importante.

Conheça o site –> CEPEPSData

2x2_Desafio_CEPESPdata

Todas as soluções propostas devem ser apresentadas em softwares livres, código aberto e fazer uso da API do CEPESPData.

Será permitida a inscrição de indivíduos ou equipes e serão oferecidas duas premiações: R$10.000 para o primeiro colocado e R$5.000 para o segundo colocado.

Mais informações serão disponibilizadas na abertura das inscrições, no…

Ver o post original 203 mais palavras

Uma forma rápida de inverter as barras no R (“\” para “/”).

Não existe coisa mais chata que inverter as barras para atribuir os diretórios de trabalho na programação em R. O Windows utiliza as barras invertidas (“\”) para separar as pastas de trabalho, desse modo:

“C:\Program Files\R\R-3.3.1\”

Contudo, quando estamos trabalhando com o R, a barra invertida é utilizada para outro propósito, como “escape sequence”. Basicamente, tudo que vem depois de uma barra invertida é a indicação de um caractere especial, como quebra de linha (“\n”) ou TAB (“\t”). O escape sequence também pode ser usado para representar caracteres que normalmente tem função especial como um caractere literal. Caso quisermos inserir as aspas simples ou aspas duplas em uma string, podemos simplesmente utilizar:

> cat(“a \” b”) # String como aspas duplas

a ” b

> cat(“a \’ b”) # String como aspas simples

a ‘ b

Por isso não podemos usar a barra invertida para descrever o caminho dos diretórios: o R irá entender todos os caracteres que vem depois das barras como indicação de alguma outra coisa. Existem duas soluções para isso. A primeira é colocar barras invertidas duplas. Assim, o R entenderá que o caractere especial que está à frente é um literal:

“C:\\Program Files\\R\\R-3.3.1\\”

Essa solução é trabalhosa e vejo poucas pessoas usando ela. Outra opção é usar barras normais (“/”) ao invés de barras invertidas:

“C:/Program Files/R/R-3.3.1/”

O problema é que mesmo inverter as barras pode ficar tedioso se você tem que fazer isso sempre, ainda mais quando temos que digitar caminhos longos, como por exemplo:

“C:\Users\Murilo Junqueira\Dropbox\Acadêmico e Educação\Doutorado\#Bancos de Dados\#BD Unificado\Rotinas R\”

Pensando nisso, pensei uma forma simples de evitar a tarefa monótona de inverter as barras nos comandos R. Utilizo uma de minhas aplicações favoritas: o AutoHotKey (AHK). O AHK é um software gratuito e open-source para automatizar tarefas repetitivas no MS Windows (usuários de Linux e Mac podem dar outra solução!). Ele basicamente consegue automatizar tudo que você faz com teclado, mouse ou joystick. Ele transforma todo seu trabalho de digitar teclas e clicar no mouse em códigos de programação. O AHK normalmente é utilizado para criar teclas de atalho personalizadas. Por exemplo, no meu computador eu consigo abrir o Bloco de Notas apenas apertando Control + Win + n. A ideia aqui é criar uma tecla de atalho que simplesmente pega o endereço que está copiado na memória do computador (que você salvou apertando Control + c) e inverter as barras quando você aperta outra tecla de atalho, como Control + Win +v. (não vamos mudar o tradicional Control + v para não causar confusão, ok?). Isso pode ser feito apenas com as seguintes linhas de código no AHK:

; Tudo que está depois do ponto e virgula (“;”), é comentário, não código.

;Primeiro vamos criar uma função que será disparada quando você

; apertar Control (“^”) + Win (“#”) + v

^#v::

; substitui todas as barras invertidas do clipboard por barras normais.

StringReplace, clipboard, clipboard, \,/,All

; coloca a string com as barras alteradas no clipboard.

Clipboard = %clipboard%

; manda um Control + v

send {CtrlDown}v{CtrlUp}

; Fim da função

return

Agora é só apertar um control + c no endereço do Windows e depois apertar Control + Win + v no seu script do R. Você perceberá que os endereço vão estar corretos. Durmo em paz pensando no tempo de vida que eu economizei depois dessa tecla de atalho.

O AHK ainda tem uma vantagem para aqueles que não querem aprender sua linguagem de programação: ele pode ser usado para criar programas customizados. Se você não quiser ter uma experiência mais “profunda” com o AHK, basta baixar e utilizar esse aplicativo, de minha autoria. Uma vez acionado o aplicativo, a função acima estará funcionando. Não é necessário nem instalar o AHK em seu computador, desde que ele esteja rodando em MS Windows. Veja o GIF abaixo.

Nesse mesmo link do aplicativo, você vai encontrar o arquivo apenas com o código de programação, o arquivo “InverteBarra.ahk”. Ele é aberto no bloco de notas, caso você quiser dar uma olhada.

De toda forma, pretendo postar mais truques com o AHK em outros posts. Super recomendo que todos baixem o AHK e tentem a usar os códigos.

Enjoy!

Quando podemos dizer que uma sociedade é mais ou menos desigual que outra? (homenagem à Atkinson, Parte 2)

Segundo da serieO primeiro pode ser conferido AQUI.


download

Quando podemos dizer que uma sociedade é  mais ou menos desigual que outra? Essa é a pergunta fundamental de Atkinson. em seu artigo “On the measurement of inequality(1970).

Existem muitas medidas de desigualdade, mas nem sempre elas coincidem ou convergem para as mesmas direções. Além disso, a sensibilidade de cada uma delas é bastante variável. Observem, por exemplo o gráfico abaixo, que mostra a evolução de três diferentes índices de desigualdades bastante utilizados.

fig1

A primeira coisa que se destaca é o escopo de variação de cada um deles. O Coeficiente de Gini pouco se move; por contraste, o Índice de Theil e a Variância do Log da Renda são muito mais sensíveis a mudanças. Em especial, a Variância do Log dá uma impressão de que uma revolução ocorreu a partir de 1990, principalmente depois do Plano Real e durante a década de 2000. Gini e Theil nos dizem, ao contrário, que os anos 1990 foram de grande estabilidade. Observando de perto, vemos ainda que os índices podem discordar com respeito às tendências: entre 1982 e 1983, o Gini e o Theil apontam queda, ao passo que a VarLog indica leve aumento.

Com essas disparidades, é como julgar se a desigualdade de renda aumenta ou diminui? Pior ainda: se dentro de um mesmo país e com a mesma fonte de dados observamos essas dissonâncias,  imaginem o problema implicado em dizer qual país é mais ou menos igualitário…


Desigualdade e bem-estar social

É necessário dar um passo atrás… e repensar o próprio conceito de desigualdade de renda subjacente a cada medida. Essa investida foi primeiramente feita por Hugh Dalton (artigo original AQUI). Ele definiu desigualdade como um déficit de bem-estar social, frente ao que seria possível com uma quantidade fixa de renda ou riqueza. Ou seja, qualquer sociedade desigual poderia atingir padrões de vida muito melhores se distribuísse sua riqueza de modo mais igualitário.

Noutras palavras, segundo essa perspectiva, o nível de desigualdade é um DIAGNÓSTICO CONTRAFACTUAL: trata-se de comparar a realidade existente e efetivamente observada com um modelo igualitário teoricamente possível. 

Na concepção de Dalton, tudo se passa como se um índice de desigualdade fosse calculado de acordo com a seguinte pseudo-equação:

fig1

De fato, Atkinson e outros estudiosos mostraram que toda medida de desigualdade pode ser matematicamente reduzida a uma fórmula semelhante a esta. A questão passa a ser então qual a noção de bem-estar embutida em cada índice.

Definir o bem-estar coletivo através de uma equação é necessariamente fazer inúmeras simplificações. Além disso, envolve dar pesos e importâncias ao que as pessoas vivem e sentem. De saída, parece algo absurdo até… (ainda que o absurdo nunca tenha sido barreira para os economistas).

O importante é ressaltar que qualquer índice de desigualdade de renda não é apenas uma medida de concentração ou dispersão; ao contrário implicitamente traz juízos normativos sobre quão justa ou injusta uma sociedade é — mesmo que o usuário do índice não saiba disso. Cabe inclusive destacar que o próprio Corrado Gini entendia que seu Coeficiente era meramente uma medida de Estatística descritiva e que, por isso, ficou bastante irritado com a leitura normativa proposta por Dalton (esse episódio é relatado por Atkinson e Brandolini — ver. págs 210 e 211).

Não há lugar livre de juízos de valor nas Ciências Sociais.


Matematizando o Bem-Estar social

Tomemos um exemplo simples: um indivíduo possui uma quantidade de dinheiro para gastar e suponhamos que no mundo só exista um único tipo de bem para gastar: carro. Assuma ainda que não é possível guardar dinheiro ou poupar para depois (ou seja necessariamente a pessoa gasta tudo o que tem). Nessa configuração, a quantidade adquirida de carros (denominada abaixo por x1) dependerá unica e exclusivamente dos preços (p1).

A equação abaixo indica apenas que a renda pessoal, nesse caso fictício onde se gastou tudo, é igual ao total de carros adquiridos vezes o preço:

fig1

Agora, de forma simplificada (simplista, até), podemos compreender a ideia de bem-estar econômico como sinônima da satisfação obtida por meio do consumo. Formalmente podemos escrever o seguinte:

fig2

U é a satisfação individual — “U” é para denotar o conceito de “Utilidade“, utilizado na Economia para expressar a ideia de satisfação.  Dizemos então que “U é uma função da quantidade de carros“. Mas que função seria essa? A título de exemplo, uma raiz quadrada serviria bem:

fig3

Por que diabos uma raiz quadrada? Bem… essa função tem uma propriedade bastante interessante: é sempre crescente, mas a taxas cada vez menores, vejam só:fig-6

Essa propriedade é muito conveniente para expressar de que modo seres humanos extraem satisfação de suas atividades. Vejam o exemplo abaixo:

fig4

O primeiro carro traz muita satisfação ao indivíduo, o segundo carro traz menos… e assim por diante. Em casos como esse, dizemos que os retornos marginais são decrescentes. Intuitivamente faz sentido, não? Infelizmente, com mais nos satisfazemos menos…

Suponha agora que todas as pessoas são iguais: que cada carro adicional traga os mesmos acréscimos de satisfação pessoal. Ou seja, suponha que socialmente todos os indivíduos tenham o mesmo valor (ninguém é mais ou menos importante) e que todos possuam a mesma função de utilidade (a raiz quadrada, nesse exemplo).

Nesse caso, a “Utilidade Social” (ou Bem-Estar Social) seria simplesmente a soma das utilidades individuais. Numa sociedade em que existissem indivíduos, teríamos:

fig5

Essa perspectiva é inspirada na filosofia Utilitarista, de Jeremy Bentham e outros.


Igualdade e maximização do Bem-estar

Por que Dalton pensava que a igualdade maximizaria o bem-estar social? A intuição, na realidade, é simples.

Imagine que existam 3 indivíduos numa sociedade e que eu tenha 4 carros para distribuir entre eles. Qual configuração faz com que a função de bem-estar social, definida conforme a seção anterior, atinja um valor maior?

  • Se dermos tudo para uma única pessoa, sua satisfação será \sqrt{4}=2. A satisfação dos demais será zero. Assim, o bem-estar social será 2+0+0=2.
  • Se primeiramente oferecemos um carro a cada pessoa e sorteamos o último restante para um deles, teremos:  \sqrt{2}+\sqrt{1}+\sqrt{1}=3,41.

A configuração mais igualitária gerou mais bem-estar social. 


A prioridade dos mais pobres e os diferentes graus de aversão à desigualdade

Essa propriedade decorre dos retornos marginais decrescentes, sobre os quais falamos anteriormente: o primeiro carro traz sempre grande acréscimo de satisfação/utilidade. Deste modo, dar o primeiro carro para todo mundo sempre maximizará o bem-estar social nesse exemplo.

Dizemos, nesse caso, que os mais pobres têm PRIORIDADE na função de bem-estar social — ou, que estamos assumindo uma postura prioritarista (Veja também AQUI).

Mas o grau de prioridade dos mais pobres pode variar… Isso depende da função de utilidade que aplicamos. Ao invés da raiz quadrada, poderíamos ter usado uma raiz cúbica… ou quarta… etc. Em verdade, podemos dar um exemplo um pouco mais geral e definir a função de utilidade individual como:

fig1

Onde k é um valor que pode ser definido ao gosto do analista. Quanto maior o seu valor, maior a prioridade dos mais pobres. Ou seja, maior é a satisfação relativa acrescentada pelo primeiro carro… Quando k=2, temos a raiz quadrada. Se k=3, temos a raiz cúbica… e assim por diante.

Quando k =1, todos os carros extras trazem a mesma satisfação. Ou seja, já não há mais prioridade dos mais pobres —  independentemente de como se distribuir os recursos, o valor da função de bem-estar será sempre o mesmo. Nesse caso, implicitamente estamos afirmando que a questão distributiva não tem qualquer importância.

Em suma, na equação acima, k é um parâmetro de aversão à desigualdade.


Comparando desigualdades…

Uma das contribuições de Atkinson foi mostrar que os índices de desigualdade trazem implicitamente alguma função de bem-estar social. Essa função pode assumir diversas formas, para além das descritas aqui (um logaritmo, uma parábola… etc).

O importante é que também de forma implícita há um parâmetro de aversão à desigualdade — ou, poderíamos dizer, de prioridade dos mais pobres. Atkinson mostrou que podemos explicitamente determinar esse valor e calibrar nosso índice, conforme nossas preferências em termos de justiça social.

Por que o Theil e a Variância do Log caíram mais rápido do que o Gini no Brasil? Porque são medidas que priorizam mais os pobres; e boa parte das transformações sociais no Brasil envolveram justamente a redução da pobreza e da miséria e o crescimento da classe média-baixa (a famosa “Classe C”).

Quando podemos dizer que uma sociedade é  mais ou menos desigual que outra? Bem… Diferentes índices trarão respostas distintas. É preciso fazer uma escolha, que é necessariamente ética, normativa e arbitrária.

Tony Atkinson (1944-2017) e os estudos sobre desigualdades – Parte 1

220px-tony_atkinson_-_festival_economia_2015O ano de 2017 iniciou mal, para os estudiosos das desigualdades. Já no dia 1 de janeiro, faleceu Anthony Atkinson, um dos pais fundadores dos modernos estudos de distribuição de renda. Devo dizer que fiquei realmente triste com a notícia — que me chegou através de um tweet de Branko Milanovic.

Em seu blog no Le Monde, Thomas Piketty, seu ex-aluno, publicou um respeitoso obituário, enfatizando o pioneirismo de Atkinson no estudo das tendências de longo prazo da concentração de renda entre os mais ricos (top incomes).

Mas fato é que Atkinson fez muito mais que isso — e julgo que sua principal contribuição aos estudos de desigualdade nem mesmo seja esta… Com um artigo intitulado On the measurement of inequality, publicado em  1970, ele assentou bases conceituais e metodológicas para a interpretação das tendências e índices de desigualdades.

É verdade que o campo de estudos sobre a concentração de rendimentos já vinha se formando desde o século XIX, com a obra de Vilfredo Pareto, teve importante inflexão com Hugh Dalton (em especial devido ao seu artigo de 1920) e recebeu muita atenção depois de Simon Kuznets (principalmente por causa de sua hipótese do “U invertido”, que apareceu em trabalho de 1955). Mas é apenas com Atkinson que as desigualdades de renda e seu significado empírico se tornam de fato um campo de estudos em si mesmo.

E é sobre seu texto seminal, de 1970, que vou tratar nesta série de posts que se inicia. Na realidade, trata-se de um pequeno curso de introdução à mensuração das desigualdades, para que seja possível compreender o trabalho de Atkinson propriamente.  Vejo vocês no próximo post. 

 

“As meias-verdades do ENEM por Escola”, de Chico Soares

31122013134435Reproduzo aqui o texto “As meias-verdades do ENEM por Escola”, de José Francisco Soares, ex-presidente do Inep, presidente da Câmara de Educação Básica no Conselho Nacional de Educação e professor titular aposentado da UFMG.

O texto foi originalmente publicado no site do Jeduca e posteriormente reproduzido também em outros lugares (como no blog do Simon Schwartzman)

 

O ranking do ENEM simplesmente consagra as escolas que fazem seleção de seus alunos. Entre as escolas bem classificadas, as privadas selecionam seus alunos pela renda e entre os que podem pagar escolhem os alunos que se saem bem em provas. Esta seleção interna é frequentemente feita ao longo da trajetória escolar dos alunos. A escola alega que o estudante não se adequou ao projeto pedagógico e convida os alunos seus alunos mais fracos a saírem As escolas públicas, que estão entre nas melhores colocações, são aquelas que admitem seus alunos através de difíceis vestibulares.

Depois da divulgação, as escolas privadas pertencentes a redes de ensino comprarão páginas de jornal para convencer as famílias que qualquer escola da rede é igualmente boa. Por outro lado, os gestores públicos das escolas bem classificadas darão declarações dizendo que o ensino público pode ser de excelência, não enfatizando nem a seleção nem o custo de suas escolas.

Em ambos os casos a sociedade recebe meias verdades. A dura realidade é que os projetos pedagógicos das escolas bem classificadas no ENEM são projetos excludentes socialmente, comuns em um Brasil que aceita, sem critica, dar tudo para poucos e nada para muitos.
Expor a fragilidade do argumento que a boa escola é aquela mais bem posicionada no ranking do ENEM, não deve obscurecer o fato de que, entre as escolas lideres, há projetos de muito boa qualidade pedagógica, que precisam ser conhecidos e que podem inspirar as mudanças que o sistema de educação básica brasileira precisa. Se a viabilidade destes projetos vem das boas condições de funcionamento e dos alunos selecionados, por outro lado são experiências feitas com estudantes e professores brasileiros, e, portanto, úteis para indicar formas de organização do ensino médio que podem ser usadas em escolas públicas abertas e todos os estudantes.

No entanto, a divulgação do ranking do ENEM, mesmo com suas limitações, permite discussões importantes pedagogicamente. Se a escola privada escolhida pela família for grande e mantiver seus alunos ao longo de sua trajetória escolar, não ficará nas primeiras posições do ranking. No entanto, manter os filhos nestas escolas é uma opção racional. Por um lado, garante-se um ambiente de formação humana mais diversificada, que o maior número de alunos permite, e, por outro lado, permite a convivência dos filhos com estudantes de alto desempenho, que serão uma fonte de desafio. Para identificar estas escolas o INEP criou dois indicadores. O primeiro mostra o percentual de alunos matriculados há vários anos na escola e o segundo é a média de desempenho dos 30 melhores alunos de cada escola.
Há escolas públicas e privadas que não selecionam seus alunos e cujo alunado é de baixo nível socioeconômico. Também há escolas privadas que acolhem número substancial de alunos bolsistas. As escolas com este perfil, cujos alunos tem bom desempenho, precisam ter seus projetos reconhecidos; outro efeito da divulgação do ranking, contextualizados com indicadores escolares e sociais.

Simulando o trânsito e os limites de velocidade

O pessoal do HackLab criou uma ferramenta simples e fácil de usar para mostrar as consequências de diferentes limites de velocidade sobre o fluxo do trânsito. Ela pode ser acessada AQUI NESSE LINK.

transito1

O usuário pode estabelecer limites entre 0 km/h e 90 km/h e ver o que ocorre com a velocidade média, fluxo em locais específicos etc. Trata-se de um “toy model“, muito simplificado (não há cruzamentos, semáforos, paradas, pedestres etc.)  — mas essa é justamente a grande virtude dessa simulação: mesmo com tantas simplificações, que a princípio deixariam o trânsito melhor, há um claro efeito negativo acarretado por altos limites de velocidade.

Modelos de simulação podem contribuir muito para pensar políticas públicas. Quer saber mais? Veja a série de posts sobre o assunto aqui: Parte 1, Parte 2, Parte 3 , Parte 4 e Parte 5.

O que penso sobre a Reforma do Ensino Médio

[post de opinião]

Há exatamente uma semana, no dia 22 de setembro de 2016, Temer trouxe a público a Medida Provisória 746/16 (MP), que reforma o Ensino Médio (EM). Estou até agora tentando formar algumas opiniões sobre isso. Reuni aqui algumas reflexões que consegui sistematizar. Mas dado o caráter recente de tudo isso, é difícil pisar com firmeza num solo que se revela bastante móvel…

Considero que a ideia subjacente à MP, de que há um “excesso” de conteúdos no EM que prejudica o desenvolvimento de habilidades básicas, é muito enviesada pela forma como se estruturam os sistemas de avaliação da educação. Esses testes padronizados geram indicadores de desempenho da administração pública – e foi justamente insuficiência de um indicador, o IDEB, que iniciou todo esse estardalhaço da MP. Considera-se como eixos básicos do conteúdo do EM principalmente a compreensão/expressão da linguagem e o raciocínio lógico-matemático – que, por exemplo, no SAEB são avaliados através das provas de Português e Matemática. O Programa Internacional de Avaliação de Alunos (PISA) chega a avaliar Ciências também. Mas não temos indicadores para outros conteúdos. Sem a pressão de maximizar os indicadores e elevar o Brasil nos rankings, há menos incentivo para investir nas demais disciplinas não avaliadas. Enxugar o ensino médio, é investir no que é visível nos indicadores, sem se preocupar com o que é invisível a eles.

O problema com a noção de “habilidades básicas” vai além. Certamente, interpretação de texto e raciocínio lógico são básicos no sentido de que sem esse mínimo não é possível compreender nada. No entanto, esse mínimo é tão mínimo que não permite interpretar a realidade social só com ele. Pra ler revistas, jornais, livros… pra votar, criticar, manifestar… compreender os próprios direitos, o sistema de justiça e saber acessar instituições… nada disso se faz só com o mínimo. As disciplinas de Ciências Humanas são fundamentais exatamente aí. Eu vi a nota do MEC dizendo que não vai tirar Sociologia, Filosofia etc… Mas lendo a MP, não fica nada claro como essas disciplinas vão realmente ficar.

Há também problemas na forma como se divide o currículo optativo em 5 áreas de ênfase. Isso cria um sistema de trackings que, de acordo com diversos estudos de Estratificação Social, pode gerar desigualdades cumulativas no ciclo de vida (ver, por exemplo, o estudo clássico de Samuel Lucas). Torna-se mais difícil mover-se entre carreiras em pontos avançados do curso de vida. Poderíamos dizer que a trajetória individual no mercado de trabalho pode acabar mais marcada por uma “dependência de trajetória” (path dependence). Fato é que um estudante de tempo integral e que cursa o tracking “de elite” (por exemplo, ciências da natureza) terá muito mais chances de vida do que aquele que cursar em tempo parcial um tracking não de elite (talvez ciências humanas ou vocacional). Num estudo bastante importante, Richard Arum e Yossi Shavit mostram que os trackings de ensino vocacional e técnico atraem estudantes que teriam, de fato, menos chances de entrar em universidades e originam-se das camadas mais baixas da população. Esse caminho minimizaria a incidência de desemprego e a incerteza no mercado de trabalho — o que é ótimo — , mas não garantiria mobilidade social ascendente. Isso tudo é particularmente mais preocupante no caso brasileiro dados os níveis astronômicos de desigualdades de oportunidades e de resultados. No mínimo, deveríamos ter mais estudos sobre isso.

O documento da MP é vago também quanto à extensão das mudanças. Quantas escolas passarão a operar em regime integral? Quantas no regime parcial? O governo informou posteriormente que a implantação do regime integral vai se dar aos poucos, seguindo as diretrizes do Plano Nacional de Educação (PNE) de 2014:

A carga horária mínima anual, de 800 horas, será gradualmente ampliada para 1,4 mil horas. O Plano Nacional de Educação (PNE) prevê para 2024 até 50% das escolas atendidas pelo ensino integral e 25% das matrículas no Ensino Fundamental dentro do mesmo modelo.

Mas se isso já estava no PNE, o que então a MP trouxe de novo nesse quesito. Vago… não!? Ainda restam outras indagações: Haverá oferta de todos os 5 trackings possíveis em todos os locais? Certamente não… Mas será que em todos os municípios haverá diversidade suficiente de trackings ofertados? Diversos ex-Ministros da educação se mostraram muito preocupados com esse ponto. A desigualdade de oferta de trackings e ensino integral/parcial pode reforçar desigualdades regionais (algo que já foi dito na nota lançada pelo Cenpeq e, em entrevista, pela dirigente dessa instituição, Maria Alice Setubal).

Dependendo de como for implantado, o Ensino Médio assim estratificado pode também aumentar as desigualdades através de um reforço de mecanismos de auto seleção. Em diversas reportagens que vi (por exemplo, aqui – ver trechos 00:10-00:26 e 04:00-04:40) e li por aí, encontrei declarações de alunos dizendo que vai ser ótimo poder evitar as “matérias difíceis”. Ora, essa ideia é muitíssimo problemática, uma vez que a noção de “dificuldade” está fortemente associada a condições socioeconômicas do aluno, condições da escola (infraestrutura, formação de professores, etc), além de raça e gênero. Mulheres e negros, por exemplo, são muito marcados pelo estigma de que não são tão bons em matemática quanto os homens brancos (há diversos estudos mostrando como essa “ameça dos estereótipos — stereotype threat — é construída e opera — ver, por exemplo, esse e esse trabalho de Claude Steele). A auto exclusão em relação às “matérias difíceis” leva à auto exclusão com respeito às carreiras mais rentáveis.

Outro ponto que não compreendo é de que forma toda essa reforma se casa com a proposta do atual governo de enxugar os gastos. O estabelecimento do ensino em tempo integral envolve duplicação da jornada de alguns funcionários da escola, necessidade de infra-estrutura para atender todos os alunos de uma só vez (que anteriormente poderiam estar divididos em turnos diurnos, verspertinos e noturnos), necessidade de fornecer alimentação/merenda mais vezes. Promover todas essas mudanças será muito custoso para o Estado. E fico aqui me indagando: Isso não é contraditório com a PEC 241, que fixa o valor dos gastos públicos aos níveis de 2016 (ano de crise fiscal), ajustando-os apenas pela inflação (IPCA)? Fica o receio de que tudo seja feito de forma torta, na expectativa de mudar e economizar ao mesmo tempo… Especulando um tanto, podemos imaginar o quanto a mão de organizações privadas vai entrar pesado. Não há algo necessariamente ruim na gestão privada da educação pública. Mas o compromisso das instituições de mercado em promover igualdade educacional esbarra na vontade de maximizar o lucro. Se não houver forte regulação aí, investimentos diferenciais e concentração de recursos podem gerar mais desigualdade também. De todo modo, até as escolas privadas estão preocupadas com o aumento de custos que a implantação súbita do modelo de turno integral pode acarretar. Turno integral pode significar a duplicação das mensalidades — o que, por consequência, pode expulsar os alunos menos bem abastados (gerando desigualdade) e até mesmo levar à falência de algumas escolas, devido ao súbito aumento de preços num contexto em que a demanda por educação é fixa.

Por fim, penso que o formato atual do Ensino Médio estava mesmo problemático (pra não dizer falido) e uma reforma era mesmo necessária. Mas eu esperava algo parecido com o pacto que se teceu com a LDB de 1996, e não algo vindo do alto, com um som tecnocrático e impositivo — esse é o ponto enfatizado também pela Associação Nacional de Pós-Graduação em Filosofia (Anpof), em nota de repúdio divulgada no dia posterior à MP. Já havia um Projeto de Lei em tramitação no Congresso sobre a Reforma do Ensino Médio (PL 6840/2013), que se movia lentamente, sem nenhuma urgência (não estou dizendo que o projeto era bom, mas que existia e poderia ser trabalhado). De repente, pá! É tudo pra ontem…

A proposta atual não é feita apenas de defeitos, claro. Ela advém de discussões e sugestões feitas por um conjunto de especialistas ligado ao Conselho Nacional dos Secretários de Educação (Consed) – e havia pessoas brilhantes e muitíssimo sérias lá dentro.A proposta foi fechada e apresentada em março deste ano. Uma série de documentos foi trazida a público (disponíveis aqui). No entanto, por mais inteligente que fosse essa intelligentsia, para construir legitimidade política é necessário discutir. Não sei se o Temer tomou o documento do Consed com o consentimento de quem o formulou… A princípio, acredito que esperavam que a Reforma viria através de uma ampla reformulação do Projeto de Lei 6840/2013, citado acima. Haviam até preparado uma nova versão dele, comentada. Essa versão acabou subsidiando a MP.

Agora, em meio aos atropelos, a cada dia temos novos capítulos: o Supremo Tribunal Federal recebe ações contra a MP; o PSOL entra com uma Ação Direta de Inconstitucionalidade De um lado, alegando falta de diálogo, a Confederação Nacional dos Trabalhadores da Educação se recusa a sugerir emendas a algo que considera ilegítimo… De outro lado, uma turba descontrolada vê esse momento como grande oportunidade de pendurar uma série de adendos que lhes atendam; e, até agora, a MP já acumula mais de 180 propostas de emendas.

 

Banco de dados da Pesquisa Dimensões Sociais da Desigualdade (PDSD) para download

Logo_CEM_300

O Centro de Estudos da Metrópole (CEM – USP) acaba de divulgar em seu site o banco de dados da Pesquisa Dimensões Sociais da Desigualdade (PDSD)

TrNelsonDoValleSilva-168x168ata-se de uma iniciativa ímpar no cenário da ciência social brasileira, de um projeto coordenado por Nelson do Valle Silva. Disponibilizar a PDSD para o público é, ao mesmo tempo, uma busca por divulgar dados de qualidade incrível e, além disso, uma forma de homenagear Nelson, que sem sombra de dúvida é uma das principais figuras das Ciências Sociais no Brasil. Ele foi pioneiro nos estudos de estratificação social no país (em especial nas áreas de desigualdades educacionais, raciais, ocupacionais e estruturação de classes e no mercado de trabalho). Atualmente é Pesquisador Sênior nacional do Instituto de Estudos Sociais e Políticos da Universidade do Estado do Rio de Janeiro (IESP-UERJ), vinculado ao Ceres (Centro para o Estudo da Riqueza e da Estratificação Social).

A realização da PDSD contou com financiamento do CNPQ (era um dos projetos financiados pelo “Institutos do Milênio”) e foi a campo por todo Brasil, produzindo uma amostra (aleatória) com representatividade nacional – e com desenho comparável ao vigente nas Pesquisas Nacionais por Amostragem de Domicílios (PNAD-IBGE) até 2004 (isto é, apenas não foram investigadas as áreas rurais da região Norte).

A PDSD é bastante rica e detalhada, visando suprir a lacuna de informações em muitos temas de interesse. Uma de suas principais motivações era investigar o processo de criação e transmissão das desigualdades ao longo do ciclo de vida dos indivíduos, identificando momentos e etapas cruciais.

Para acessar o site do CEM, saber mais sobre a PDSD e fazer download do banco de dados e da documentação, CLIQUE AQUI.

Marx e o infinito: uma introdução ao Cálculo e os “limites” dos Manuscritos Matemáticos (Parte 1)

Parte 1: Limites.                      Parte 2: Derivadas (em breve)


karl_marx_2_by_morales899-d5oqkp4Marx errou. E não estou falando do materialismo histórico. Seu tropeço foi na Matemática.

Seus Manuscritos Matemáticos sintetizam sua incursão no o Cálculo Infinitesimal e seus lapsos por ter mal compreendido o conceito de limite — justamente aquele que carrega a idéia de infinito.

Decidi aproveitar dessa ocasião para explicitar o erro dele e fazer algo que sempre quis aqui no Sociais & Métodos: uma simples e pouco técnica introdução ao Cálculo. Espero motivar alguns cientistas sociais e/ou curiosos. Além disso, com esse material aqui, acredito que fica mais fácil fazer referência a notações e conceitos matemáticos em posts futuros. 

Mas aviso: é só um overview — e muito básico…


Limite

“Qual é o maior número de todos?”. Pergunte isso a uma criança de 5 anos e logo se ouvirá respostas incríveis: “Mil! Não, não… Um milhão!! Mil milhões! Um trilhão de bilhão!! Um mil bilhões de zilhões!!” Obviamente, isso não tem fim.

A criança não sabe, mas possui uma intuição verdadeira sobre como nós lidamos com o infinito: com arbitrariedade. Com isso já temos uma noção sobre o conceito matemático de “limite”. Em linguagem formal, se um número x “tende ao infinito”, escrevemos:

x \to+\infty

O infinito é representado por esse oito deitado \infty. O sinal de mais à sua frente indica que se trata do infinito positivo (“à direita” na reta dos números reais) — afinal existe o infinito negativo (podemos caminhar para “a esquerda” na reta: menos mil, menos um milhão, menos um trilhão…). A seta significa “tende à”.

Trata-se, no caso acima, daquele mesmo “jogo” em que podemos dizer um número cada vez mais alto. Mas quando isso pára? Ou seja, qual o seu “limite”? Para isso escrevemos:

\displaystyle \lim_{x \to+\infty}x = +\infty

Agora temos “o limite de x, quando x  tende ao infinito é infinito“. Com isso, queremos dizer que “no limite”,  x será infinito. Parece uma contradição, né? Afinal o infinito é “ilimitado”. Mas esse foi só um jeito formal de dizer que a brincadeira não tem fim.

Observemos agora a seguinte situação:

\displaystyle \lim_{x \to 2}x

Esse é o limite de x, quando x tende a 2. Isso significa que podemos pensar em números arbitrariamente próximos de 2, SEM JAMAIS CHEGAR A ESSE VALOR EFETIVAMENTE. Veja, por exemplo, a seguinte sequência de quatro números:

1.5, \:\:\: 1.8, \:\:\: 1.93, \:\:\: 1.9997843

Cada um está cada vez mais próximo de 2, certo? Apelando, pra chegar realmente próximo, poderíamos pensar em 1,999999... com um número “infinito” de 9s — infinito, no sentido de tantos quantos quisermos. Mas a pergunta relevante é: pra você, 1,9 já é suficientemente próximo de 2?

Podemos dizer que, que, no limite, o número mais próximo de 2 é o próprio 2. Por isso, o limite de x, quando x tente a 2 é igual a 2:

\displaystyle \lim_{x \to 2}x = 2

Essa notação oculta o fato de que a regra dessa brincadeira é se aproximar do “valor-alvo” sem jamais tocá-lo. x nunca  será 2. Na realidade, 2 é a resposta para a pergunta: “para qual número x está tendendo?” — e não algo em que x se transforma. Por exemplo: para qual número a sequencia abaixo parece estar tendendo?

1.6, \:\:\: 2.2, \:\:\: 2.33 ,\:\:\:2.397 ,\:\:\:2.39998654 ,\:\:\:2.3999999583

Parece ser 2.4, certo? Então escrevemos:

\displaystyle \lim_{x \to 2.4}x = 2.4

É uma notação praticamente tautológica, já que abaixo da expressão “lim” já havíamos escrito que x \to 2.4. As coisas mudam um pouco quando fazemos:

\displaystyle \lim_{x \to 3}x^2 = 9

Desta vez não desejamos saber o valor do próprio x quando tende a um número, mas sim de uma função sua. A medida a x chega perto de 3, observamos que x^2 se aproxima de 9

\displaystyle \lim_{x \to 3}x^2 = 9

Um exemplo numérico disso pode ilustrar bem o que quero dizer:

limite

Nesse caso, não importa se chegamos perto de 3 a partir de números menores (“pela esquerda”) ou a partir de números maiores (“pela direita”), o que ocorre é o mesmo.

Podemos agora falar de limites laterais. Quando tendemos a um número apenas a partir da esquerda, escrevemos:

\displaystyle \lim_{x \to 3^-}

Observe o pequeno sinal de negativo, ao lado do número 3. Se a aproximação é pela direita:

\displaystyle \lim_{x \to 3^+}

No caso acima, como os dois limites laterais são iguais, podemos dizer que “o” limite existe:

\displaystyle \lim_{x \to 3^-}x^2 = \lim_{x \to 3^+}x^2 = \lim_{x \to 3}x^2 = 9

Isso não é verdade para todos os casos. Tomemos a função \displaystyle \frac{1}{x}, quando x \to 0. Quando \frac{1}{x} se aproxima de zero, temos uma situação perigosa, pois \displaystyle \frac{1}{0} não existe, é indeterminado, uma contradição. Afinal, como dividir ou distribuir algo se não há ninguém para receber o que vai ser distribuído?

É necessário avaliar com cuidado o que ocorre tanto quando x \to 0^-, como quando x \to 0^+:

limite2

Quanto mais nos aproximamos de zero, o valor absoluto dos resultados cresce. No entanto, os dois limites são completamente opostos:

\displaystyle \lim_{x \to 0^-} \frac{1}{x} = \frac{1}{0^-} = -\infty

e

\displaystyle \lim_{x \to 0^+} \frac{1}{x} = \frac{1}{0^+} =+\infty

A intuição é relativamente simples: no primeiro caso, não importa quão pequeno e próximo de zero seja 0^-, ele sempre será um número negativo. Ora, dividir um valor negativo por um positivo sempre vai gerar um negativo. “Menos com menos dá mais”, afinal.

Não existe um resultado para \lim_{x \to 0}\frac{1}{x}, mas sim dois valores diferentes para \lim_{x \to 0^-} \frac{1}{x}\lim_{x \to 0^+} \frac{1}{x}. Se representarmos graficamente os resultados de \displaystyle \frac{1}{x} para cada valor de x, temos algo assim:

limite2

Observem que as linhas vão para lados diferentes no eixo vertical, quando chegamos perto de zero no eixo horizontal. Cada vez mais próximas do infinito (obviamente sem jamais chegar lá, pois não existe “lá”). Os casos mais delicados são sempre esses em que “quase” dividimos por zero.


Por enquanto é só, pessoal. A Parte 2 vem aí.

MQ/UFMG: Inscrições Abertas

logoApenas divulgando: estão abertas as inscrições para o Programa Intensivo de Metodologia Quantitativa, do Programa de Pós-graduação em Sociologia da UFMG, o famoso “MQ”.

A data final para submeter uma aplicação é dia 17 de junho de 2016. As aulas ocorrem entre 11 de julho e 05 de agosto. São vários módulos de uma ou duas semanas — e você pode montar o “cardápio” que quiser. Confiram as disciplinas oferecidas no deles:

aqui!

Vou lecionar uma “Introdução ao R”. Mas a oferta contempla todos os gostos e estágios de formação. Apesar do nome “Metodologia Quantitativa”, há também cursos de métodos qualitativos.

(Não faço parte da organização… então não saberia dar informações detalhadas sobre preços, horários, salas etc.)

 

 

Sociedade, caos e complexidade

(Quinto post da série. Veja os outros: Parte 1, Parte 2, Parte 3 e Parte 4.)

 

O argumento principal aqui é bem simples: Modelos matemáticos e computacionais não serão  “a última palavra” nas ciências do comportamento humano.


Seção 1 – O Demônio de Laplace e o Relógio de Einstein

Imagine que por um segundo você soubesse exatamente onde estão todas as coisas que existem no universo, bem como a dirA-Clockwork-Orange-a-clockwork-orange-18133446-1024-768eção para onde se movem, suas velocidades e acelerações relativas — tudo. E agora? Sabendo de todas essas coisas seria possível prever os próximos estados, o futuro? O universo se comportaria como uma mesa de bilhar em que, teoricamente, é possível saber exatamente o que vai ocorrer com todas as bolas depois da primeira tacada? Noutras palavras, o universo seria um sistema determinístico, fruto de uma cadeia “mecanismística” de causas e efeitos?

Foi exatamente nisso que estava pensando Pierre Laplace quando formulou sua famosa conjectura, bastante conhecida como “Laplace’s Devil“:

“Vemos o estado presente do universo
como efeito dos estados antecedentes e
como causa dos estados que se seguem.
Uma inteligência superior que conhecesse
todas as forças atuantes na natureza em
dado instante, assim como as posições
momentâneas de todas as coisas no
universo, seria capaz de compreender numa
simples fórmula os movimentos dos grandes
corpos assim como dos simples átomos do
mundo…”

— Conjectura de Laplace. Tradução de Eleutério Prado.

Expressão máxima do materialismo determinista, sonho utópico da ciência que têm na Física Newtoniana sua matriz de inspiração. Mas o universo não pára, não sabemos onde estão todas as coisas, nem como se movem etc.

Mas suposição continua guiando, como um horizonte distante, empreendimentos diversos. “Deve haver alguma regularidade, uma lei, uma fórmula, qualquer coisa…”. Os gregos (pitagóricos) acreditavam que a regularidade estava nas formas geométricas e proporções perfeitas subjacentes a todas as coisas. Galileu inaugura uma nova fase, dizendo que a matemática é a língua pela qual Deus escreveu o universo — e Newton de fato desvela o léxico, a sintaxe e a morfologia de boa parte dessa língua. Agora não só a estática (a forma) é regular, mas também o movimento.

Sim… o universo deve mesmo ser esse grande mecanismo. Toda laranja é mecânica, todo orgânico é mecânico; tudo, no fundo, deverá um dia se reduzir à Física. Vamos mais longe: é possível que não haja “alma”, “além”, nada… Nossos processos mentais devem, no limite, se constituir apenas de uma imensa, complexa e incomensurável rede de cadeias causais puramente materiais; consequência da Seleção Natural operando por 3,5 bilhões de anos. Sim! Sim!

Mas não… ainda não sabemos de fato de todas essas coisas. Apenas supomos, temos fé. Confortados e atormentados pelo Demônio de Laplace, observamos o universo acontecendo, como quem observa um relógio fechado:

“Na tentativa de perceber a realidade, nós somos de certa forma como um homem que tenta perceber o mecanismo de um relógio fechado. Esse homem vê o mostrador, os ponteiros e até ouve o tique-taque, mas não tem meios para abrir a caixa. Se o homem for engenhoso, pode imaginar um mecanismo que poderá ser responsável por tudo que observa, mas nunca poderá ter a certeza de que o mecanismo por si imaginado é o único que pode explicar suas observações.”

A. Einsten

(Sei que é brega citar frases “profundas” do Einstein e que muitas delas são fake. Mas essa é verdadeira, eu garanto. E caiu aqui como uma luva).


Seção 2 – O mecanismo da amizade, a matemática dos amantes

Recent-Study-Suggests-Over-85-Of-Social-Media-Users-Cant-Correctly-Solve-Simple-Math-Equation.jpgNa Matemática encontramos o modelo mais simples que encarna as propriedades ansiadas pela Conjectura de Laplace: uma Progressão Aritmética (PA). Veja o exemplo abaixo:

x_{t+1} = r + x_t

Sabendo o valor da primeira realização da sequência ( x_{t} ) e da variação acrescentada em cada iteração (r), podemos deduzir todos os demais pontos. Se x_{0} = 4r = 3, então x_{10} será 34. Ou seja, se sabemos os estados iniciais e as propriedades da variação, uma sequência determinística como essa nos dá qualquer resultado.

As fórmulas da Física clássica funcionam exatamente assim: movimentos através do tempo podem ser compreendidos como sucessões de uma série matemática (às vezes discreta, como uma Progressão Aritmética ou Geométrica simples, dessas que aprendemos na escola; às vezes contínua, delineando variações infinitesimais). Se lançamos uma bola de canhão, ela seguirá uma trajetória em forma de parábola e, sabendo a posição e a velocidade iniciais, podemos saber a posição, aceleração, velocidades horizontal e vertical em todos os pontos. Vocês já notaram isso antes? Aquela famosa fórmula do movimento retilíneo uniformemente variado é parente da PA:

S_t = S_0 + V_0t + \frac{at^2}{2}

A posição em qualquer momento do tempo (S_t) pode ser conhecida se soubermos a posição inicial (S_0), a velocidade inicial (V_0) e a aceleração da gravidade (a). Será que conseguiríamos fazer o mesmo para as ciências sociais? Será que conseguiríamos obter fórmulas do tipo:

PIB_t = PIB_0 + r(t)

Ou então:

DesigualdadeDeGenero_t = DesigualdadeDeGenero_0 + r(t)

Ou mais ainda:

SituacaoDaSociedadeBrasileira_t = SituacaoDaSociedadeBrasileira_0 + r(t)

Será!? Descobrir uma fórmula como essa foi exatamente o feito de Harry Seldon, personagem de Isaac Asimov na série de livros A Fundação. Seldon inventou uma ciência preditiva do comportamento social agregado, a Psychohistory (ou Psico-história), capaz de deduzir estados futuros séculos a frente. Aqueles que acompanharam os livros se lembrarão que seu feito inicial foi justamente descobrir as relações e regras de movimento (as fórmulas, por assim dizer). Mas faltava-lhe determinar os parâmetros iniciais corretos, calibrar o seu modelo (saber o S_0, por assim dizer). Depois de descobertos esses estados iniciais, foi só tocar o play.

A Psychohistory ainda não foi inventada… Mas tentamos elaborar fórmulas daquele tipo o tempo todo. Uma das mais conhecidas, em Economia, é o modelo modelo de Mincer (1958):

log[Y(S)]= log[Y(0)] + rS

Ela diz que o logaritmo da renda de uma pessoa com S anos de estudo é igual ao logaritmo da renda de uma pessoa com zero anos de estudo adicionado do retorno (r) pelos S anos de estudo. Ou seja, é possível “prever” a renda de qualquer pessoa, se soubermos Y(0), r e S. Obviamente as coisas não funcionam bem assim… Por isso, considera-se a existência de uma variação aleatória:

log[Y_i(S)]= log[Y_i(0)] + rS_i + \epsilon_i

Posteriormente, Mincer (1974) incorporou variações devidas ao ciclo de vida e on-the-job training. Sua equação, no formato mais famoso, é:

log[Y_i(S)]= \beta_0 + \beta_1X + \beta_2X^2 + rS_i + \epsilon_i

Na Sociologia, também temos inúmeros exemplos de fórmulas como essa. Vocês encontrarão diversos exemplos no excelente artigo Cumulative Advantage as a Mechanism for Inequality, de DiPrete e Eirich (2005).

Mas os problema são sempre os mesmos:

  • Suposições fortes são feitas com respeito ao funcionamento da sociedade e ao comportamento dos indivíduos. Na primeira versão da fórmula de Mincer, assume-se que todos os indivíduos são homogêneos (idênticos em termos de recursos, oportunidades, acesso ao crédito, preferências etc.) e que a soma dos rendimentos acumulados de todo curso de vida é sempre idêntica. Um indivíduo que não vai à escola, recebe diversas “parcelas” de salários menores. Um indivíduo que vai à escola, deixa de receber vários salários (pois estudava em tempo integral); mas depois é compensado, recebendo parcelas maiores (que são o “retorno” pelo investimento). Mas ambos receberam o mesmo montante. Forçado demais né? O segundo modelo é mais flexível, mas também tem pressupostos absurdos. James Heckman revisou esses pressupostos num incrível artigo.
  • Como obter o valor dos parâmetros? Geralmente o que se faz é estimar empiricamente, através de Estatística/Econometria. O problema é que parâmetros obtidos desta forma não são necessariamente os “verdadeiros”, que estariam por traz do fenômeno. Já falei disso aqui no blog, quando discuti Variáveis Instrumentais e Causalidade (nessa e nessa ocasião).

Seção 3 – A explicação generativista

Thematrixincode99.jpgAgent-based models são uma forma de lidar com esse problema — obviamente, também insuficiente, mas muito mais flexível.

Conseguimos fazer suposições mais “realistas” (agente heterogêneos, racionalidade limitada, informação incompleta, interações locais etc.). Podemos mais facilmente estabelecer dinâmicas que entrelaçam esferas distintas (aspectos demográficos, políticos, econômicos, históricos etc). Podemos estudar a dinâmica — e não apenas os pontos de equilíbrio estáticos  — com muito mais facilidade do que através de Dinâmica Comparativa e uso de equações diferenciais.

O problema, é que, como disse Galileu, Deus escreveu a natureza utilizando a linguagem da Matemática — e não da computação. Economistas e formalistas, dados às equações, não costumam ser muito receptivos aos ABMs. Fórmulas dão elegância, altivez e “cheiro de Ciência”, com C maiúsculo. Quem nunca se encantou com e = mc^2? Três letrinhas e um número — e dentro deles jaz a chave para a bomba atômica e para a viagem interestelar. Algoritmos são atrapalhados, longos, expressos em diversos dialetos (R, Python, C, C++, Java…). E o pior de tudo: não garantem uma resposta única para um mesmo problema. Pessoas diferentes poderiam chegar a implementações completamente díspares.

Entretanto, o método das “Sociedades Artificiais” tem suas vantagens. A primeira delas é estabelecer um novo parâmetro de validação científica: para explicar um fenômeno, é preciso compreender exatamente o funcionamento dos seus mecanismos geradores; tendo compreendido-os, é possível implementá-los em um ambiente in vitro (uma simulação) e observar se os padrões emergentes são os mesmos observados empiricamente. Nas palavras de Joshua Epstein: “If you didn’t grow it, you didn’t explain it”:

Or, in the notation of first-order logic:

epstein
To explain a macroscopic regularity x is to furnish a suitable microspecification that suffices to generate it. The core request is hardly outlandish: To explain a macro-x, please show how it could arise in a plausible society. Demonstrate how a set of recognizable–heterogeneous, autonomous, boundedly rational, locally interacting–agents could actually get there in reasonable time. The agent-based computational model is a new, and especially powerful, instrument for constructing such demonstrations of generative sufficiency.

Epstein

Nesse texto referenciado, Epstein insiste ainda que mesmo nos ABMs, Equações Existem. Mas trata-se de uma outra forma de pensar a modelagem, recursiva.

Pensem nos exemplos de ABM que eu forneci nos três posts anteriores. Em todos eles, as simulações eram, na realidade, loops. Ou seja, eram passos discretos que produziam resultados que alimentavam as rodadas posteriores. Cada rodada tomava como input o resultado da rodada anterior. Podemos então pensar que os parâmetros são um vetor de inputs x e que um passo da simulação é uma função h(x). Deste modo, o resultado depois de duas iterações seria:

h(h(x)))

E assim por diante:

h(h(h(x))))h(h(h(h(x))))), …

Na realidade, o argumento de Epstein é bem mais interessante e completo. Ele mostra que a representação algorítmica de uma função em uma máquina de Turing (i.e. um computador) tem um equivalente matemático. Mas vou deixar as tecnicalidades excessivas de lado neste post.

De todo modo, a lógica é algo semelhante à de uma série, em que o input no tempo t+1 é fruto de operações ocorridas no tempo t. Um ABM é, no final das contas, uma série ou sequencia matemática, parente da PA — ainda que complicações adicionais advindas de processos estocásticos possam advir.


Seção 4 – O Caos

butterfly-effect

É claro que todo mundo já ouviu falar no tal “Efeito borboleta” (ou, no mínimo, já viu aquele filme horrível com o Ashton Kutcher). Uma borboleta bate asas na China hoje e pode provocar desastres naturais nos Estados Unidos séculos ou milênios depois. Segundo a visão de mundo subjacente a essa ideia, pequenas ações têm grandes consequências não premeditadas; o mundo seria um grande emaranhado de causas e efeitos, tão gigantesco em sua complexidade, que às vezes partes que pensamos estar completamente desconectadas, na realidade, demonstram estreita relação. É um caos.

No entanto, em Matemática a noção de Caos têm origem no estudo de séries, como a PA e a PG. Descobriu-se uma família muito peculiar de funções cujo comportamento não se assemelhava nada antes visto. Tudo começou com uma funçãozinha humilde e aparentemente simples:

x_1 = rx_0(1 - x_0)

Fácil, né? Você insere um valor para x_0 e obtém um valor para x_1. Um procedimento simples, de input e output. Mas temos que definir um valor para r antes.

O físico e blogueiro Ricardo Marino fez um fantástico post sobre esse assunto no seu Todas as Configurações Possíveis, quando o matemático brasileiro Artur Ávila recebeu a Medalha Fields, o “Nobel da Matemática”, por ter desenvolvido trabalhos justamente na área de Sistemas Dinâmicos e Teoria do Caos (ninguém melhor que um brasileiro pra falar de caos, afinal). Vou reproduzir aqui algumas citações e gráficos do post dele.

Vejamos o que acontece quando começamos no valor x0=0,e com r=1,2. Primeiro calculamos o próximo passo: x1=r.x0(1x0) =1,2.0,1(10,1)=0,108. Para calcular o próximo passo, continuamos com a regra: x2=r.x1(1x1) =1,2.0,108(10,108)=0,1156032. Não vou escrever linha por linha, mas um gráfico revela o futuro dessa conta, ela converge para um valor específico.

avila_1

[…] Veja o que acontece quando trocamos r por 3,1.

avila_2

Com esse valor de r, o sistema não converge para um valor, mas para dois valores. Esse comportamento não é lá muito normal, mas piora, veja o que acontece quando colocamos r=3,5.

avila_3

[…] Quando chegamos a r=3,7, na verdade bem antes disso, torna-se completamente impossível prever os valores desses sistema. O único jeito de obter o valor na centésima iteração é calcular todas as noventa e nove anteriores. Veja como fica nosso gráfico para r=3,7.

avila_4

Esse é o caos: um sistema determinístico, mas de comportamento imprevisível (se não sabemos as condições iniciais). Saindo da metáfora, o verdadeiro “efeito borboleta” é o seguinte: alterações mínimas no parâmetro r da equação (principalmente depois que ele ultrapassa 3,7) ou no valor inicial x_0 provocam mudanças absurdas na série. Qualquer coisa pode acontecer. Com r=4 e início em x0 = 0,6, temos:

a.png

Retirado dos slides da Aula 3 da disciplina “Economia e Complexidade”, ofertada pelo Prof. Eleutério Prado na pós-graduação em Teoria Econômica da FEA/USP (2014)

Laplace não viveu pra ver. Ele faleceu em 1827 e a Teoria do Caos só começou a ser desenvolvida de verdade depois de Poincaré, a partir de 1880. Certamente teria tomado um baque.

As implicações epistemológicas e ontológicas da existência de sistemas assim são trágicas e assustadoras. E se o universo, esse relógio fechado, for, na realidade, um sistema caótico? Agora, depois de 14 bilhões de anos, infinitas “rodadas” já aconteceram… Será que conseguiríamos de fato abstrair seus mecanismos de funcionamento e parâmetros iniciais para que fosse possível prever futuros estados?

Não precisa nem queimar a pestana com isso. A resposta é um óbvio e categórico NÃO. E esta não é apenas uma questão de (falta de) desenvolvimento da Ciência. Todo modelo científico é como um mapa. E todo mapa é uma simplificação. Para que fosse tão detalhado quanto a própria realidade, deveria ser tão grande quanto ela. Um modelo capaz de explicar todo o universo deveria ser do mesmo tamanho ou maior que o próprio universo. Esse nem é um problema de Sistemas Dinâmicos e Teoria do Caos. É uma impossibilidade lógica.

Mas se o caso é modelar e compreender partes mais circunscritas e restritas, a questão sobre o caos se coloca. Seria a sociedade um sistema caótico? Aparentemente, as Ciências Sociais enfrentam muito mais dificuldades em encontrar regularidades e padrões gerais precisos. Nossos fenômenos são tão instáveis, que não permitem a fácil matematização. A não ser que assumamos agentes homogêneos, informação completa, racionalidade perfeita etc… Mas se o caso não é esse, estamos muito longe do padrão de ciência estabelecido pela Física. Não é somente a lacuna de formação em Exatas por parte dos sociólogos e cientistas políticos: matemáticos, físicos e cientistas da computação que migraram pra cá ainda não conseguiram fazer muitas revoluções… É um caos.

ABMs são mais uma vela no meio dessa escuridão. Contudo, ainda não sabemos muito bem onde estamos.


Seção 5 – A aleatoriedade

randombitmap

O Caos é um golpe contra a vontade de desvelar os mecanismos determinísticos do mundo, essa laranja mecânica. O golpe final é a aleatoriedade ontológica. Segundo essa perspectiva, nenhum fenômeno é guiado por leis determinísticas. Eles ocorrem apenas com alguma probabilidade. A ideia é a seguinte: se você jogar uma bola para o alto, ela tem ou não a possibilidade de cair… certamente é mais provável que ela caia. Mas vai que…

Parece absurdo, mas é exatamente isso o que ocorre com as partículas sub-atômicas — e caracteriza bastante o ramo chamado Física Quântica. Não sabemos exatamente onde os elétrons estão… mas conhecemos “zonas de probabilidade”, onde é mais frequente encontrá-los; são os chamados orbitais. A Física Quântica deixou todos tão atônitos que Einstein (que inadvertidamente havia ajudado a fundá-la), declarou: “Deus não joga dados” (querendo dizer que essa concepção de um “mundo probabilístico”, ao invés de determinístico, era absurda). Deus, na verdade, desde Galileu, todos sabem, resolve equações diferenciais — que absurdo pensar diferente, oras!

A aleatoriedade quântica é, atestadamente, um componente do fenômeno em si, e não um erro de medida ou fruto da insuficiência do conhecimento. Ao menos na Física subatômica. Com isso, mesmo que tivéssemos todas as informações requeridas pela conjectura de Laplace, não seria possível prever o futuro. Choques aleatórios acumulados (um random walk) nos levariam para qualquer lugar, no longo prazo.

Mas e no resto dos fenômenos do mundo? E na sociedade? Onde reina a aleatoriedade ontológica? Durma com um barulho desses…


Seção 6 – De onde viemos e para onde vamos

Os ABM estão muito longe de serem verdadeiramente “Sociedades Artificiais” completas e num sentido lato. Não somos ainda capazes de construir uma Matrix ou algo do tipo. Falta-nos conhecimentos substantivos sobre o comportamento humano, capacidades computacionais e um monte de outras coisas. Mas o caos e a aleatoriedade lançam desafios adicionais: ainda que fossemos capazes de tamanho empreendimento, a completa previsão do comportamento humano dificilmente seria possível (não estou sequer discutindo se seria desejável).

Modelos científicos de explicação são parciais. A totalidade é incomensurável e inabarcável (ainda que alguém de matriz marxista possa discordar…). Assumo que não haverá “a” equação do comportamento humano, nem a Matrix, nem a Psychohistory. Modelos matemáticos e computacionais são úteis, porém não são  e não serão  “a última palavra”.

Quem, de três milênios, não é capaz de se dar conta, vive na ignorância, na sombra, à mercê dos dias, do tempo.

— Goethe

Simulando a segregação racial: o modelo de Schelling (ABM – Parte 4)

Quarto post da série. Veja os outros: Parte 1, Parte 2, Parte 3 e Parte 5.


 

Não faz muito tempo, fomos surpreendidos pela produção e divulgação desses excelentes mapas, produzidos por um aplicativo on-line e interativo:

raca

São mapas da distribuição espacial dos indivíduos por raça. No exemplo acima, trata-se da Região Metropolitana de São Paulo. Cada indivíduo é repesentado por um ponto e colorido de acordo com sua raça. São dados baseados no Censo Demográfico de 2010. Os criadores do aplicativo tiveram a nobreza de disponibilizar os códigos e todos os procedimentos que estão nos bastidores desse empreendimento. Está tudo no GitHub.

O que interessa aqui desta vez é discutir sobre como agent-based models podem ajudar a compreender a formação desses padrões espaciais, que evidenciam uma clara e bem delimitada separação dos grupos. O propósito não será discutir desigualdades raciais, mas sim a noção de emergência (sobre o que já falei brevemente no post anterior): ações individuais isoladas podem gerar padrões macrossociais não previstos e que não poderiam ser deduzidos a partir da observação de indivíduos ou grupos específicos.

Imagine a seguinte situação: uma sociedade cujos indivíduos podem ser classificados em dois grupos raciais, azul e vermelho. Com excessão da raça, todos são iguais, em termos de recursos, oportunidades etc. A princípio, nessa situação abstrata, qualquer pessoa poderia comprar uma casa e se mudar para absolutamente qualquer lugar daquela localidade, desde que o local de destino estivesse desocupado. Numa situação como essa, haveria segregação racial? A princípio não, a não ser que os indivíduos tivessem algum grau de racismo. E é exatamente isso que vamos modelar desta vez: quanto racismo é necessário para que um padrão claramente segregado se forme?

Obviamente, o padrão que observamos em São Paulo na figura acima não se deve somente ao racismo. Há uma sobreposição de inúmeros processos: pobreza, desigualdades de renda, dinâmicas do mercado imobiliário, além de um path dependence com relação à colonização, ocupação do espaço e história social dos bairros. Mas não sejamos ingênuos, os pobres não são negros por “coincidência”. Além disso, mesmo controlando pela situação socioeconômica, encontramos segregação por cor; como evidenciou o meu caro amigo Danilo França em sua dissertação de mestrado e também num capítulo mais recente, publicado no livro A metrópole de São Paulo no século XXI, organizado por Eduardo Marques.

Thomas Schelling, prêmio Nobel de Economia em 2005, elaborou seu modelo de simulação fundando-se numa situação abstrata semelhante àquela exposta acima. Ele propôs o seguinte (sério, vejam o artigo): suponha que os indivíduos tenham preferência por residir próximos a certa quantidade de pessoas da mesma raça que eles — por exemplo, no mínimo 20%. Assim, uma pessoa olha ao seu redor, conta quantos vizinhos têm a sua cor e, se houver menos do que gostaria, muda-se para outro lugar (sorteado aleatoriamente, mas que estava previamente vazio, não ocupado por alguém). Assumindo, que todas as pessoas compartilhem de um mesmo grau de “racismo” ou “tolerância” (nessa acepção absurdamente simplificada), qual é o valor mínimo desse parâmetro para que obtenhamos delimitações raciais muito claras no espaço? A resposta é: aproximadamente 30%.

F4.large.jpg

Provavelmente o leitor já se deparou com diagramas como esse aí acima, que mostram o resultado do modelo de segregação de Schelling, assumindo diversos graus de tolerância e fazendo variar o número de espaços vazios para onde os indivíduos “infelizes” podem se mudar. É exatamente isso que vamos simular.


Desta vez, apelei à comodidade. Ao invés de programar eu mesmo os códigos para a implementação do modelo, resolvi copiar e modificar um exemplo muito bom que encontrei no blog R Snippets. Em time que está ganhando não se mexe, hehe. Fiz modificações mínimas para tornar mais fácil a modificação dos parâmetros. O exemplo, no entanto, segue uma estratégia muito distinta da apresentada nos três posts anteriores desta série sobre ABM aqui no Sociais & Métodos. Ele não usa Reference Classes. Os agentes, segundo essa representação, não são objetos com atributos e capacidades de ação… Podemos indagar se de fato, da maneira como foi construída, a implementação desse modelo se constitui num verdadeiro ABM. Conceitualmente talvez sim. Mas como eu disse no primeiro post, replicando meu amigo Davoud, “it’s all about ontology”. Com isso, quero frisar que a forma de implementação deve refletir o modelo conceitual: se “agentes agem”, é desejável que exista um objeto computacional que operacionalize os agentes e suas ações. Não é só o resultado o que importa.

Tudo se passa numa matriz. Aleatoriamente, distribui-se os valores 2, 4 e 0, que representarão, respectivamente, as cores vermelho (raça 1), azul (raça 2) e branco (espaços vazios). Para cada célula, avaliamos se há X% de células da mesma cor (vermelho ou azul) ao redor. Mapeamos então esses “infelizes”. Em ordem aleatória, os re-alocamos para espaços vazios. Simples assim.

A execução do código abaixo produz, ao final, um GIF animado. Mas para que tudo funcione direitinho, é necessário instalar um software a mais, que gera esses GIFs, o ImageMagik (gratuito), além do pacote animation, no R.

Os parâmetros serão os seguintes:

tam = 50          # dimensao da matriz

tolerancia = .5   # nivel de tolerância/racismo

perc_ocupado = .9 # proporção de células ocupadas
                  # não vazias
raio = 1          # raio dentro do qual o indivíduo
                  # observa a vizinhança (1 célula em
                  # todas as direções: cima, baixo, 
                  # esquerda, direita e diagonais)

max_rep           # número máximo de iterações

Trago agora todo o código em bloco, sem muito me delongar ou explicar suas partes. O autor do post original já trabalhou nisso, e os mais curiosos podem dar uma passada lá pra conferir detalhes adicionais.

# 0 - empty
# 2 - first agent type color
# 4 - second agent type color
# initialize simulation
# size      - square size
# perc.full - percentage of lots to be occupied


init = function(side, perc.full) {
  size = floor(side ^ 2 * perc.full / 2)
  state = matrix(0, side, side)
  occupied = sample(side ^ 2, 2 * size)
  state[occupied] = c(2,4)
  return(state)
}


# plot simulation state
# state - simulation state
# i     - simulation iteration
do.plot = function(state, i) {
  side = dim(state)[1]
  x = rep(1:side, side)
  y = rep(1:side, each = side)
  par(fin=c(6,6), fig=c(0,1,0,1))
  plot(x , y, axes = F, xlab="", ylab="", col = state,
       main = paste("Rodada", i), pch = 19, cex = 40 / side)
}


# perform one step of simulation
# state     - simulation state
# threshold - percent of required agents of the same color
#             in neighborhood
# radius    - neighborhood radius

sim.step = function(state, threshold, radius) {
  mod.1 = function(a, b) { 1 + ((a - 1) %% b) }
  div.1 = function(a, b) { 1 + ((a - 1) %/% b) }
  unhappy = rep(NA, length(state))
  side = dim(state)[1]
  check = (-radius):(radius)
  
  #find unhappy agents
  for (n in which(state > 0)) {
    x = div.1(n, side)
    y = mod.1(n, side)
    x.radius = mod.1(check + x, side)
    y.radius = mod.1(check + y, side)
    region = state[y.radius, x.radius]
    similar = sum(region == state[n]) - 1
    total = sum(region > 0) - 1
    unhappy[n] = (similar < total * threshold)
  }
  vunhappy = which(unhappy)
  # move unhappy agents
  vunhappy = vunhappy[sample.int(length(vunhappy))]
  empty = which(state == 0)
  for (n in vunhappy) {
    move.idx = sample.int(length(empty), 1)
    state[empty[move.idx]] = state[n]
    state[n] = 0
    empty[move.idx] = n
  }
  return(state)
}

library(animation)
# simple wrapper for animation plotting
go = function() {
  s = init(tam, perc_ocupado)
  for (i in 1:max_rep) {
    do.plot(s, i)
    last.s = s
    s = sim.step(s, tolerancia, raio)
    if (identical(last.s, s)) { break }
  }
  for (j in 1:20) {
    do.plot(s, i)
  }
  ani.options(interval = 3 / (i + 2))
}
saveGIF(go())

Os resultados serão salvos num arquivo .gif no seu diretório de trabalho. Abaixo seguem alguns exemplos. Esse aqui abaixo é fruto de uma simulação em que a tolerância foi ajustada para 0.10 (10 %). Observa-se que a convergência é atingida rapidamente, em duas rodadas apenas. Depois disso, todos os indivíduos estão “felizes” e ninguém mais muda:

tol 0.10

Tolerância = 0,1

Nos dois casos a seguir, a tolerância foi ajustada para 0.2 e 0.3 . De fato, ajustando para 30%, é possível ver “ilhas” bem delineadas, obtidas ao longo de 16 rodadas. Ou seja, quanto maior a intolerância à indivíduos de outra cor, mais bem delineada a segregação e maior o tempo necessário para obter equilíbrio.

tol 0.20

Tolerância = 0,2

 

tol 0.30

Tolerância = 0,3

Veja que é possível obter padrões ainda mais segregados. Abaixo apesento dois outros diagramas. Um em que o nível de tolerância está em 0.5 e outro em 0.7 (esse último ficou parecendo um dinossauro ou é só viagem minha?).

tol 0.50

Tolerância = 0,5

 

Notem que no caso abaixo, entre vermelhos e brancos há espaços vazios!

tol 0.70

Tolerância = 0,7

Por fim, um caso extremo: tolerância em 0.9. É um grau de exigência tão alto que simplesmente não gera equilíbrio.

tol 0.90

Tolerância = 0,9


Conveniente rodar tantas simulações só mudando os parâmetros e apertando o play novamente né? Pois é… parece que o Schelling, no artigo original, fez tudo na mão — e usou lançamento de moedas para fazer o sorteio. Isso mesmo: fez um (quase?) ABM na mão! Isso é que é força. Há vários modos de implementar ABMs.

“Do bar”. Modelando a racionalidade limitada com ABM: o modelo El Farol (ABM – Parte 3)

Terceiro post da série. Veja os outros: Parte 1, Parte 2, Parte 4 e Parte 5.


sloppy-joes-bar-in-downtown-chicago-everettEssa é velha… Dois economistas entram num bar. Tinham preferências idênticas: detestavam aquele ambiente quando estava cheio demais. Era uma sociedade pequena, de três pessoas apenas (logo, todo mundo conhecia todos que existiam para conhecer). E pra todos era tácito: três é demais! Mas ir sozinho ou encontrar mais alguém por lá seria bom. Por isso, cada um havia feito, de antemão e sozinho, um cálculo sobre quem iria ou não. Cada um sabia exatamente como os outros dois decidiam, por isso era fácil adivinhar o que de fato ocorreria. Esse cálculo todo ocorreu da maneira a seguir.

Vamos adotar a seguinte notação: se uma pessoa decide ir ao bar, escrevemos V. Assim, o resultado V V V significa: a primeira pessoa foi, a segunda pessoa também e a terceira idem. Por conseguinte, VNV significa: a primeira e a terceira pessoa foram, mas a segunda não. E assim por diante. Usando essas siglas, podemos dizer que as preferências de cada economista da estória eram as seguintes:

  1. Preferiam ir sozinhos ou, no máximo com mais alguém. Do ponto de vista da primeira pessoa, os resultados desejados seriam: VNN, VVN ou VNV. Vamos atribuir 2 pontos de “satisfação” (pay offs) a esses resultados.
  2. Em segundo lugar, era preferível simplesmente não ir: NVV, NVN, NNV ou NNN. Não ir dá 0 pontos de satisfação para a pessoa.
  3. Por último, o pior dos mundos: chegar no bar lotado, VVV. A raiva é tanta que a satisfação diminui um ponto.

Com essas definições, desenhamos o seguinte diagrama, que representa as decisões individuais, os pay-offs e os resultados (pontos de equilíbrio). Um caso simples de teoria dos jogos.

jogo

A Pessoa 1 pensa da seguinte maneira:

  • Se as Pessoas 2 e Pessoa 3 já estiverem indo, vou ficar insatisfeito (-1 ponto). Então, nesse caso, eu não vou (então 0 pontos).
  • Se somente uma das duas pessoas estiverem indo ou se nenhum deles for, aí sim…! Estou dentro (2 pontos).

O diagrama acima apenas representa mais formalmente esse raciocínio, mostrando como pessoas avalia todas as combinações de situação e o que fariam em cada caso. Os números coloridos de azul mostram as decisões da Pessoa 1; os de vermelho, as decisões da Pessoa 2 e os de verde, as da Pessoa 3. Onde as três decisões se encontram, temos um equilíbrio de Nash – uma situação em que ninguém tem incentivo para mudar sua decisão. Nesse caso, temos três equilíbrios, que são exatamente as situações em que apenas duas pessoas vão ao bar. Qual deles de fato vai ocorrer? Boa pergunta! A princípio, qualquer um dos três . Ou então, pensando num longo prazo, os três podem acontecer em iguais proporções… Mas fato é: de acordo com esse raciocínio, sempre haverá duas pessoas.

A piada (“Dois economistas entram num bar…”) perde a graça quando começamos a trazer elementos mais realistas para a estorinha: 1) numa sociedade real, há muito mais do que três pessoas, como seria possível saber quem vai ou não, mesmo que todo mundo tivesse as mesmas preferências e decidisse utilizando as mesmas regras?; 2) e se cada pessoa decidisse utilizando regras diferentes e sem ter informação sobre o que os outros estão fazendo?; 3) e se cada pessoa tivesse acesso apenas a uma quantidade parcial de informações sobre a lotação do bar?; 4) e se tivessem preferências distintas sobre a quantidade de gente que consideram adequada?

Entram em cena os Agent-based models.


Esse joguinho do bar que eu inventei é só um uso simplificado de Teoria dos Jogos, pra ilustrar o quanto estamos exigindo dos nossos agentes mesmo numa situação tão simples quanto essa. Em especial, coloco em questão a informação completa sobre o método de decisão dos outros, sobre suas efetivas ações potenciais e sobre o comportamento da lotação do bar. Vamos suspender essas suposições. Será que mesmo assim podemos chamar nossos agentes de racionais? Será que um padrão de comportamento agregado vai ser produzido ou será que vai ser um caos? Essas foram as questões colocadas por W. Brian Arthur em seu clássico Inductive Reasoning and Bounded Rationality (veja a quantidade de citações no Google Scholar).

A noção de racionalidade limitada já fora proposta há muito tempo, por Herbert Simon — conferindo-lhe um Prêmio Nobel. Para Simon, que está na origem do desenvolvimento da cibernética e inclusive da inteligência artificial, nossa forma de pensar se parece muito mais com um algoritmo do que com uma equação. O critério de decisão parece muito mais com a tentativa de atingir um ponto de satisfação (um limite inferior) do que a maximização da utilidade. Além disso, é importante levar em consideração a cognição: isto é, a representação parcial da realidade dentro da cabeça do indivíduo. Cognição é importante justamente porque as pessoas não tem acesso completo à realidade externa e a interpretam da mesma maneira. Brian Arthur utiliza de uma simulação computacional para operacionalizar aspectos da racionalidade limitada. Traz como exemplo a decisão sobre ir ou não a um bar, o El Farol (que de fato existe na cidade de Santa Fé, Novo México, EUA – era um bar em que os pesquisadores do Instituto Santa Fé costumavam frequentar nos Happy Hours).

De forma geral, o modelo é o seguinte: o bar publica periodicamente quantas pessoas estiveram presentes das últimas vezes, formando um histórico de lotações. Cada indivíduo tem sua própria forma de calcular e decidir se vai ou não, e pode levar em conta as informações publicadas da maneira que quiser — ou seja, possuem, cada um, sua própria heurística. Alguns acham que sempre vai estar vazio, outros que sempre vai estar cheio. Alguns observam as tendências de curto prazo: a lotação têm crescido ou diminuído? Outros, as de longo prazo. Uns simplesmente julgam que a lotação da próxima vez será idêntica a da vez anterior. Outros, fazem uma média de todo o histórico do bar. E assim por diante. Depois de formarem seu próprio palpite (um chute/guess), decidem sozinhos se vão ou não. Então o bar registra a lotação daquele dia e depois publica como foi.

O que vale sublinhar é que não há um modo objetivamente correto de decidir e que cada pessoa não tem a menor ideia sobre como os outros decidem e o que vão acabar fazendo. O bar será uma surpresa.

O pseudo-código para o “Modelo El Farol” (como ficou conhecido), é:

Definimos parâmetros
  Histórico de lotações do bar (historico)
  Número de indivíduos na simulação (n)
  (Limite de) Lotação preferida (quantidade_preferida)
  Numero de rounds (rounds)

Criamos um conjunto amplo de formas de decidir (heurísticas)

Definimos a classe "Indivíduo"
  Sortearemos uma heurística para cada indivíduo, ao ser criado 

Criamos uma quantidade "n" de indivíduos.

Início de um loop:
  Rodada de decisões
    Cada indivíduo acessa o histórico de lotações e aplica sua 
    regra de decisão

  Rodada do bar
    Quem decidiu ir, de fato comparece
    Registra-se a quantidade de pessoas que estiveram presentes
    
  Se o número de repetições atingir "rounds"
    Termine o loop

Mãos à obra pra implementar no R agora. Primeiro os parâmetros:

historico = sample(1:100, 10)
n = 100
quantidade_preferida = function() 60
rounds = 100

Agora definimos as heurísticas. Trata-se de uma lista de funções. Cada uma acessa o histórico de lotações, que existe no ambiente principal e executa algum procedimento com ele. Por exemplo: estimativa_ultimo retorna o último valor do histórico. Isso significa que o indivíduo que aplica esse tipo de heurística supõe que a lotação da próxima vez será idêntica à da última. A função estimativa_espelho retorna um valor “espelhado” ao redor de 50: por exemplo, se da última vez foram 40 (i.e. 50 – 10), da próxima irão 60 (i.e. 50 +10). Alguns sempre chutam “37” (acham que vai pouca gente). Outros sempre chutam “70” (acham que vai muita). Os que observam a tendência de curto prazo “rodam mentalmente” uma regressão linear, considerando as últimas 5 vezes e estimam o valor predito para a próxima vez. O que observam a tendência de longo prazo, levam em conta as últimas 10. Seria possível ficar inventando heurísticas à vontade. Mas eu só elaborei 13. É o bastante para os fins deste exemplo.

heuristicas = list(
      estimativa_ultimo =
        function(){
          x = get("historico", envir=.GlobalEnv)
          tamanho = length(x)
          return(min(x[tamanho]))
        },

      estimativa_penultimo =
        function(){
          x = get("historico", envir=.GlobalEnv)
          tamanho = length(x)
          return(min(x[tamanho-1]))
        },

      estimativa_espelho =
        function(){
          x = get("historico", envir=.GlobalEnv)
          tamanho = length(x)
          return(n - x[tamanho])
        },

      estimativa_min3 =
        function(){
          x = get("historico", envir=.GlobalEnv)
          tamanho = length(x)
          return(min(x[(tamanho-2):tamanho]))
        },

      estimativa_max2 =
        function(){
          x = get("historico", envir=.GlobalEnv)
          tamanho = length(x)
          return(max(x[(tamanho-1):tamanho]))
        },

      estimativa_37 =
        function(){
          return(37)
        },

      estimativa_70 =
        function(){
          return(70)
        },

      estimativa_media2 =
        function(){
          x = get("historico", envir=.GlobalEnv)
          tamanho = length(x)
          return(mean(x[(tamanho-1):tamanho]))
        },

      estimativa_media5 =
        function(){
          x = get("historico", envir=.GlobalEnv)
          tamanho = length(x)
          return(mean(x[(tamanho-4):tamanho]))
        },

      estimativa_media10 =
        function(){
          x = get("historico", envir=.GlobalEnv)
          tamanho = length(x)
          return(mean(x[(tamanho-9):tamanho]))
        },

      estimativa_media_todos =
        function(){
          x = get("historico", envir=.GlobalEnv)
          return(mean(x))
        },

      estimativa_regr5 =
        function(){
          x = get("historico", envir=.GlobalEnv)
          tamanho = length(x)
          beta = coef(lm(x[(tamanho-4):tamanho]~c(1:5)))
          pred = c(1,6)
          return(as.numeric(pred%*%beta))
        },

       estimativa_regr10 =
        function(){
          x = get("historico", envir=.GlobalEnv)
          tamanho = length(x)
          beta = coef(lm(x[(tamanho-9):tamanho]~c(1:10)))
          pred = c(1,11)
          return(as.numeric(pred%*%beta))
        }
)

Definimos a classe “Indivíduo”:

Individuo = setRefClass("Individuo",
  fields = c("decisao",
             "estrategia_adotada",
             "quantidade_preferida"),

  methods = list(

    initialize = function(decisao = NULL,
    estrategia = sample(length(heuristicas),1),
    ...){

      .self$decisao            = decisao
      .self$estrategia_adotada = estrategia
      callSuper(...)
    },

    decide = function(){
      chute = heuristicas[[estrategia_adotada]]()

      if(chute > quantidade_preferida){
        .self$decisao = 0
      }else{
        .self$decisao = 1
    }}
))

Instanciamos os indivíduos:

pessoas = list()
for(i in 1:n)
pessoas[[i]] = Individuo$new(quantidade_preferida =
quantidade_preferida() )

E os rounds são bem simples:

for(t in 1:rounds){
  print(t)

  #Rodada de decisão
  for(pessoa in pessoas)
    pessoa$decide()

  # Rodada do bar
  decisoes = sapply(pessoas, function(x) x$decisao)
  quantos_foram = sum(decisoes)
  historico = c(historico, quantos_foram)
}

Aí, ó:rounds

Depois é só plotar os resultados:

# Excluindo os 10 primeiros rounds, que
# foram pré-definidos como parâmetros
historico = historico[-(1:10)]

# Gráfico
plot(historico, type = "l", ylim = c(0, 100), col = "red")
abline(h = mean(historico), col = "blue", lwd=2)

E então obtemos:

farol1As preferências eram todas iguais… certo? Estabelecemos nos parâmetros que ninguém gostava do bar com mais de 60 pessoas. E, de fato, um padrão emergente se estabelece em torno de 60, como se vê no gráfico acima. Mas não se trata de um ponto de equilíbrio: situações não desejadas por ninguém ocorrem frequentemente, sem padrão algum. Há uma instabilidade dinâmica.

Podemos testar o que ocorreria se as pessoas tivessem diferentes limites de tolerância à lotação. Pra isso, é só fazer:

quantidade_preferida = function() sample(0:100, 1)

Um número aleatório entre 0 e 100 será sorteado para cada pessoa. Assim:farol2

De uma forma bizarra, obtivemos um ponto de equilíbrio!! Mas isso foi completamente aleatório, dado ao acaso. Nem foi preciso assumir aquela quantidade toda de supostos tradicionais da escolha racional.

Mas poderíamos tornar o exemplo cada vez mais complexo. Cada agente poderia ter, por exemplo, mais de uma estratégia. Assim, fariam um chute a partir de cada uma delas e, na medida em que uma desse resultados melhores, tenderiam a utilizá-la mais vezes. Seria um aprendizado com a experiência. Poderíamos estabelecer uma regra diferente para a decisão. A atual é um limite superior de lotação: todo mundo gosta de ver no bar no máximo X pessoas. Mas poderia haver pessoas que gostasse de ver no mínimo X pessoas… ou então uma quantidade entre X e Y. E assim por diante…

Padrões emergem. Não combinados por ninguém e sem que ninguém tivesse informação prévia sobre o resto. A sociedade é exatamente isso, uma propriedade emergente, fruto da ação de todos, mas não presente completamente na cabeça de ninguém. Nada parecida com o diagrama de Teoria dos Jogos exposto acima. Escolha Racional tem muitas utilidades, sem dúvida. Mas também limitações… e algumas delas podem ser contornadas com ABM.

 

 

Sobre coelhos e lobos: um exemplo completo de agent-based model (ABM – Parte 2)

Segundo post da série. Veja os outros: Parte 1, Parte 3, Parte 4 e Parte 5.


Giant_20Rabbit_20or_20Small_20Wolf2_original.jpgNo ultimo post, mostrei como representar agentes de Agent-based Models no R utilizando Reference Classes, que permitem guardar “atributos” e “ações” num único objeto. Neste post, trarei um exemplo de implementação completa de um ABM — um modelo simples e bastante famoso chamado Predator & Prey. Com isso, teremos um overview de toda a estrutura de uma simulação.

Haverá dois tipos de agentes, coelhos e lobos. Coelhos têm a capacidade de se reproduzir e lobos têm a capacidade de caçar coelhos e, se estiverem alimentados, também podem se reproduzir. Se não se alimentarem, os lobos podem morrer. O objetivo da simulação é observar as dinâmicas demográficas desses dois grupos de animais (basicamente, o tamanho da população). A estrutura básica da simulação se dará conforme o pseudo-código abaixo:

Definimos parâmetros
  Número inicial de lobos a serem criados (num_lobos)
  Número inicial de coelhos a serem criados (num_coelhos)
  Taxa de fertilidade dos lobos (fertilidade_lobos)
  Taxa de fertilidade dos coelhos (fertilidade_coelhos)
  Probabilidade de um lobo morrer de fome (prob_morrer_de_fome)
  Numero de rounds (rounds)

Definimos as classes "Lobo" e "Coelho"

Criamos uma quantidade "num_lobos" de lobos
Criamos uma quantidade "num_coelhos" de coelhos

Inicio de um loop:
  Rodada dos coelhos
    Cada coelho se reproduz com probabilidade "fertilidade_coelhos"

  Rodada dos lobos
    Cada lobo caça coelhos e os encontra com uma probabilidade 
      proporcional ao tamanho da população de coelhos. Se for 
      bem sucedido na caça, se reproduz com probabilidade igual
      a "fertilidade_lobos". Caso contrário, morre com probabilidade
      "prob_morrer_de_fome".

  Se não houver mais lobos ou coelhos
    Termine o loop

  Se o número de repetições atingir "rounds"
    Termine o loop

 

Vejamos então como fazer isso no R. Primeiro criamos os parâmetros:

# Parametros

num_lobos = 100
prob_morrer_de_fome = .6
fertilidade_lobos = .4

num_coelhos = 1000
fertilidade_coelhos = .2

rounds = 50

Depois definimos as classes de agentes, usando as Reference Classes, explicadas no post anterior. Primeiramente os lobos:

Lobo = setRefClass("Lobo",
  methods = list(
    come_e_reproduz = function(){
      if( ((length(coelhos)/num_coelhos)^2) > runif(1) ){

        if(length(coelhos) > 0){
          coelhos = coelhos[-length(coelhos)]
          assign("coelhos", coelhos, envir = .GlobalEnv)
        }

        if (fertilidade_lobos > runif(1)){
          lobos[[length(lobos)+1]] = Lobo$new()
          assign("lobos", lobos, envir = .GlobalEnv)
        }

      }else if (prob_morrer_de_fome > runif(1)){
        lobos = lobos[-length(lobos)]
        assign("lobos", lobos, envir = .GlobalEnv)
      }
}))

Então os coelhos:

Coelho = setRefClass("Coelho",
  methods = list(
    reproduz = function(){
      if (fertilidade_coelhos > runif(1)){
        coelhos[[length(coelhos)+1]] = Coelho$new()
        assign("coelhos", coelhos, envir = .GlobalEnv)
      }
}))

Observem alguns pontos importantes:

  • Nenhum dos dois tipos de agentes possui atributos. Ambos possuem apenas “ações”. Lobos comem e se reproduzem; coelhos apenas se reproduzem. Deste modo, nenhuma informação foi passada para o argumento “fields”, que usualmente é exigido pelas Reference Classes.
  • Dentro da classe Lobo, a função “come_e_reproduz” faz referência a dois objetos que ainda não existem no ambiente do R, pois ainda não os criamos. Trata-se de um objeto chamado “lobos” (que será uma lista contendo todos os lobos criados) e de outro chamado “coelhos” (a lista dos coelhos criados). Ainda assim, já podemos fazer referência a eles.
  • Os dois objetos que ainda não existem serão criados no ambiente principal do R (.GlobalEnv). Para que possamos modificá-los a partir dessas funções que apenas existiram dentro das classes “Lobo” e “Coelho”, devemos especificar que estamos de fato acessando algo do ambiente principal e o sobrescrevendo. Para isso, utilizei o comando assign. Certamente há formas mais simples e “limpas” de fazer isso. Mas para os fins deste post, a estratégia empregada serve. Para saber mais sobre a estrutura de ambientes do R, veja isto.

Agora que as classes já existem, podemos “instanciá-las”. Primeiramente os  lobos :

lobos = list()
for(i in 1:num_lobos)
 lobos[[i]] = Lobo$new()

Agora os coelhos:

coelhos = list()
for(i in 1:num_coelhos)
 coelhos[[i]] = Coelho$new()

Como adiantado nos tópicos acima, os lobos e coelhos existentes são guardados dentro de listas. Agora já estamos prestes a fazer a simulação rodar. Mas antes, é bom criar dois objetos que guardarão as informações de nosso interesse: o número de lobos e coelhos existentes em cada round. Serão dois vetores que, de início, trazem as quantidades iniciais de cada tipo de agente.

num_lobos_no_tempo = num_lobos
num_coelhos_no_tempo = num_coelhos

Agora, pau na máquina:

for(t in 1:rounds){
  # Rodada dos coelhos
  for(coelho in coelhos)
    coelho$reproduz()

  # Rodada dos lobos
  for(lobo in lobos)
    lobo$come_e_reproduz()

  # Atualizando as quantidades de interesse
  num_lobos_no_tempo = c(num_lobos_no_tempo, length(lobos))
  num_coelhos_no_tempo =c(num_coelhos_no_tempo,length(coelhos))

  # Condições sob as quais o loop é interrompido
  if((length(coelhos)==0)|
     (length(lobos)==0)|
     ((length(coelhos)+length(lobos)) > 100000))
    break

  # Imprime na tela os resultados do round
  print(paste("round", t,
              "-- num coelhos =", length(coelhos),
              "-- num lobos =", length(lobos)))
}

E assim, a simulação segue:

pp

Agora podemos compilar e plotar os resultados:

library(ggplot2)

resultados = data.frame(num = c(num_lobos_no_tempo,
                                num_coelhos_no_tempo),
                        animal = rep(c("lobo","coelhos"),
                                       each = rounds + 1),
                        tempo = rep(0:rounds, 2))

ggplot(resultados, aes(x = tempo, y = num, group = animal)) +
   geom_line(aes(color=animal),lwd= 2)

Pronto:

result1

O mais interessante é observar a influência de mudanças nos parâmetros. Esse é um dos objetivos fundamentais de uma análise usando ABM. Criando condições e mecanismos artificiais, podemos alterar características essenciais da situação e obter contra-factuais — e, por consequência uma forma de efeitos causais. Vejam dois exemplos de resultados produzidos por parâmetros diferentes:

Internet a fora, é possível achar inúmeros outros exemplos.

É importante sublinhar que todos os eventos que acontecem nesse modelo simples de simulação são aleatórios. Coelhos se reproduzem, lobos caçam… etc… Tudo ocorre como se fosse um sorteio. Por isso, rodar a mesma simulação duas vezes pode não produzir os mesmos resultados. O que se costuma fazer é repetir diversas vezes todo o processo e plotar diversos gráficos de linha; cada um representando uma “linha do tempo alternativa”. Assim, podemos observar se há um padrão, apesar do caráter estocástico.

Foi isso, por exemplo, que fizeram Bernardo Furtado e  Isaque Eberhardt em um trabalho bem recente, em que procuraram simular o funcionamento básico de uma economia com ABM. Vejamos gráficos abaixo, reproduzidos desse artigo:

bernardo1bernardo2


Com isso dá pra ter uma ideia um pouco mais tangível sobre o que são ABMs e quais as suas utilidades. Quem de fato executar esses códigos aqui apresentados logo perceberá que a simulação se torna muito lenta nos rounds em que há grande quantidade de agentes. Às vezes, por qualquer razão, o número de lobos cai muito e há uma explosão na população de coelhos. Como estamos fazendo um loop que percorre cada agente um-a-um, rounds com, digamos, 30 mil coelhos acabam por durar particularmente muito… Diversas soluções poderiam ser implementadas: otimizar o código, computação paralela, compilar as funções utilizadas etc… Mas isso é coisa pra outra hora.

 

 

 

Cachorros artificiais: agentes de agent-based modeling usando R (ABM – Parte 1)

(Primeiro Post da série. Veja os outros: Parte 2, Parte 3, Parte 4 e Parte 5)


robot-dog-meets-a-real-doberman-dog

Modelos baseados em agentes (ou Agent-Based Models – ABM) já foram um tópico discutido no blog outras vezes (por exemplo, aqui e aqui). Mas julgo que esse é um assunto “quente”, que sempre vai acabar voltando.

Para aqueles que não sabem ao que estou me referindo, vou dar uma ideia simples e rápida. Trata-se de simulações de algo como “sociedades artificiais” através de modelos computacionais. O propósito NÃO É construir a Matrix ou qualquer coisa do tipo… ao, contrário, é algo bem mais “humilde” e focado. Funciona assim: o pesquisador tem hipóteses sobre como indivíduos ou grupos se comportam, cria um ambiente simples que contém apenas algumas características fundamentais e indispensáveis para a caracterização de uma situação típica e então toca o play. Com isso, pode investigar se os mecanismos interacionais supostos de fato produzem, no nível macro ou agregado, os padrões efetivamente observáveis. Trata-se de um exercício lógico, antes de qualquer outra coisa.

Economistas neoclássicos, trabalhos que envolvem modelagem formal e escolha racional fazem exercícios lógicos de natureza semelhante o tempo todo: “suponha indivíduos homogêneos (idênticos em todas as suas características), com determinado tipo de preferência e orçamento; de fronte a um mercado que se lhes apresente certas quantidades e preços, eles se comportarão desta e daquela maneira, gerando um estado de equilíbrio tal e qual…”. No entanto, nem todo tipo de modelagem deve envolver escolha racional… e nem matemática. Certos problemas são complexos o suficiente para não permitir “forma fechada” (i.e. uma equação bem definida, cuja solução informa um resultado predito). Os ABMs entram em cena exatamente aí.


Um agente é uma entidade conceitual, que pode ser representada de diversas formas e nas mais diversas linguagens de programação. Mas duas propriedades fundamentais devem estar presentes: atributos e ações. Um indivíduo, por exemplo, tem diversas características: idade, peso, altura, raça, sexo, ocupação etc… Esses são os atributos. E também é capaz de agir no mundo de diversas formas: correr, gritar, socializar, procurar emprego etc. Um “agente”, nesse sentido a que me refiro, seria a representação computacional dos aspectos analiticamente relevantes de um indivíduo para determinados fins de pesquisa. Ou seja, ele não contém todos os atributos e ações possíveis de um indivíduo, mas apenas aqueles imprescindíveis para a análise. Isso vai ficar mais claro adiante.

O exemplo que vou dar será utilizando o R, minha “linguagem nativa” (que uso no dia a dia para fazer análises estatísticas). Mas reconheço que ele não é o melhor ambiente pra isso… Existem linguagens de programação específicas para ABM (a mais conhecida é a LOGO, que se tornou bastante popular devido ao software NetLogo, que implementa uma de suas versões). Também bastante utilizada é a linguagem Python — que é uma linguagem de programação completa (não específica para ABM) e tão flexível quando o R (e muito parecida, inclusive). ABMs escritos em Python têm scripts mais simples, diretos e rodam mais rápido; de acordo com minha experiência (mas esse último ponto é controverso).

As estruturas de dados mais simples e comuns no R são vetores, matrizes, listas e data.frames. Basicamente, todos os outros tipos de objetos existentes são algum tipo de combinação ou transformação desses… Além disso, os comandos que executamos também são objetos e são chamados funções. Criar um agente é guardar seus atributos em algum desses tipos de estrutura de dados e representar suas ações por funções. Uma forma conveniente de mesclar atributos e funções num único objeto-agente é fazer uso de um tipo de estrutura de dados pouco utilizada no R, chamada Reference Class (veja mais coisas sobre isso aqui).

Dou um exemplo. Desejamos representar um cachorro como agente. Os atributos relevantes serão a idade e a raça. E as ações possíveis serão latir e nos dizer qual é a sua raça e a sua idade, se lhe perguntarmos (sim! é um cachorro falante! e daí!?). Criaremos uma Reference Class do tipo “Cachorro”

Cachorro = setRefClass("Cachorro",
             fields = c("raca",
                        "idade"),

             methods = list(
                 late = function(){
                     print("Au! Au!")
                 },

                 diz_raca = function(){
                     print(paste("Eu sou um", .self$raca))
                 },

                 diz_idade = function(){
                    print(paste("Tenho", .self$idade,
                                "anos, o que significaria",
                                 7*.self$idade,
                                 "para um humano" ))
                 }
) )

Acredito que para quem conhece um pouco de R, mesmo sem jamais ter visto uma Reference Class antes, o procedimento acima é mais ou menos inteligível. Com o comando setRefClass estamos criando esse novo tipo de objeto — tipo que será chamado “Cachorro”. Ele terá dois atributos, cujos nomes estão declarados no argumento  fields (como vetores character). Depois especificamos as ações que os Cachorros são capazes de realizar: latir, dizer a raça e dizer a idade. Observem uma coisa importante, que é específica das Reference Classes: a expressão .self. Quando .self$raca estamos dizendo que o atributo raça está contido dentro do próprio objeto Cachorro, não é preciso procurá-lo no ambiente principal do R. Essa é a principal característica das Reference Classes: a capacidade de se auto-referenciar. Qualquer pessoa familiarizada com C++,  Java ou Python logo identifica que essa é uma das principais características de qualquer “linguagem orientada a objetos“. Essa expressão simplesmente significa que os objetos criados são auto-contidos: trazem consigo informações, dados e também os métodos para acessá-los, modificá-los e utilizá-los.

Tá… e agora? Agora que definimos as propriedades de um cachorro em abstrato, o próximo passo é efetivamente criar um (é como se tivéssemos definido a “idéia” de cachorro e agora fossemos de fato criar um “cachorro empírico”).

Jimmy = Cachorro$new(raca = "Vira-latas", idade = 4)

Acredito que o código acima seja mais o menos intuitivo. Mas é bom discuti-lo. Observem que estamos utilizando o $ para acessar uma função que está “dentro” do objeto Cachorro, chamada new(). Essa não era uma das ações definidas no argumento methods (late, diz_idade, diz_raca). Trata-se de uma função presente em todo e qualquer objeto do tipo Reference Class, que significa, em termos simples, “crie pra mim uma espécie ou instancia empírica dessa classe”. Informamos as características daquele exemplar particular de cachorro (Vira-latas, com 4 anos). E pronto, fiat Jimmy. Esse é o Jimmy “por dentro”:

jimmy1

Ele é capaz de latir, dizer a idade e a sua raça:

jimmy2

Vamos agora criar novamente a classe Cachorro, mas com duas novas capacidades de ação: dar a pata e abaixá-la. Além dessas duas novas funções, que deverão ser informada dentro da lista passada para o argumento methods, temos que também definir um novo atributo, o “status” da pata (i.e., se está levantada ou abaixada). Se já estiver levantada e pedirmos mesmo assim para que ele a levante, o cachorro vai nos informar. O mesmo se já estiver abaixada e ainda assim pedirmos a ele para abaixá-la.

Cachorro = setRefClass("Cachorro",
             fields = c("raca",
                        "idade",
                        "pata"),

             methods = list(
                 initialize = function(pata = 0, ...){
                     .self$pata = pata
                     callSuper(...)
                 },
                 late = function(){
                     print("Au! Au!")
                 },

                 diz_raca = function(){
                     print(paste("Eu sou um", .self$raca))
                 },

                 diz_idade = function(){
                    print(paste("Tenho", .self$idade,
                                "anos, o que significaria",
                                 7*.self$idade,
                                 "para um humano" ))
                 },

                 da_pata = function(){
                     if( .self$pata == 0 ){
                         .self$pata = 1
                         print("Levantei a pata")
                     }else{
                         print("Já te dei a pata, oras...!")
                     }
                 },

                 abaixa_pata = function(){
                     if( .self$pata == 0 ){
                         print("Minha pata já está abaixada!")
                     }else{
                         .self$pata = 0
                         print("Abaixei a pata")
                 }
}
) )

Observem que uma outra função teve que ser definida dentro de methods, denominada initialize. Essa função simplesmente especifica valores-padrão que serão passados para todos os agentes daquela classe no momento de sua criação. Neste caso, todos os cachorros começam com pata = 0 (com a pata abaixada). Vejamos agora o que o Tobby, nosso novo cachorro, faz:

jimmy3

Tobby não é bobo. Não peça pra que ele dê a pata ou a abaixe duas vezes seguidas. E Tobby tem a capacidade de “modificar-se a si mesmo”. Quando levanta ou abaixa a pata, ele altera o atributo pata, que existe dentro de si.

O ponto aqui é que Reference Classes são adequadas para fazer uma aproximação operacional dos conceitos de atributos e ações. Poderíamos fazer isso de inúmeros outros modos, sem apelar para programação orientada a objeto. Mas há simplicidade nos códigos acima. Agentes agem (ou, nos termos de Taylor Swift, “players are gonna play”). Essa representação sugere uma analogia com a realidade. Como diria meu amigo Davoud, especialista em ABM, “it’s all about ontology”.

 

 

 

Reflexão sobre o recrutamento dos justiceiros

(Um post mais de Sociais do que de Métodos)

Justiça CegaFico aqui pensando em qual o tamanho da associação entre, de um lado, esse comportamento de juizes, promotores e PF e, de outro, os métodos de recrutamento para esses cargos.

Concursos disputadíssimos, anos de cursinhos caros, frequentemente dedicação integral ao estudo (sem exercício de trabalho remunerado concomitante), paixão pela disputa e competição, vontade de enterrar os outros candidatos. Não raro, já vi gente estudando pra essas coisas que “escondia o ouro”: não revelavam seus modos de estudo, suas melhores bibliografias, suas fontes complementares. Que tipo de personalidades decorrem daí? Não me parece que arrogância e compromisso de justiça sejam adjetivos que caibam tranquilamente numa mesma pessoa.

Com esses métodos, fica também muito clara a origem social de quem estamos recrutando — bem como as prováveis preferências que decorrem dela. Justiceiros, filhos da classe média moralista, famintos por galgar uma posição estável no Estado e garantir mobilidade ascendente; ou, ao menos, impedir a descendente.

A alteridade entre um juiz e um julgado, entre um promotor e um réu, não é simplesmente aquela entre o “inocente que julga” e o “criminoso culpado”, mas sim uma completa impossibilidade de que um “se sinta afetado” pelas mesmas coisas que afetam o outro (“être affecté”, no sentido de Jeanne Favret-Saada. Ah… meus dias de Antropologia). São dois aliens, um frente ao outro.

Frequentemente, um promotor, frente a um menor infrator, sente-se como se fosse feito de outro material. Pode ser até que não consiga sequer sentir empatia — a pesquisa de Thiago Oliveira mostra bem isso. E está em disputa. E assim, às vezes, o julgamento é uma competição com o defensor, com o juiz, com outros promotores .

Moro se sente feito de outro material; de uma qualidade superior não somente ao material de Lula, como ao material das próprias instituições. E a classe média reconhece seu filho.

Estamos fazendo errado. Esses não são os atributos que deveríamos querer para pessoas nessas posições.

Obviamente, essas caracterizações não se aplicam a todos os juízes, promotores, policiais federais. Seria um disparate pensar em “determinação causal” entre recrutamento e comportamento — estou falando de uma correlação, associação. E nem mesmo tenho dados; e afinal, eles não existem. Também não posso negar que os magistrados também têm papel progressista, que o Ministério Público frequentemente é o herói (é só pensar em questões como o trabalho escravo, por exemplo) e que sem a PF seria o caos.

Isso não nega que estamos fazendo errado. Não sei como seria a alternativa, mas não podemos ficar onde estamos.

Repúdio ao relatório técnico sobre as Escolas em SP

Um post breve, apenas para manifestar o profundo DESPREZO e REPÚDIO que sinto acerca do relatório técnico intitulado “Escolas Estaduais com uma única etapa de atendimento e seus reflexos no desempenho dos alunos“, produzido pela Coordenadoria de Informação, Monitoramento e Avaliação Educacional (CIMA), da Secretaria de Educação do Estado de São Paulo.

Acho que eu nunca tinha visto algo tão mal feito, sem critério e ideologicamente enviesado assim…

O argumento principal do relatório é o de que uma estrutura de gestão menos complexa seria melhor para o desempenho escolar. Mas desde quando a oferta de níveis de ensino é uma medida SUFICIENTE de organização e gestão das escolas? E o corpo técnico e administrativo? E os organismos e estruturas de tomadas de decisão? E mais: DE ONDE VEIO ESSA IDEIA!? Quais estudos embasam essa hipótese?

O Inep tem um indicador de complexidade da gestão, que de fato inclui o número de ciclos ofertados como um dos componentes da escala, mas há outros quesitos. Além disso, abertamente reconhece-se, ao lado das potencialidades, os limites de tal escala:

“O indicador de complexidade de gestão das escolas resume em uma única medida as informações de porte, turnos de funcionamento, nível de complexidade das etapas e quantidade de etapas ofertadas. A gestão da escola certamente envolve outros fatores e dimensões não contemplados aqui, entretanto, verifica-se que, mesmo com poucos aspectos contemplados na sua construção o indicador apresenta potencial para contextualização dos resultados das avaliações. O INEP estuda a inclusão de novos quesitos no Censo Escolar visando o aprimoramento deste e de outros indicadores que contribuem para a avaliação do contexto da oferta educacional no País”.

Além desse indicador, o Inep ainda classifica as escolas segundo: nível socioeconômico (Inse), adequação da formação docente e esforço docente. Certamente complexidade da gestão é uma variável importante. No entanto, certamente não é suficiente e nem mesmo temos indicação de que está sendo medida de forma adequada no relatório do CIMA — que nem sequer menciona a existência daquele índice ou define de modo satisfatório a noção de “complexidade da gestão”.

Nas primeiras sete páginas daquele realtório, os autores apresentam os MESMOS DADOS 5 VEZES (uma tabela de frequências, univariada), alterando apenas a forma de agrupar categorias!! Como se, de tanto repetir, fosse aparecer algo diferente.

Mas os problemas são vários:

  1. Não há nenhuma variável de controle. Todas as análises são univariadas ou bivariadas. Não dá pra dizer absolutamente nada sem controles sobre características familiares, características da vizinhança, formação dos professores, aspectos da infraestrutura da escola e variáveis que verdadeiramente digam respeito à gestão.
  2. Não há qualquer referência a nenhum tipo de estudo sobre desempenho dos alunos previamente realizado (e essa é uma literatura enorme). Na ciência, qualquer estudo isolado deve ser alvo de desconfiança. Os achados se estabelecem quando há embasamento em outros achados, convergência de resultados e possibilidade de replicabilidade ou reprodução. Os autores não citam sequer como obter os dados que utilizaram.
  3. Um único indicador é utilizado como variável dependente, o IDESP – que mede desemprenho nas provas do SARESP e Taxas de Aprovação. Há várias medidas de desempenho escolar: (não-)evasão, proficiência em Português e Matemática (medidos inclusive por outras avaliações, como o SAEB-Prova Brasil), o IDEB. O IDESP é o mais obtuso dos indicadores; SUA BASE DE DADOS NEM MESMO É PÚBLICA!!!

E mais: o desempenho, conforme medido em provas é a única coisa que essa política visa maximizar? Educação não é só isso… e não se faz política com um único indicador, Sr. Governador e equipe técnica envolvida na proposta de reestruturação.

Me disponho a dar aulas de Estatística, Econometria, Sociologia da Educação e uso de bases de dados educacionais para esses técnicos de araque da Secretaria Estadual de Educação. E de graça.

***

Um adendo: só pra ilustrar a necessidade de incluir variáveis de controle, é bom reproduzir aqui o breve e excelente post no Facebook feito por Amanda Rossi (original aqui):

A reestruturação escolar é baseada em uma correlação: quanto menos ciclos de ensino, maior a nota da escola. Mas o número de ciclos é apenas uma variável. Há muitas outras que precisariam ser analisadas. Seria interessante, inclusive, estudar o peso de casa uma, para saber qual pode ser a mais determinante na qualidade do ensino. Quer uma amostra de outras variáveis relevantes? Vamos falar da variável socioeconômica.

Analisando os dados das escolas da cidade de São Paulo, descobri algo instigante. As escolas de 3 ciclos – que têm as piores notas, segundo o governo – ficam localizadas principalmente na periferia. São os pontos vermelhos no mapa. Acrescentei ao mapa as áreas de ZEIS-1 da nova Lei de Zoneamento. São as manchas vermelhas. As ZEIS-1 são favelas, ocupações irregulares, assentamentos precários (alguns em área de risco).

Notou uma coincidência absurda entre a localização das escolas de 3 ciclos e as áreas de ZEIS-1? O que isso significa? Que as escolas de 3 ciclos em São Paulo estão concentradas em áreas de maior vulnerabilidade socioeconômica. Dá para desprezar essa variável e dizer que as escolas de 3 ciclos têm pior desempenho simplesmente porque têm 3 ciclos?

12321562_1026415270755879_8882151119085652785_n

 

O espaço de similaridade das pesquisas centradas no ator

[Post de Daniel Little, publicado originalmente em inglês no blog Understanding Society. Tradução para o Sociais & Métodos feita por Thiago Rodrigues Oliveira]

im1

im2

Há um determinado número de abordagens no estudo do mundo social que conferem prioridades especiais aos indivíduos em contextos sociais. A Teoria da Escolha Racional (TER) e a Teoria dos Jogos (Becker, Harsanyi) buscam compreender eventos sociais como o resultado de estratégias e cálculos de atores racionais. A Sociologia Centrada no Ator (SCA) e a teoria pragmatista buscam adentrar em um conhecimento profundo dos quadros e dos modos de ação dos atores (Goffman, Gross). A Sociologia Analítica (SA) busca resolver a lógica do barco de Coleman ao mostrar como fatores sociais de nível macro influenciam o comportamento de indivíduos e como fatores de nível macro resultam de interações entre indivíduos no nível micro (Hedström, Yilikoski). E agent-based models (ABM) trazem sistemas computacionais para representar as formas complexas de interação que ocorrem entre indivíduos levando a eventos sociais (Axelrol, Manzo).

Essas quatro abordagens parecem seguir uma mesma estratégia básica: deduzir eventos sociais a partir do que sabemos sobre os modelos de ação e da composição dos indivíduos que produzem o contexto social. É tentador ver essas quatro formulações distintas como a mesma abordagem básica. Mas isso seria um erro. A distância científica entre Hedström e Goffman, ou entre Goffman e Becker, é grande. TER, SCA e SA trazem pressupostos diferentes para o estudo de atores e diferentes pressupostos sobre o que a explicação social demanda. São distintos paradigmas de pesquisa que geram tipos de produtos de pesquisa qualitativamente distintos. E ABM é uma ferramente que pode ser empregada em cada um desses quadros, mas que melhor se adequa à TER e à SA.

Essa figura quer dizer que abordagens centradas no agente tem mais coisas em comum umas com as outras do que com outras importantes estratégias de metodologias de pesquisa em ciências sociais. É possível codificar essas intuições de alguma maneira? E é possível listar as relações lógicas e pragmáticas que existem entre essas abordagens?

Segue aqui uma tabela que representa alguns dos principais pressupostos metodológicos e ontológicos de cada um desses quadros de pesquisa:

Sociologia Centrada no Ator Sociologia Analítica Teoria da Escolha Racional
Eventos sociais derivam de ações de atores socialmente constituídos em relação uns com os outros Explica eventos como o resultado agregado de ações e interações de indivíduos intencionais Indivíduos se comportam como agentes economicamente racionais. Explica eventos como o resultado agregado dessas ações
Atenção às “grandes” teorias do ator Quadro desejo-crença-oportunidade para atores Racionalidade econômica restrita: preferências consistentes e maximização das utilidades
Atores são formados por relações sociais nas quais eles desenvolvem Modelos causais; comprometimento com a abordagem de mecanismos causais Modelos de equilíbrio: comprometimento com soluções matemáticas de problemas de escolha bem definidos
Contas narrativas do desenvolvimento de eventos sociais geram ações dos atores Preferência pelo barco de Coleman: explicação acontece do micro ao macro e do macro ao micro A Teoria dos Jogos é usada para representar interações entre agentes racionais
Agnóstica sobre fundamentos micro Fortemente associada aos fundamentos micro Fortemente associada aos fundamentos micro

Como se pode pensar as relações que existem entre essas abordagens de pesquisa? Muitas possibilidades existem. O primeiro diagrama representa um espaço de abordagens de pesquisa a tópicos de sociologia em ternos de um diagrama de Venn. U é o universo de de abordagens de pesquisa. A, B, C, e D são abordagens que caem dentro de “Sociologia Analítica”, “Teoria da Escolha Racional”, “Sociologia Centrada no Ator” e “Agent-Based Models”. Cada uma dessas famílias de abordagens de pesquisa foi discutida em posts anteriores, linkados acima. A sobreposição nos conjuntos devem representar a intersecção entre os grupos selecionados: abordagens centradas no ator que usam pré-requisitos da teoria da escolha racional; abordagens da sociologia analítica que usam pré-requisitos da SCA; esforços de pesquisa nos três conjuntos que usam modelos baseados no agente; etc.

O segundo diagrama traz um esforço inicial de identificar aspectos que distinguem essas abordagens em uma estrutura dicotômica. SA e TER compartilham as características de fundamentos micro, enquanto a abordagem fenomenológica não. Esta enfatiza a necessidade por “grandes” teorias do ator, enquanto SA e TER favorecem teorias “magras”. SA distingue o pressuposto de Desejo-crença-oportunidade dos pressupostos mais restritos da racionalidade econômica. E SA está mais interessada em identificar mecanismos causais do que qualquer outra alternativa, enquanto a abordagem fenomenológica favorece narrativas e a TER favorece a criação de modelos de equilíbrio. A linha final desse diagrama traz instâncias de paradigmas explicativos das várias abordagens — notas de Goffman sobre comportamentos sociais em um restaurante, o barco de Coleman, a análise formal do dilema do prisioneiro e a tabela de Skocpol de eventos revolucionários.

Aqui segue uma outra abordagem possível, que pode ser descrito como uma visão “ecológica” das metodologias. Em um post recente eu argumentei que nós podemos pensar um quadro de pesquisa como consistindo de um pequeno conjunto de “genes” (pressupostos metodológicos e ontológicos), os quais depois geram o “fenótipo” dos produtos de pesquisa nas mãos dos grupos de pesquisadores (link).

Nesse sentido, SA e TER compartilham um número de genes e estão abertas a emprestar elementos adicionais no futuro por meio de colaboração de pesquisa (contatos inter-espécies). Cada uma compartilha alguns dos principais pressupostos da SCA, mesmo que postulem estratégias explicativas e teóricas bastante distantes daquelas praticadas pela SCA. As duas “espécies” de quadros de pesquisa estão proximamente relacionadas e prometem estar ainda mais no futuro. Mas ao mesmo tempo a SA pode se tornar um genótipo mais robusto para a pesquisa sociológica ao compartilhar componentes genéticos com seu parceiro ecológico, SCA. Finalmente, por essa medida todas essas três abordagens estão a alguma distância das outras principais abordagens na sociologia: survey, pesquisa quantitativa, pesquisa comparativa e estudos organizacionais.

Eu gostaria de argumentar que a sociologia analítica é intelectualmente ampla o suficiente para abranger entendimentos e métodos essenciais da TER e da SCA como teorias distintas do ator, e que ABM é uma metodologia formal que se adequa bem a um componente do modo de explicação da SA, o componente agregativo (o suporte crescente do barco de Coleman). AB, não é limitada a modelos econômicos do ator e pode incorporar tantos detalhes sobre o ator quando o modelador escolher; assim SCA e achados pragmatistas podem ser incorporados a modelos ABM com o possível custo de perda da determinação do evento final.