Introdução

2017

Estrutura do Curso

Este curso procura apresentar um conjunto de técnicas utéis a cada fase da análise de dados, desde a importação dos dados à comunicação de resultados:

alt text

Estrutura do Curso -- Dia 1

Neste primeiro dia introduzimos a linguagem R, abordamos a recolha de informação, como organizá-la para posterior análise e realização de visualizações exploratórias.

alt text

Estrutura do Curso -- Dias 2, 3, e 4

No 2º, 3º dia e ainda na manhã do 4º dia focar-se-ão os aspectos da transformação dos dados, da modelação e inferência.

alt text

Estrutura do Curso -- Dia 4

Na tarde do 4º dia falar-se-á das ferramentas do RStudio para criar apresentações que possam comunicar os resultados de forma eficaz, atraente e até interativa.

alt text

Referências

Dia 1:

# inclui vários pacotes úteis
install.packages("tidyverse")  
library(tidyverse)

Dias 2, 3 e manhã do dia 4:

Tarde do dia 4:

A linguagem R

O R é uma linguagem de programação usada originalmente para computação estatística.

Foi desenvolvida na Universidade de Auckland nos anos 90 como um projecto open source.

Desde a sua primeira versão estável em 2000 tem ganho popularidade e é hoje uma das linguagens de eleição nas comunidades estatística e de machine learning.

Possui, no fim de 2016, cerca de 8000 bibliotecas especializadas. A maioria encontra-se nos repositórios CRAN, BioConductor e ainda no GitHub.

Usaremos o RStudio, uma aplicação gráfica que permite interagir de uma forma muito produtiva com a consola R.

Este curso assume que todos sabem programar. Faremos de seguida uma apresentação da sintaxe R e dos conceitos/funções úteis no resto do curso.

Ambiente de Trabalho: RStudio

O RStudio está disponível em www.rstudio.com para vários sistemas operativos.

alt text

Tipos de Dados

  • Valores numéricos, strings, lógicos, factores
x <- 1
y <- "Uma string"
z <- TRUE
i <- 1L
class(x); class(y); class(z); class(i)
[1] "numeric"
[1] "character"
[1] "logical"
[1] "integer"

Tipos de Dados

  • Vectores: sequência de valores do mesmo tipo
