Erro de medida e ‘atenuação’ dos efeitos estimados


Andrew Gelman publicou um pequeno comentário na Science sobre erro de medida e “atenuação dos efeitos estimados”. O argumento é o seguinte: no modelo clássico de erro de medida, na média suas estimativas são puxadas para baixo. Suponha, então, que você tenha feito um experimento com amostra pequena, com erro de medida, mas ainda assim você tenha encontrado um efeito estimado “significante”. Ora, é tentador argumentar o seguinte: tanto a amostra pequena quanto o erro de medida estão “jogando contra” meu efeito estimado, então é provável que o efeito real seja ainda maior do que o que eu estimei. Parece lógico, não?

Parece, mas não é. E, infelizmente, esse raciocínio ainda engana muitos pesquisadores. Na verdade, em um contexto de efeitos reais pequenos junto com amostras pequenas, é mais provável que aquelas estimativas estatisticamente significantes estejam superestimando o efeito real. O problema aqui é que o ruído das amostras pequenas em conjunto com o viés de seleção de estimativas estatisticamente significantes predomina. Vejamos isso na prática com uma simples simulação.

No código abaixo eu simulo mil estudos com um tamanho amostral fixo (n = 10, n = 20, n = 50, n = 500 e n = 1000). Desses mil estudos, eu seleciono apenas aqueles que são estatisticamente “significantes” e coloco no gráfico o valor estimado do estudo. O valor real do efeito é 0.1, que está representado pela linha vermelha. Vejam que, para amostras até de tamanho 100, todas as estimativas “significantes” da simulação estão superestimando o efeito real. Apenas quando a amostra é grande o suficiente que o efeito atenuante do erro de medida se faz prevalecer, revertendo o resultado.

plot of chunk cars

E se você comparar as estimativas com e sem erro de medida, como faz Gelman, também vai verificar que com amostras pequenas dificilmente uma é sempre maior do que a outra.


Código para simulação:

rm(list = ls())
set.seed(10)
ns = c(10, 20, 50, 100, 500, 1000)
oldpar <- par(mfrow = c(2,3))
for (n in ns) {
  b = 0.1
  x <- rnorm(n)
  y <- b*x 

  coefs <- replicate(1000, {
    xs <- x + rnorm(n)
    ys <- y + rnorm(n)
    coef(summary(lm(ys ~ xs)))[2,]
  })

  coefs <- t(coefs)
  plot(coefs[coefs[,3] > 2, 1], ylim = c(min(c(b, coefs[,1])), max(coefs[,1])),
       xlab = "Significant Experiments", ylab = "'Significant' Estimates",
       main = paste("Sample size =", n), pch = 20)
  abline(h = b, col = "red", lty = 2)
}
par(oldpar)
Anúncios

Data Frames


***

Parte do livro Introdução à análise de dados com R.  Este trabalho está em andamento, o texto é bastante preliminar e sofrerá muitas alterações. 

Quer fazer sugestões? Deixe um comentário abaixo ou, se você sabe utilizar o github, acesse aqui.

Não copie ou reproduza este material sem autorização.

Volte para ver atualizações!

***

Data Frames: seu banco de dados no R

Por que um data.frame?

Até agora temos utilizado apenas dados de uma mesma classe, armazenados ou em um vetor ou em uma matriz. Mas uma base de dados, em geral, é feita de dados de diversas classes diferentes: no exemplo anterior, por exemplo, podemos querer ter uma coluna com os nomes dos funcionários, outra com o sexo dos funcionários, outra com valores… note que essas colunas são de classes diferentes, como textos e números. Como guardar essas informações?

A solução para isso é o data.frame. O data.frame é talvez o formato de dados mais importante do R. No data.frame cada coluna representa uma variável e cada linha uma observação. Essa é a estrutura ideal para quando você tem várias variáveis de classes diferentes em um banco de dados.

Criando um data.frame: data.frame() e as.data.frame()

É possível criar um data.frame diretamente com a função data.frame():

funcionarios <- data.frame(nome = c("João", "Maria", "José"),
                           sexo = c("M", "F", "M"),
                           salario = c(1000, 1200, 1300),
                           stringsAsFactors = FALSE)
funcionarios
##    nome sexo salario
## 1  João    M    1000
## 2 Maria    F    1200
## 3  José    M    1300

Também é coverter outros objetos em um data.frame com a função as.data.frame().

Discutiremos a opção stringsAsFactors = FALSE mais a frente.

Vejamos a estrutura do data.frame. Note que cada coluna tem sua própria classe.

str(funcionarios)
## 'data.frame':    3 obs. of  3 variables:
##  $ nome   : chr  "João" "Maria" "José"
##  $ sexo   : chr  "M" "F" "M"
##  $ salario: num  1000 1200 1300

Nomes de linhas e colunas

O data.frame sempre terá rownames e colnames.

rownames(funcionarios)
## [1] "1" "2" "3"

colnames(funcionarios)
## [1] "nome"    "sexo"    "salario"

Detalhe: a função names() no data.fram trata de suas colunas, pois os elementos fundamentais do data.frame são seus vetores coluna.

names(funcionarios)
## [1] "nome"    "sexo"    "salario"

Não parece tão diferente de uma matriz…

O que ocorreria com o data.frame funcionarios se o transformássemos em uma matriz? Vejamos:

as.matrix(funcionarios)
##      nome    sexo salario
## [1,] "João"  "M"  "1000"
## [2,] "Maria" "F"  "1200"
## [3,] "José"  "M"  "1300"

Perceba que todas as variáveis viraram character! Uma matriz aceita apenas elementos da mesma classe, e é exatamente por isso precisamos de um data.frame neste caso.

Manipulando data.frames como matrizes

Ok, temos mais um objeto do R, o data.frame … vou ter que reaprender tudo novamente? Não! Você pode manipular data.frames como se fossem matrizes!

Praticamente tudo o que vimos para selecionar e modificar elementos em matrizes funciona no data.frame. Podemos selecionar linhas e colunas do nosso data.frame como se fosse uma matriz:

## tudo menos linha 1
funcionarios[-1, ]
##    nome sexo salario
## 2 Maria    F    1200
## 3  José    M    1300

## seleciona primeira linha e primeira coluna (vetor)
funcionarios[1, 1]
## [1] "João"

## seleciona primeira linha e primeira coluna (data.frame)
funcionarios[1, 1, drop = FALSE]
##   nome
## 1 João

## seleciona linha 3, colunas "nome" e "salario"
funcionarios[3 , c("nome", "salario")]
##   nome salario
## 3 José    1300

E também alterar seus valores tal como uma matriz.

## aumento de salario para o João
funcionarios[1, "salario"] <- 1100

funcionarios
##    nome sexo salario
## 1  João    M    1100
## 2 Maria    F    1200
## 3  José    M    1300

Extra do data.frame: selecionando e modificando com $ e [[ ]]

Outras formas alternativas de selecionar colunas em um data.frame são o $ e o [[ ]]:

## Seleciona coluna nome
funcionarios$nome
## [1] "João"  "Maria" "José"

funcionarios[["nome"]]
## [1] "João"  "Maria" "José"

## Seleciona coluna salario
funcionarios$salario
## [1] 1100 1200 1300

funcionarios[["salario"]]
## [1] 1100 1200 1300

Tanto o $ quanto o [[ ]] sempre retornam um vetor como resultado.

Também é possível alterar a coluna combinando $ ou [[ ]] com <-:

## outro aumento para o João
funcionarios$salario[1] <- 1150

## equivalente
funcionarios[["salario"]][1] <- 1150
funcionarios
##    nome sexo salario
## 1  João    M    1150
## 2 Maria    F    1200
## 3  José    M    1300

Extra do data.frame: retornando sempre um data.frame com [ ]

Se você quiser garantir que o resultado da seleção será sempre um data.frame use drop = FALSE ou selecione sem a vírgula:

## Retorna data.frame
funcionarios[ ,"salario", drop = FALSE]
##   salario
## 1    1150
## 2    1200
## 3    1300

## Retorna data.frame
funcionarios["salario"]
##   salario
## 1    1150
## 2    1200
## 3    1300

Tabela resumo: selecionando uma coluna em um data.frame

Resumindo as formas de seleção de uma coluna de um data.frame.

screen-shot-2017-02-07-at-12-02-02-am

Criando colunas novas

Há diversas formas de criar uma coluna nova em um data.frame. O principal segredo é o seguinte: faça de conta que a coluna já exista, selecione ela com $, [,] ou [[]] e atribua o valor que deseja.

Para ilustrar, vamos adicionar ao nosso data.frame funcionarios mais três colunas.

Com $:

funcionarios$escolaridade <- c("Ensino Médio", "Graduação", "Mestrado")

Com [ , ]:

funcionarios[, "experiencia"] <- c(10, 12, 15)

Com [[ ]]:

funcionarios[["avaliacao_anual"]] <- c(7, 9, 10)

Uma última forma de adicionar coluna a um data.frame é, tal como uma matriz, utilizar a função cbind() (column bind).

funcionarios <- cbind(funcionarios,
                      prim_emprego = c("sim", "nao", "nao"),
                      stringsAsFactors = FALSE)

Vejamos como ficou nosso data.frame com as novas colunas:

funcionarios
##    nome sexo salario escolaridade experiencia avaliacao_anual prim_emprego
## 1  João    M    1150 Ensino Médio          10               7          sim
## 2 Maria    F    1200    Graduação          12               9          nao
## 3  José    M    1300     Mestrado          15              10          nao