v1 <- 1:5
v1
[1] 1 2 3 4 5
class(v1)
[1] "integer"
v2 <- c(4:5, -2, 7, -1)
v2
[1]  4  5 -2  7 -1
letters
 [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q"
[18] "r" "s" "t" "u" "v" "w" "x" "y" "z"
letters[1]
[1] "a"
letters[length(letters)]
[1] "z"
letters[1:5]
[1] "a" "b" "c" "d" "e"
letters[1:5][-1]
[1] "b" "c" "d" "e"

Tipos de Dados -- Vector

Gerar vectores

1:9
[1] 1 2 3 4 5 6 7 8 9
seq(1,9)
[1] 1 2 3 4 5 6 7 8 9
seq(1,9,3)
[1] 1 4 7
seq(1,2,len=11)
 [1] 1.0 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 2.0
rep(NA, 4)
[1] NA NA NA NA
rep(1:2, 3)
[1] 1 2 1 2 1 2
v2
[1]  4  5 -2  7 -1
v2 > 0
[1]  TRUE  TRUE FALSE  TRUE FALSE
v2[v2>0]
[1] 4 5 7
v2[!v2>0]
[1] -2 -1
which(v2>0)
[1] 1 2 4

Tipos de Dados

  • Listas: vector genérico que contém vários objetos (que podem ter nomes)
l <- list(a=1:5, b="string", c=c(TRUE,FALSE))
class(l)
[1] "list"
l[1]           # uma sublista com um vector de inteiros
$a
[1] 1 2 3 4 5
l["a"]         # idem
$a
[1] 1 2 3 4 5
l[[1]]         # o vector de inteiros
[1] 1 2 3 4 5
l$a            # idem
[1] 1 2 3 4 5
l[[1]][2] = 0  # alterar o 2º valor do 1º elemento da lista
l$a
[1] 1 0 3 4 5

Tipos de Dados

  • Matrizes: uma coleção de valores dispostos em 2D
m <- matrix(15:24, nrow=2, ncol=5, byrow = TRUE)
m
     [,1] [,2] [,3] [,4] [,5]
[1,]   15   16   17   18   19
[2,]   20   21   22   23   24
class(m)
[1] "matrix"
m[1,]
[1] 15 16 17 18 19
m[,1]
[1] 15 20
m[1,2]
[1] 16
m[,c(1,3,5)]
     [,1] [,2] [,3]
[1,]   15   17   19
[2,]   20   22   24

Tipos de Dados -- Matriz

colnames(m) <- paste0("col",1:5)
rownames(m) <- paste0("row",1:2)
m
     col1 col2 col3 col4 col5
row1   15   16   17   18   19
row2   20   21   22   23   24
m["row1","col2"]
[1] 16
m1 <- matrix(-5:-1, nrow=1)
rbind(m, m1)            # juntar matrizes por linhas
     col1 col2 col3 col4 col5
row1   15   16   17   18   19
row2   20   21   22   23   24
       -5   -4   -3   -2   -1
cbind(m, m1[1:2])       # juntar matrizes por colunas
     col1 col2 col3 col4 col5   
row1   15   16   17   18   19 -5
row2   20   21   22   23   24 -4
c(m)                    # deconstruir matriz
 [1] 15 20 16 21 17 22 18 23 19 24

Tipos de Dados

  • Data frames: uma lista de vectores do mesmo tamanho
df <- data.frame(num=c(27,15,9,64), 
                 char=c('a','b','c','a'), 
                 bool=c(TRUE,FALSE,FALSE,NA))
df
  num char  bool
1  27    a  TRUE
2  15    b FALSE
3   9    c FALSE
4  64    a    NA
class(df)
[1] "data.frame"
nrow(df)
[1] 4
ncol(df)
[1] 3

head(iris,4)  # os datasets estão organizados em data frames
  Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1          5.1         3.5          1.4         0.2  setosa
2          4.9         3.0          1.4         0.2  setosa
3          4.7         3.2          1.3         0.2  setosa
4          4.6         3.1          1.5         0.2  setosa

Tipos de Dados -- Data Frame

df[[1]]             # a 1ª lista do data frame
[1] 27 15  9 64
df$num              # idem
[1] 27 15  9 64
df[,"num"]          # idem
[1] 27 15  9 64
df[c(1,3)]          # um data frame parte do original
  num  bool
1  27  TRUE
2  15 FALSE
3   9 FALSE
4  64    NA
df[c("num","bool")] # idem
  num  bool
1  27  TRUE
2  15 FALSE
3   9 FALSE
4  64    NA
df[c(1,3),c("num","bool")] 
  num  bool
1  27  TRUE
3   9 FALSE

Tipos de Dados -- Data Frame

df$new.col <- ifelse(!df$bool, df$num*5, -10) # adicionar coluna
df
  num char  bool new.col
1  27    a  TRUE     -10
2  15    b FALSE      75
3   9    c FALSE      45
4  64    a    NA      NA

df[,4] <- NULL                                # apagar coluna
df
  num char  bool
1  27    a  TRUE
2  15    b FALSE
3   9    c FALSE
4  64    a    NA

Tipos de Dados -- Data Frame

head(iris,4)
  Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1          5.1         3.5          1.4         0.2  setosa
2          4.9         3.0          1.4         0.2  setosa
3          4.7         3.2          1.3         0.2  setosa
4          4.6         3.1          1.5         0.2  setosa

iris[iris$Sepal.Length == 4.9,]
    Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
2            4.9         3.0          1.4         0.2     setosa
10           4.9         3.1          1.5         0.1     setosa
35           4.9         3.1          1.5         0.2     setosa
38           4.9         3.6          1.4         0.1     setosa
58           4.9         2.4          3.3         1.0 versicolor
107          4.9         2.5          4.5         1.7  virginica

iris[iris$Sepal.Length == 4.9,]$Petal.Length
[1] 1.4 1.5 1.5 1.4 3.3 4.5

Tipos de Dados -- Data Frame

names(iris)
[1] "Sepal.Length" "Sepal.Width"  "Petal.Length" "Petal.Width" 
[5] "Species"     

table(iris$Species)

    setosa versicolor  virginica 
        50         50         50 

summary(iris[,1:4])
  Sepal.Length    Sepal.Width     Petal.Length    Petal.Width   
 Min.   :4.300   Min.   :2.000   Min.   :1.000   Min.   :0.100  
 1st Qu.:5.100   1st Qu.:2.800   1st Qu.:1.600   1st Qu.:0.300  
 Median :5.800   Median :3.000   Median :4.350   Median :1.300  
 Mean   :5.843   Mean   :3.057   Mean   :3.758   Mean   :1.199  
 3rd Qu.:6.400   3rd Qu.:3.300   3rd Qu.:5.100   3rd Qu.:1.800  
 Max.   :7.900   Max.   :4.400   Max.   :6.900   Max.   :2.500  

sapply(iris, class)    # operação aplicada a cada coluna
Sepal.Length  Sepal.Width Petal.Length  Petal.Width      Species 
   "numeric"    "numeric"    "numeric"    "numeric"     "factor" 

Tipos de Dados

  • Factores: variáveis categóricas
class(iris$Species)
[1] "factor"
levels(iris$Species)
[1] "setosa"     "versicolor" "virginica" 
plot(iris$Sepal.Length ~ iris$Species, xlab="Species", ylab="Sepal Length")

plot of chunk unnamed-chunk-13

Tipos de Dados -- Factores

Pode transformar-se strings em factores e definir factores ordenados:

df$char <- factor(df$char, labels=c("a","b","c"))
df$ord  <- ordered(cut(df$num, c(0,10,20,100), 
                       labels=c("Baixo","Medio","Alto")))
df
  num char  bool   ord
1  27    a  TRUE  Alto
2  15    b FALSE Medio
3   9    c FALSE Baixo
4  64    a    NA  Alto

sapply(df[,c(2,4)], class)
$char
[1] "factor"

$ord
[1] "ordered" "factor" 

Na regressão o R cria dummy vars para os factores.

Para remover factores que já não estão a ser utilizados usar a função droplevels().

Funções

dobro <- function(x) {
  2*x
}

ePar <- function(n) {
  n %% 2 == 0
}

dobro(1.5)
[1] 3
dobro(-4:6)
 [1] -8 -6 -4 -2  0  2  4  6  8 10 12

ePar(11)
[1] FALSE
ePar(1:6)
[1] FALSE  TRUE FALSE  TRUE FALSE  TRUE

Fechos (Closures)

As funções do R podem devolver funções que se 'lembram' dos valores das variáveis quando foram criadas (designa-se environment a estes conjuntos de valores):

increment.factory <- function(amount) {
  function(x) x + amount
}

succ   <- increment.factory(1)
jump10 <- increment.factory(10)

succ(5)
[1] 6
jump10(5)
[1] 15

Exemplo

Qual a probabilidade de saírem exactamente três caras em dez lançamentos de uma moeda equilibrada? Três resoluções:

1) Usando a fórmula da binomial: \( {n \choose k} p^k (1-p)^{n-k} = {10 \choose 3} \left(\frac{1}{2}\right)^3 \left(\frac{1}{2}\right)^7 \)