E agora, temos colunas demais, como remover algumas delas?

Removendo colunas

A forma mais fácil de remover coluna de um data.fram é atribuir o valor NULL a ela:

## deleta coluna prim_emprego
funcionarios$prim_emprego <- NULL

Mas a forma mais segura e universal de remover qualquer elemento de um objeto do R é selecionar tudo exceto aquilo que você não deseja. Isto é, selecione todas colunas menos as que você não quer e atribua o resultado de volta ao seu data.frame:

## deleta colunas 4 e 6
funcionarios <- funcionarios[, c(-4, -6)]

Adicionando linhas

Uma forma simples de adicionar linhas é atribuir a nova linha com <-. Mas cuidado! O que irá acontecer com o data.frame com o código abaixo?

## CUIDADO!
funcionarios[4, ] <- c("Ana", "F", 2000,  15)

Note que nosso data.frame inteiro se transformou em texto! Você sabe explicar por que isso aconteceu? relembrar coerção

str(funcionarios)
## 'data.frame':    4 obs. of  4 variables:
##  $ nome       : chr  "João" "Maria" "José" "Ana"
##  $ sexo       : chr  "M" "F" "M" "F"
##  $ salario    : chr  "1150" "1200" "1300" "2000"
##  $ experiencia: chr  "10" "12" "15" "15"

Antes de prosseguir, transformemos as colunas salario e experiencia em números novamente:

funcionarios$salario <- as.numeric(funcionarios$salario) 

funcionarios$experiencia <- as.numeric(funcionarios$experiencia)

Se os elementos forem de classe diferente, use a função data.frame para evitar coerção:

funcionarios[4, ] <- data.frame(nome = "Ana", sexo = "F",
                                salario = 2000, experiencia = 15,
                                stringsAsFactors = FALSE)

Também é possível adicionar linhas com rbind():

rbind(funcionarios,
      data.frame(nome = "Ana", sexo = "F",
                 salario = 2000,  experiencia = 15,
                 stringsAsFactors = FALSE))

Atenção! Não fique aumentando um data.frame de tamanho adicionando linhas ou colunas. Sempre que possível pré-aloque espaço!

Removendo linhas

Para remover linhas, basta selecionar apenas aquelas linhas que você deseja manter:

## remove linha 4 do data.frame
funcionarios <- funcionarios[-4, ]
## remove linhas em que salario <= 1150
funcionarios <- funcionarios[funcionarios$salario > 1150, ]

Filtrando linhas com vetores logicos

Relembrando: se passarmos um vetor lógico na dimensão das linhas, selecionamos apenas aquelas que são TRUE. Assim, por exemplo, se quisermos selecionar aquelas linhas em que a coluna salario é maior do que um determinado valor, basta colocar esta condição como filtro das linhas:

## Apenas linhas com salario > 1000
funcionarios[funcionarios$salario > 1000, ]
##    nome sexo salario experiencia
## 2 Maria    F    1200          12
## 3  José    M    1300          15

## Apenas linhas com sexo == "F"
funcionarios[funcionarios$sexo == "F", ]
##    nome sexo salario experiencia
## 2 Maria    F    1200          12

Funções de conveniência: subset()

Uma função de conveniência para selecionar linhas e colunas de um data.frame é a função subset(), que tem a seguinte estrutura:

subset(nome_do_data_frame,
       subset = expressao_logica_para_filtrar_linhas,
       select = nomes_das_colunas,
       drop   = simplicar_para_vetor?)

Vejamos alguns exemplos:

## funcionarios[funcionarios$sexo == "F",]
subset(funcionarios, sexo == "F")
##    nome sexo salario experiencia
## 2 Maria    F    1200          12

## funcionarios[funcionarios$sexo == "M", c("nome", "salario")]
subset(funcionarios, sexo == "M", select = c("nome", "salario"))
##   nome salario
## 3 José    1300

Funções de conveniência: with

A função with() permite que façamos operações com as colunas do data.frame sem ter que ficar repetindo o nome do data.frame seguido de $ , [ , ] ou [[]] o tempo inteiro.

Para ilustrar:

## Com o with
with(funcionarios, (salario^3 - salario^2)/log(salario))
## [1] 2.4e+08 3.1e+08

## Sem o with
(funcionarios$salario^3 - funcionarios$salario^2)/log(funcionarios$salario)
## [1] 2.4e+08 3.1e+08

Quatro formas de fazer a mesma coisa (pense em outras formas possíveis):

subset(funcionarios, sexo == "M", select = "salario", drop = TRUE)
## [1] 1300

with(funcionarios, salario[sexo == "M"])
## [1] 1300