choose(10,3) * (1/2)^3 * (1/2)^7
[1] 0.1171875

2) Usando a função massa de probabilidade da Binomial:

dbinom(3, prob=0.5, size=10)
[1] 0.1171875

3) Simulando:

set.seed(222)
n.sims  <- 1e5
sum(replicate(n.sims, rbinom(1, prob=.5, size=10)==3)) / n.sims
[1] 0.11728

Exemplo

Um passeio aleatório baseado numa moeda equilibrada:

set.seed(222)
n.sims <- 1e3
walk   <- cumsum(ifelse(rbinom(n.sims, prob=.5, size=1)==0, -1, 1))

plot(walk, type='l', main='Passeio Aleatorio')
abline(h=0, lty="dashed", col="darkgrey")

plot of chunk unnamed-chunk-20

Programação Funcional

É possível manipular listas de valores sem usar ciclos explícitos:

n  <- 1000
df <- data.frame(col1=runif(n), col2=rnorm(n), col3=rexp(n))
head(df,3)
        col1        col2      col3
1 0.03562685  0.18488589 0.2916406
2 0.90972808  0.36186461 2.7866127
3 0.83601691 -0.02469412 1.2222748

Calcular a média com ciclos:

means <- rep(NA, ncol(df))
for(col in 1:ncol(df)) {
  means[col] = mean(df[,col])
}
means
[1]  0.49398452 -0.01413925  1.02370468