funcionarios$salario[funcionarios$sexo == "M"]
## [1] 1300

funcionarios[funcionarios$sexo == "M", "salario"]
## [1] 1300

Aplicando funções no data.frame: sapply e lapply, funções nas colunas (elementos)

Outras duas funções bastante utilizadas no R são as funções sapply() e lapply().

  • As funções sapply e lapply aplicam uma função em cada elemento de um objeto.
  • Como vimos, os elementos de um data.frame são suas colunas. Deste modo, as funções sapply e lapply aplicam uma função nas colunas de um data.frame.
  • A diferença entre uma e outra é que a primeira tenta simplificar o resultado enquanto que a segunda sempre retorna uma lista.

Testando no nosso data.frame:

sapply(funcionarios[3:4], mean)
##     salario experiencia
##        1250          14

lapply(funcionarios[3:4], mean)
## $salario
## [1] 1250
##
## $experiencia
## [1] 14

Filtrando variáveis antes de aplicar funções: filter()

Como data.frames podem ter variáveis de classe diferentes, muitas vezes é conveniente filtrar apenas aquelas colunas de determinada classe (ou que satisfaçam determinada condição). A função Filter() é uma maneira rápida de fazer isso:

# seleciona apenas colunas numéricas
Filter(is.numeric, funcionarios)
##   salario experiencia
## 2    1200          12
## 3    1300          15

# seleciona apenas colunas de texto
Filter(is.character, funcionarios)
##    nome sexo
## 2 Maria    F
## 3  José    M

Juntando filter() com sapply() você pode aplicar funções em apenas certas colunas, como por exemplo, calcular a média e máximo apenas nas colunas numéricas do nosso data.frame:

sapply(Filter(is.numeric, funcionarios), mean)
##     salario experiencia
##        1250          14

sapply(Filter(is.numeric, funcionarios), max)
##     salario experiencia
##        1300          15

Manipulando data.frames

Ainda temos muita coisa para falar de manipulação de data.framese isso merece um espaço especial. Veremos além de outras funções base do R alguns pacotes importantes como dplyr, reshape2 e tidyr em uma seção separada.

Trump e políticas pró-empresa vs políticas pró-mercado


Saber fazer a distinção entre políticas pró-empresa e políticas pró-mercado é fundamental – mas, infelizmente, um ponto em que geralmente ainda há muita confusão entre as pessoas. 

Quando o PT decide dar benefícios para a JBS, por exemplo, isso é uma política pró-empresa – certamente vai beneficiar os atuais donos da JBS, mas dificilmente veremos benefícios para a economia como um todo no longo prazo. 

Outro nome comum para isso é capitalismo de compadres: ao invés de melhorar o ambiente para a livre-iniciativa, vemos surgir um ambiente que favorece os amigos do governo.

Digo isto porque há algum tempo estava querendo escrever um pouco sobre Trump – ou, ao menos, minhas primeiras impressões sobre Trump – que, infelizmente, parece tender para políticas de um capitalismo de compadres. Mas o Zingales acabou de escrever sobre o assunto então apenas deixo aqui o post como sugestão.

Berkeley Initiative for Transparency in the Social Sciences (BITSS) – 2016 meeting


Ontem e hoje houve a reunião da Berkeley Initiative for Transparency in the Social Sciences (BITSS). Além de anunciados os vencedores do último Leamer-Rosenthal Prizes, houve várias apresentações interessantes sobre métodos quantitativos em ciências sociais.

Os dois dias foram  filmados e estão disponíveis no Youtube.

Dia 1:

Dia 2:

Computer age statistical inference e The undoing project


Segue minha sugestão de leitura para as férias de final de ano: um livro de estatística e outro de psicologia/economia comportamental.

Para falar a verdade, ainda não os li, mas já recomendo.

O primeiro livro é do Michael Lewis, sem dúvida um dos melhores cronistas da atualidade (entre outros ótimos livros: Flash Boys, Moneyball, The Big Short). Lewis conta a história da vida e amizade dos dois psicólogos israelenses que começaram a revolução da economia comportamental:Daniel Kahneman e Amos Tversky. Para quem ainda não conhece o trabalho da dupla, vale a pena recomendar de novo o já clássico Thiking, Fast and Slow.

O segundo livro é o mais novo lançamento dos estatísticos Bradley Efron e Trevor Hastie. Os dois fazem um tour histórico e técnico pela revolução computacional dos últimos 60 anos da estatística. Para quem está começando na área, Efron é mais conhecido por seu trabalho no bootstrap; Trevor (junto com Tibshirani), por seus trabalhos em GAMs e modelos esparsos entre outros. Trevor também é co-autor dos já famosos Elements of Statistical Learning e sua recente versão baby An introduction to Statistical Learning — ambos com versões gratuitas na internet (aqui e aqui).