Programação Funcional

E sem ciclos:

means <- apply(df, 2, mean)
means
       col1        col2        col3 
 0.49398452 -0.01413925  1.02370468 

Podemos facilmente mudar a estatística:

apply(df, 2, sd)
     col1      col2      col3 
0.2935531 0.9912709 0.9781108 

O pacote `purrr`

A base R tem várias funções deste tipo mas apresentamos aqui o pacote purr que as disponibiliza numa forma mais organizada.

As funções map_XXX aplicam uma função a cada um dos elementos dados devolvendo valores de um dado tipo:

library(purrr)

data  <- 1:10L
dobro <- function(x) 2L*x
map_int(data, dobro)
 [1]  2  4  6  8 10 12 14 16 18 20

map_dbl(df, mean)    # Os exemplos anteriores
       col1        col2        col3 
 0.49398452 -0.01413925  1.02370468 
map_dbl(df, sd)
     col1      col2      col3 
0.2935531 0.9912709 0.9781108 

keep(1:10, ~ .x%%2 == 0)  # guardar os pares
[1]  2  4  6  8 10

Composição de funções

É possível compor funções a partir de outras existentes:

isEven <- compose(function(x) x==0, function(x) x%%2) 
keep(data, isEven)
[1]  2  4  6  8 10

Também se pode aplicar uma função sobre todos os elementos:

reduce(c(1,3,5), `+`)
[1] 9
factorial <- function(n) reduce(1:n, `*`, .init=1)
factorial(4)
[1] 24

Exemplo: Regressão linear por grupos

head(mtcars)
                   mpg cyl disp  hp drat    wt  qsec vs am gear carb
Mazda RX4         21.0   6  160 110 3.90 2.620 16.46  0  1    4    4
Mazda RX4 Wag     21.0   6  160 110 3.90 2.875 17.02  0  1    4    4
Datsun 710        22.8   4  108  93 3.85 2.320 18.61  1  1    4    1
Hornet 4 Drive    21.4   6  258 110 3.08 3.215 19.44  1  0    3    1
Hornet Sportabout 18.7   8  360 175 3.15 3.440 17.02  0  0    3    2
Valiant           18.1   6  225 105 2.76 3.460 20.22  1  0    3    1
groups <- split(mtcars, mtcars$cyl) # dividir os carros por cilindrada
head(groups$`4`)
                mpg cyl  disp hp drat    wt  qsec vs am gear carb
Datsun 710     22.8   4 108.0 93 3.85 2.320 18.61  1  1    4    1
Merc 240D      24.4   4 146.7 62 3.69 3.190 20.00  1  0    4    2
Merc 230       22.8   4 140.8 95 3.92 3.150 22.90  1  0    4    2
Fiat 128       32.4   4  78.7 66 4.08 2.200 19.47  1  1    4    1
Honda Civic    30.4   4  75.7 52 4.93 1.615 18.52  1  1    4    2
Toyota Corolla 33.9   4  71.1 65 4.22 1.835 19.90  1  1    4    1

Exemplo: Regressão linear por grupos

apply_lm <- function(df) { fit <- lm(mpg ~ wt, data=df); fit$cyl <- df[1,]$cyl; fit }
models <- map(groups, apply_lm)

draw_lm <- function(model) { 
  with(mtcars,                           plot  (wt, mpg, col = "gray", pch=cyl)); 
  with(mtcars[mtcars$cyl == model$cyl,], points(wt, mpg, col = "blue", pch=cyl)); 
  abline(model, col="red") 
}
map(models, draw_lm)

plot of chunk unnamed-chunk-29plot of chunk unnamed-chunk-29plot of chunk unnamed-chunk-29

$`4`
NULL

$`6`
NULL

$`8`
NULL