Versão: 1.0.0
John Chambers iniciou a criação de um ambiente de análises estatísticas em 1976 no Bell Telephone Laboratories, também conhecido como Bell Labs. Naquela época a computação estatística costumava ser feita por meio de chamadas diretas às funções de bibliotecas Fortran, e tal ambiente foi projetado para oferecer uma abordagem alternativa, mais interativa, e com funções de documentação acessível. Este ambiente foi denominado de ‘S’ e após 1979 o nome passou a ser usado sem as aspas simples.
Em 1988 foi lançada a versão S3, muitas mudanças foram feitas na sintaxe da linguagem, estendendo o conceito de objetos, e novas funcionalidades possibilitavam a passagem de funções para outras funções, como o uso do apply
. Foi publicado o livro The New S Language para introduzir as novas funcionalidades e ajudar os usuários a entender como os códigos deveriam ser escritos.
A linguagem R foi criada em 1991, como uma variante da linguagem S, por Ross Ihaka e Robert Gentleman no Departamento de Estatística da Universidade de Auckland, e foi anunciada para o público em 1993. Neste mesmo ano, a Bell Labs concedeu uma licença exclusiva à StatSci, que posteriormente virou a Insightful Corporation, para desenvolver e vender a linguagem S. A Insightful Corporation adicionou algumas funcionalidades à linguagem, como a adição de uma interface gráfica, e vendia esta implementação como o produto S-PLUS.
Uma das limitações da linguagem S era que ela só estava disponível no pacote comercial S-PLUS, e em 1995, Martin Mächler convenceu Ross e Robert a usarem a GNU General Public License, tornando o R um software livre. Em 1998 foi lançada a última versão da linguagem S, conhecida como S4, que fornecia funcionalidades avançadas de orientação a objetos. Em 2000 a versão 1.0.0 da linguagem R foi lançada publicamente. E em 2008 a TIBCO Software Incorporation adquiriu a Insightful Corporation por 25 milhões de dólares.
O interpretador da linguagem R pode ser instalado em Linux, Mac e Windows1 os passos necessários para a instalação podem ser diferentes de acordo com o sistema operacional utilizado, e encontra-se disponível gratuitamente no Comprehensive R Archive Network (CRAN).
O RStudio é um ambiente de desenvolvimento integrado que inclui console, editor ciente de sintaxe e diversas outras ferramentas, que visam o aumento da produtividade do desenvolvedor. Possui edições gratuitas e comerciais, que podem ser obtidas em RStudio.com.
# adição
2+5
## [1] 7
# subtração
5-2
## [1] 3
# multiplicação
2*5
## [1] 10
# divisão
8/2
## [1] 4
# exponenciação
2^5
## [1] 32
2**5
## [1] 32
# resto da divisão
5%%2
## [1] 1
# igual
3==5
## [1] FALSE
# diferente
3!=5
## [1] TRUE
# maior que
3>5
## [1] FALSE
# menor que
3<5
## [1] TRUE
# maior ou igual
3>=5
## [1] FALSE
# menor ou igual
3<=5
## [1] TRUE
Operações podem ser concatenadas:
((2+5-3)*10)^4/7^4
## [1] 1066.222
Atribuição de valores:
x <- 1
# sobrescreve o conteúdo anterior da variável x
x <- 5
y <- "gol do Grêmio"
Exibindo conteúdo de variáveis:
x
## [1] 5
y
## [1] "gol do Grêmio"
Armazenando o resultado de operações:
x<-2+5
y=5-2
2*5->w
z<-8/2
resultado <- (((x-y)*w)^z)/(x^z)
resultado
## [1] 1066.222
Chamando funções:
sum(1,3,5)
## [1] 9
a<-rep("Aluno",times=3)
a
## [1] "Aluno" "Aluno" "Aluno"
Estas funções buscam e exibem a documentação de funções:
help(sum)
?sd
??plot
Estas funções manipulam o diretório de trabalho:
# verifica o caminho para o diretório de trabalho
getwd()
# define o diretório de trabalho
setwd()
# lista os arquivos presentes no diretório de trabalho
list.files()
# carrega um arquivo binário do diretório de trabalho para o ambiente
load()
# salva o conteúdo de uma variável no diretório de trabalho
save()
Função de concatenação c()
:
number<-c(1, 2, 3, 4, 5)
letter<-c("x", "y", "z", "w", "j")
logico<- c(TRUE, FALSE, FALSE, TRUE, FALSE)
seq<-1:10
complexo<-4i
A função class()
pode ser usada para acessar a classe de um determinado objeto:
class(number)
## [1] "numeric"
A função vector()
cria vetores com valores padrões de uma determinada classe:
a<-vector(mode = "integer", length = 10)
b<-vector("logical", 10)
c<-numeric(10)
d<-character(10)
e<-complex(10)
Números são salvos como numeric
por padrão:
x <- 1
class(x)
## [1] "numeric"
Para explicitar o tipo integer
usa-se L como sufixo do número:
x <- 1L
class(x)
## [1] "integer"
Vetores comportam apenas uma classe de elementos. Quando um vetor é criado com valores pertecentes a classes distintas, é feita uma conversão implícita. Um valor logical
é convertido para numeric
, e um valor numeric
é convertido para character
:
class(c(1, 2, 3))
## [1] "numeric"
class(c("1", "2", "3"))
## [1] "character"
class(c(TRUE, FALSE, FALSE))
## [1] "logical"
class(c("TRUE", "FALSE", "FALSE"))
## [1] "character"
class(c(1, "a", TRUE))
## [1] "character"
class(c(1, "a"))
## [1] "character"
class(c(1, T))
## [1] "numeric"
class(c("a", T))
## [1] "character"
Com esta hierarquia, é possível somar valores lógicos, sendo TRUE
equivalente a 12 na conversão de valores numéricos para lógicos, 0 é convertido para FALSE e qualquer outro valor é convertido em TRUE, e FALSE
equivalente a 0:
logical<- c(TRUE, FALSE, FALSE, TRUE, FALSE)
sum(logico)
## [1] 2
Uma conversão explícita pode ser feita com as funções as.<nome da classe>
:
x<-0:10
x
## [1] 0 1 2 3 4 5 6 7 8 9 10
class(x)
## [1] "integer"
a<-as.numeric(x)
a
## [1] 0 1 2 3 4 5 6 7 8 9 10
class(a)
## [1] "numeric"
b<-as.character(x)
b
## [1] "0" "1" "2" "3" "4" "5" "6" "7" "8" "9" "10"
class(b)
## [1] "character"
c<-as.logical(x)
c
## [1] FALSE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
class(c)
## [1] "logical"
Valores não disponíveis são representados por NA
(Not Available), e valores impossíveis, como o resultado de uma divisão por 0, são representados por NaN
(Not a Number).
x<-c(1, 2, 3, NA)
y<-c("a", "b", "c", NA)
is.na(x)
## [1] FALSE FALSE FALSE TRUE
w<-rep(NA, 10)
w
## [1] NA NA NA NA NA NA NA NA NA NA
class(w)
## [1] "logical"
z<-rep(NA_integer_, 10)
z
## [1] NA NA NA NA NA NA NA NA NA NA
class(z)
## [1] "integer"
a <- c(1, 3, NA, 7, 9)
sum(a)
## [1] NA
sum(a, na.rm=TRUE)
## [1] 20
Todos os objetos possuem atributos:
x<-1:5
x
## [1] 1 2 3 4 5
length(x)
## [1] 5
dim(x)
## NULL
attributes(x)
## NULL
names(x)<-c("a", "b", "c", "d", "e")
x
## a b c d e
## 1 2 3 4 5
attributes(x)
## $names
## [1] "a" "b" "c" "d" "e"
Um vetor da classe factor
é um vetor categórico que possui o atributo levels
:
x<-factor(c("s", "n", "n", "s", "s"))
z<-factor(c("alto", "baixo", "medio"))
x
## [1] s n n s s
## Levels: n s
z
## [1] alto baixo medio
## Levels: alto baixo medio
No R as operações são vetorizadas:
x<-1:5
x
## [1] 1 2 3 4 5
y<-6:10
y
## [1] 6 7 8 9 10
# soma dos valores de ambos os vetores
x+y
## [1] 7 9 11 13 15
# podemos multiplicar um vetor por um número
x*2
## [1] 2 4 6 8 10
x^2
## [1] 1 4 9 16 25
z<-c(x,y)
z
## [1] 1 2 3 4 5 6 7 8 9 10
z+x
## [1] 2 4 6 8 10 7 9 11 13 15
w<-1:3
w+x
## Warning in w + x: longer object length is not a multiple of shorter object
## length
## [1] 2 4 6 5 7
l<-c(T, T, F, T, F, F)
l/2
## [1] 0.5 0.5 0.0 0.5 0.0 0.0
Usamos []
para acessar elementos de vetores:
letter<-c("x", "y", "z", "w", "j")
# acessa o segundo elemento do vetor
letter[2]
## [1] "y"
# podemos usar sequências de valores
letter[2:4]
## [1] "y" "z" "w"
# usamos a função c() para valores não contíguos
letter[c(1, 4)]
## [1] "x" "w"
#usamos números negativos para excluir um ou mais valores
letter[-2]
## [1] "x" "z" "w" "j"
letter[c(-2, -5)]
## [1] "x" "z" "w"
#podemos criar índices numéricos
idx<-c(1, 4)
letter[idx]
## [1] "x" "w"
x<-1:10
# podemos usar operadores relacionais como filtros
x[x>7]
## [1] 8 9 10
# também funciona com caracteres, levando em consideração a ordem lexicográfica
letter[letter>"k"]
## [1] "x" "y" "z" "w"
letter[letter<"k"]
## [1] "j"
letter=="z"
## [1] FALSE FALSE TRUE FALSE FALSE
Funções para identificar valores extremos:
# definindo uma semente para a geração de valores aleatórios
set.seed(1)
s<-sample(-1000:1000, 200)
# procura a posição do maior valor
which.max(s)
## [1] 126
# exibe o maior valor
max(s)
## [1] 997
# exibe o menor valor
min(s)
## [1] -982
# exibe o intervalo dos valores do vetor
range(s)
## [1] -982 997
# cria um vetor lógico
s>0
## [1] TRUE TRUE FALSE FALSE FALSE TRUE FALSE FALSE FALSE TRUE TRUE FALSE
## [13] TRUE TRUE TRUE TRUE FALSE TRUE TRUE TRUE TRUE FALSE TRUE FALSE
## [25] FALSE FALSE TRUE TRUE FALSE FALSE TRUE TRUE FALSE FALSE FALSE FALSE
## [37] FALSE TRUE FALSE TRUE FALSE TRUE TRUE FALSE TRUE FALSE FALSE FALSE
## [49] FALSE TRUE FALSE TRUE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE
## [61] TRUE TRUE TRUE FALSE FALSE TRUE TRUE FALSE TRUE TRUE FALSE TRUE
## [73] FALSE TRUE TRUE FALSE TRUE TRUE TRUE TRUE TRUE FALSE FALSE FALSE
## [85] TRUE TRUE TRUE TRUE TRUE TRUE TRUE FALSE TRUE TRUE TRUE FALSE
## [97] FALSE FALSE TRUE TRUE FALSE TRUE FALSE FALSE TRUE FALSE FALSE FALSE
## [109] FALSE TRUE TRUE FALSE TRUE FALSE FALSE FALSE TRUE TRUE TRUE TRUE
## [121] FALSE TRUE TRUE TRUE FALSE TRUE FALSE FALSE FALSE TRUE TRUE FALSE
## [133] TRUE TRUE FALSE TRUE FALSE TRUE FALSE FALSE FALSE TRUE TRUE FALSE
## [145] TRUE TRUE TRUE TRUE TRUE FALSE TRUE FALSE TRUE TRUE FALSE TRUE
## [157] FALSE FALSE FALSE FALSE TRUE FALSE TRUE FALSE FALSE TRUE FALSE TRUE
## [169] TRUE TRUE FALSE FALSE FALSE FALSE FALSE FALSE TRUE TRUE FALSE FALSE
## [181] TRUE TRUE FALSE FALSE TRUE FALSE TRUE FALSE FALSE TRUE TRUE TRUE
## [193] TRUE TRUE FALSE FALSE FALSE TRUE FALSE FALSE
# cria um vetor com as posições que satisfazem o comando
which(s>0)
## [1] 1 2 6 10 11 13 14 15 16 18 19 20 21 23 27 28 31 32
## [19] 38 40 42 43 45 50 52 56 61 62 63 66 67 69 70 72 74 75
## [37] 77 78 79 80 81 85 86 87 88 89 90 91 93 94 95 99 100 102
## [55] 105 110 111 113 117 118 119 120 122 123 124 126 130 131 133 134 136 138
## [73] 142 143 145 146 147 148 149 151 153 154 156 161 163 166 168 169 170 177
## [91] 178 181 182 185 187 190 191 192 193 194 198
Funções de ordenamento:
x<-c(3, 8, 2, 1, 5, 9, 7, 7, 3)
x
## [1] 3 8 2 1 5 9 7 7 3
# ordena um vetor
sort(x)
## [1] 1 2 3 3 5 7 7 8 9
sort(x, decreasing = T)
## [1] 9 8 7 7 5 3 3 2 1
# informa a ordem na qual cada elemento deve ser acessado para exibir o conteúdo do vetor em ordem crescente
order(x)
## [1] 4 3 1 9 5 7 8 2 6
# exibe o conteúdo do vetor de forma aleatória, e uma única vez, cada posição
sample(x)
## [1] 2 5 3 3 8 1 7 7 9
# elimina as replicatas
unique(x)
## [1] 3 8 2 1 5 9 7
# exibe um vetor lógico referente à posição das replicatas
duplicated(x)
## [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE TRUE
Matrizes são vetores bidimensionais que possuem o atributo dimensão. Por serem vetores, comportam apenas uma classe de elementos:
x<-1:20
x
## [1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
attributes(x)
## NULL
m<-matrix(x, 4, 5)
m
## [,1] [,2] [,3] [,4] [,5]
## [1,] 1 5 9 13 17
## [2,] 2 6 10 14 18
## [3,] 3 7 11 15 19
## [4,] 4 8 12 16 20
attributes(m)
## $dim
## [1] 4 5
dim(x)<-c(4,5)
x
## [,1] [,2] [,3] [,4] [,5]
## [1,] 1 5 9 13 17
## [2,] 2 6 10 14 18
## [3,] 3 7 11 15 19
## [4,] 4 8 12 16 20
identical(x, m)
## [1] TRUE
a<-1:5
b<--1:-5
c<-c(3, 6, 4, 9, 1)
# a função cbind() concatena colunas
m<-cbind(a, b, c)
m
## a b c
## [1,] 1 -1 3
## [2,] 2 -2 6
## [3,] 3 -3 4
## [4,] 4 -4 9
## [5,] 5 -5 1
# a função rbind() concatena linhas
m1<-rbind(a, b, c)
m1
## [,1] [,2] [,3] [,4] [,5]
## a 1 2 3 4 5
## b -1 -2 -3 -4 -5
## c 3 6 4 9 1
# elementos são acessados pelos índices das duas dimenções [linha, coluna]
m[1,3]
## c
## 3
# toda a linha
m[1, ]
## a b c
## 1 -1 3
m[2:3, ]
## a b c
## [1,] 2 -2 6
## [2,] 3 -3 4
# atribuição
m[1,]<-NA
m
## a b c
## [1,] NA NA NA
## [2,] 2 -2 6
## [3,] 3 -3 4
## [4,] 4 -4 9
## [5,] 5 -5 1
Um array
é um vetor que possui mais de duas dimensões:
# criando um vetor multidimensional com 4 matrizes de 5 linhas e 10 colunas
ar<-array(1:200, c(5, 10, 4))
ar
## , , 1
##
## [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
## [1,] 1 6 11 16 21 26 31 36 41 46
## [2,] 2 7 12 17 22 27 32 37 42 47
## [3,] 3 8 13 18 23 28 33 38 43 48
## [4,] 4 9 14 19 24 29 34 39 44 49
## [5,] 5 10 15 20 25 30 35 40 45 50
##
## , , 2
##
## [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
## [1,] 51 56 61 66 71 76 81 86 91 96
## [2,] 52 57 62 67 72 77 82 87 92 97
## [3,] 53 58 63 68 73 78 83 88 93 98
## [4,] 54 59 64 69 74 79 84 89 94 99
## [5,] 55 60 65 70 75 80 85 90 95 100
##
## , , 3
##
## [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
## [1,] 101 106 111 116 121 126 131 136 141 146
## [2,] 102 107 112 117 122 127 132 137 142 147
## [3,] 103 108 113 118 123 128 133 138 143 148
## [4,] 104 109 114 119 124 129 134 139 144 149
## [5,] 105 110 115 120 125 130 135 140 145 150
##
## , , 4
##
## [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
## [1,] 151 156 161 166 171 176 181 186 191 196
## [2,] 152 157 162 167 172 177 182 187 192 197
## [3,] 153 158 163 168 173 178 183 188 193 198
## [4,] 154 159 164 169 174 179 184 189 194 199
## [5,] 155 160 165 170 175 180 185 190 195 200
# acessando a primeira matriz [linha, coluna, matriz]
ar[,,1]
## [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
## [1,] 1 6 11 16 21 26 31 36 41 46
## [2,] 2 7 12 17 22 27 32 37 42 47
## [3,] 3 8 13 18 23 28 33 38 43 48
## [4,] 4 9 14 19 24 29 34 39 44 49
## [5,] 5 10 15 20 25 30 35 40 45 50
Conceitualmente, uma string
é um vetor de caracteres3 independente da quantidade de caracteres o atributo length será sempre igual a 1. Certas operações são recorrentes na manipulação de strings, como a inserção de conteúdo numa dada posição, substituição do conteúdo de uma porção do vetor, ou a busca de um determinado padrão:
x<-20:30
y<-1:4
# adiciona valores num vetor numa posição específica
append(x, y, after = 3)
## [1] 20 21 22 1 2 3 4 23 24 25 26 27 28 29 30
# concatena dois vetores, converte em character
x<-paste("dt", 1:10, sep = "")
x
## [1] "dt1" "dt2" "dt3" "dt4" "dt5" "dt6" "dt7" "dt8" "dt9" "dt10"
Identificando expressões regulares (regex) numa string:
x <- c("16_24cat", "25_34cat", "35_44catch", "45_54Cat", "55_104fat")
# identifica regex por posição
grep("cat", x)
## [1] 1 2 3
# o argumento value = T retorna os valores
grep("cat", x, value = T)
## [1] "16_24cat" "25_34cat" "35_44catch"
# $ é um metacaractere que identifica o término da string
grep("cat$", x, ignore.case = T)
## [1] 1 2 4
# a função grepl() retorna um vetor lógico
grepl("cat$", x, ignore.case = T)
## [1] TRUE TRUE FALSE TRUE FALSE
Metacaractere | Funcionalidade |
---|---|
* | 0 ou mais vezes |
+ | uma ou mais vezes |
? | 0 ou 1 vez |
{n} | exatamente n vezes |
{n,} | pelo menos n vezes |
{n,m} | entre n e m vezes |
^ | início da string |
$ | final da string |
strings <- c("a", "ab", "acb", "accb", "acccb", "accccb")
grep("acb", strings)
## [1] 3
grep("ac*b", strings)
## [1] 2 3 4 5 6
grep("ac+b", strings)
## [1] 3 4 5 6
grep("ac?b", strings)
## [1] 2 3
grep("ac{2}b", strings)
## [1] 4
grep("ac{2,}b", strings)
## [1] 4 5 6
grep("ac{2,3}b", strings)
## [1] 4 5
Listas são tipos especiais de vetores que comportam elementos de diferentes classes:
a <- c(1, 3, NA, 7, 9)
b<-matrix(1:200, 20,10)
c<-"Gol do Gremio"
z<-factor(c("alto", "baixo", "medio"))
ls<-list(a, b, c, z)
# cada elemento da lista aparece com [[]]
ls
## [[1]]
## [1] 1 3 NA 7 9
##
## [[2]]
## [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
## [1,] 1 21 41 61 81 101 121 141 161 181
## [2,] 2 22 42 62 82 102 122 142 162 182
## [3,] 3 23 43 63 83 103 123 143 163 183
## [4,] 4 24 44 64 84 104 124 144 164 184
## [5,] 5 25 45 65 85 105 125 145 165 185
## [6,] 6 26 46 66 86 106 126 146 166 186
## [7,] 7 27 47 67 87 107 127 147 167 187
## [8,] 8 28 48 68 88 108 128 148 168 188
## [9,] 9 29 49 69 89 109 129 149 169 189
## [10,] 10 30 50 70 90 110 130 150 170 190
## [11,] 11 31 51 71 91 111 131 151 171 191
## [12,] 12 32 52 72 92 112 132 152 172 192
## [13,] 13 33 53 73 93 113 133 153 173 193
## [14,] 14 34 54 74 94 114 134 154 174 194
## [15,] 15 35 55 75 95 115 135 155 175 195
## [16,] 16 36 56 76 96 116 136 156 176 196
## [17,] 17 37 57 77 97 117 137 157 177 197
## [18,] 18 38 58 78 98 118 138 158 178 198
## [19,] 19 39 59 79 99 119 139 159 179 199
## [20,] 20 40 60 80 100 120 140 160 180 200
##
## [[3]]
## [1] "Gol do Gremio"
##
## [[4]]
## [1] alto baixo medio
## Levels: alto baixo medio
# a função vector() pode criar listas vazias
ls1<-vector("list", 5)
ls1
## [[1]]
## NULL
##
## [[2]]
## NULL
##
## [[3]]
## NULL
##
## [[4]]
## NULL
##
## [[5]]
## NULL
Listas podem ser acessadas com os operadores []
, [[]]
e $
(para listas nomeadas):
# [] extrai uma lista
ls[1]
## [[1]]
## [1] 1 3 NA 7 9
# [[]] extrai o objeto interno
ls[[1]]
## [1] 1 3 NA 7 9
class(ls[1])
## [1] "list"
class(ls[[1]])
## [1] "numeric"
# posição na lista e posição no elemento
ls[[c(1,2)]]
## [1] 3
ls[[2]][2,]
## [1] 2 22 42 62 82 102 122 142 162 182
names(ls)<-c("Arilson", "Roger", "Paulo Nunes", "Jardel")
ls$Roger
## [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
## [1,] 1 21 41 61 81 101 121 141 161 181
## [2,] 2 22 42 62 82 102 122 142 162 182
## [3,] 3 23 43 63 83 103 123 143 163 183
## [4,] 4 24 44 64 84 104 124 144 164 184
## [5,] 5 25 45 65 85 105 125 145 165 185
## [6,] 6 26 46 66 86 106 126 146 166 186
## [7,] 7 27 47 67 87 107 127 147 167 187
## [8,] 8 28 48 68 88 108 128 148 168 188
## [9,] 9 29 49 69 89 109 129 149 169 189
## [10,] 10 30 50 70 90 110 130 150 170 190
## [11,] 11 31 51 71 91 111 131 151 171 191
## [12,] 12 32 52 72 92 112 132 152 172 192
## [13,] 13 33 53 73 93 113 133 153 173 193
## [14,] 14 34 54 74 94 114 134 154 174 194
## [15,] 15 35 55 75 95 115 135 155 175 195
## [16,] 16 36 56 76 96 116 136 156 176 196
## [17,] 17 37 57 77 97 117 137 157 177 197
## [18,] 18 38 58 78 98 118 138 158 178 198
## [19,] 19 39 59 79 99 119 139 159 179 199
## [20,] 20 40 60 80 100 120 140 160 180 200
Um data.frame
é um tipo especial de lista, onde todos os elementos devem possuir o mesmo length. Por ser uma lista, cada posição comporta elementos de diferentes classes. Do ponto de vista prático, o data.frame
funciona como uma planilha bidimensional formado por vetores de mesmo tamanho, sendo cada vetor uma coluna:
number<-c(1, 2, 3, 4, 5)
letter<-c("x", "y", "z", "w", "j")
logical<- c(TRUE, FALSE, FALSE, TRUE, FALSE)
seq<-1:10
dt<-data.frame(number, letter, logical)
class(dt)
## [1] "data.frame"
# usamos $ para acessar as colunas de um data.frame
dt$letter
## [1] "x" "y" "z" "w" "j"
# vetores de caracteres são interpretados como fatores
class(dt$letter)
## [1] "character"
# argumento stringsAsFactors = F altera este comportamento padrão
dt<-data.frame(number, letter, logical, stringsAsFactors = F)
dt$letter
## [1] "x" "y" "z" "w" "j"
class(dt$letter)
## [1] "character"
# data.frames possuem colnames e rownames como atributos
attributes(dt)
## $names
## [1] "number" "letter" "logical"
##
## $class
## [1] "data.frame"
##
## $row.names
## [1] 1 2 3 4 5
colnames(dt)
## [1] "number" "letter" "logical"
row.names(dt)
## [1] "1" "2" "3" "4" "5"
# acessamos data.frames da mesma forma que matrizes
dt[5,2]
## [1] "j"
Para acessar data.frames podemos usar os operadores []
, [[]]
e $
:
dt<-data.frame(number=c(1, 2, 3, 4, 5),
letter = c("x", "y", "z", "w", "j"),
logical = c(TRUE, FALSE, FALSE, TRUE, FALSE))
# [[ ]] acessa cada coluna por posição
dt[[1]]
## [1] 1 2 3 4 5
# [ ] acessa as coordenadas [linha, coluna]
dt[,1]
## [1] 1 2 3 4 5
# $ acessa a coluna pelo nome
dt$number
## [1] 1 2 3 4 5
# carrega o data.frame mtcars
cars<-mtcars
# mostra as 6 primeiras linhas
head(cars)
## 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
# mostra as 6 ultimas linhas
tail(cars)
## mpg cyl disp hp drat wt qsec vs am gear carb
## Porsche 914-2 26.0 4 120.3 91 4.43 2.140 16.7 0 1 5 2
## Lotus Europa 30.4 4 95.1 113 3.77 1.513 16.9 1 1 5 2
## Ford Pantera L 15.8 8 351.0 264 4.22 3.170 14.5 0 1 5 4
## Ferrari Dino 19.7 6 145.0 175 3.62 2.770 15.5 0 1 5 6
## Maserati Bora 15.0 8 301.0 335 3.54 3.570 14.6 0 1 5 8
## Volvo 142E 21.4 4 121.0 109 4.11 2.780 18.6 1 1 4 2
# data.frames possuem colnames e rownames
colnames(dt)
## [1] "number" "letter" "logical"
row.names(dt)
## [1] "1" "2" "3" "4" "5"
# podemos alterar colnames e rownames
row.names(dt)<-c("a", "b", "c", "d", "e")
# alterando apenas a posição 2
colnames(dt)[2]<-"letras"
# podemos alterar valores específicos de um data.frame
dt[3,1]<-"10"
dt$logical<-as.numeric(dt$logical)
dt$letras<-NA
É possível verificar as ocorrencias de um data.frame em outro:
biometria<-data.frame(nomes=c("Carlos", "Roberto", "Olivio", "Joel"),
altura=c(180, 187, 155, 168),
peso=c(80, 90, 98, 64))
biometria
## nomes altura peso
## 1 Carlos 180 80
## 2 Roberto 187 90
## 3 Olivio 155 98
## 4 Joel 168 64
esportes<-data.frame(nomes=c("Carlos", "Roberto", "Olivio", "Jomar"),
esportes=c("futebol", "remo", "sumo", "maratona"))
esportes
## nomes esportes
## 1 Carlos futebol
## 2 Roberto remo
## 3 Olivio sumo
## 4 Jomar maratona
# retorna um vetor lógico
biometria$nomes %in% esportes$nomes
## [1] TRUE TRUE TRUE FALSE
# pode ser usado como índice
idx<-biometria$nomes %in% esportes$nomes
x<-biometria[idx,]
x
## nomes altura peso
## 1 Carlos 180 80
## 2 Roberto 187 90
## 3 Olivio 155 98
# ordenando data.frames por uma coluna
biometria<-biometria[with(biometria, order(altura)), ]
biometria
## nomes altura peso
## 3 Olivio 155 98
## 4 Joel 168 64
## 1 Carlos 180 80
## 2 Roberto 187 90
Unindo data.frames com a função merge()
:
# independe da ordem dos data.frames
# a busca é feita pelo nome, não pela ordem
# o resultado sempre virá em ordem alfabética
unido<-merge(biometria, esportes, by="nomes")
unido
## nomes altura peso esportes
## 1 Carlos 180 80 futebol
## 2 Olivio 155 98 sumo
## 3 Roberto 187 90 remo
# as informações não disponíveis são preenchidas por NA
# com todos os presentes no primeiro
unido<-merge(biometria, esportes, by="nomes", all.x=T)
unido
## nomes altura peso esportes
## 1 Carlos 180 80 futebol
## 2 Joel 168 64 <NA>
## 3 Olivio 155 98 sumo
## 4 Roberto 187 90 remo
# com todos os presentes no segundo
unido<-merge(biometria, esportes, by="nomes", all.y=T)
unido
## nomes altura peso esportes
## 1 Carlos 180 80 futebol
## 2 Jomar NA NA maratona
## 3 Olivio 155 98 sumo
## 4 Roberto 187 90 remo
# com todos presentes
unido<-merge(biometria, esportes, by="nomes", all=T)
unido
## nomes altura peso esportes
## 1 Carlos 180 80 futebol
## 2 Joel 168 64 <NA>
## 3 Jomar NA NA maratona
## 4 Olivio 155 98 sumo
## 5 Roberto 187 90 remo
Uma das habilidades básicas necessárias para se fazer análises com o R é importar arquivos e fazer conexões com, por exemplo, bancos de dados, e exportar os resultados obtidos em formatos que possam ser lidos pela maioria dos softwares atuais.
Vamos aqui listar algumas funções úteis para a importação de arquivos no R.
source()
A função source()
carrega arquivos de scripts em R e executa os comandos ali contidos.
# Caminho onde o script está salvo
source("/home/usuario/Área de Trabalho/script.R")
load()
A função load()
permite o carregamento de arquivos binários reconhecíveis pelo R. A extensão .RData é reconhecida pelo RStudio.
# Caminho onde o .RData está salvo
load("/home/usuario/Área de Trabalho/arquivo.RData")
A principal função para importar dados tabulares (tabelas, planilhas, etc.) para o R é a read.table()
. Esta função possui vários argumentos que podem ser modificados.
Antes de carregar dados tabulares no R, é importante saber como o dado está organizado (se a separação entre as colunas é feita por tabulação ou por vírgula, por exemplo.)
Alguns argumentos cuja modificação pode ser útil para a importação da tabela:
file
: caminho do diretório onde o arquivo está.header
: se FALSE
, não considera o cabeçalho (se houver) da tabelasep
: como o dado está separado. Se por tabulação, sep = "\t"
, se por vírgula, sep = ","
dec
: como os números decimais são definidos, se com “.” ou “,”.col.names
e row.names
: recebem um vetor contendo os nomes das colunas e das linhas, respectivamente.quote
: atribui um caracter para as aspas. Por padrão, atribui ““.comment.char
: atribui um caracter para ser usado como comentário.skip
: valor numérico. Pula a importação da quantidade definida de linhas.stringsAsFactors
: se uma das colunas da tabela for um vetor de caracteres, a opção TRUE
a considera como um vetor de fatores.Outras duas funções bastante utilizadas são derivadas da função read.table()
. Estas possuem os mesmos argumentos da função read.table()
.
read.delim()
: por default, considera o argumento sep = "\t"
. Útil para a importação de arquivos cujos elementos são separados por tabulações.read.csv()
: por default, considera o argumento sep = ","
. Útil para leitura de arquivos .csv.Quando lidamos com arquivos dos quais desconhecemos a sua estrutura, podemos dispor de algumas estratégias para facilitar a importação deles para o R.
Podemos usar a função readLines()
. Esta função pode abrir uma conexão (ver adiante) com um arquivo e ler o conteúdo de suas linhas. A saída da função é um vetor de caracteres, onde o conteúdo de cada linha do arquivo original compreenderá uma posição do vetor de saída. Este procedimento pode revelar como o dado está organizado: se é um dado tabulado, como os elementos de cada coluna estão separados, etc.
# Irá ler as 10 primeiras linhas do arquivo
readLines("COG.mappings.v9.0.txt", 10)
Uma outra forma de desvendar a estrutura de um arquivo é usando a função scan()
. A saída da função scan()
é um vetor de caracteres onde cada string do arquivo original compreenderá uma posição do vetor de saída.
scan(file = 'COG.mappings.v9.0.txt', nlines = 10, what = character())
As funções citadas anteriormente tem em comum a capacidade de abrirem conexões com arquivos e extraírem as informações neles contidas. Além destas, o R possui muitas outras funções para lidar com outros tipos de arquivos e dados externos ao R.
Pode-se também estabelecer conexões com sites da web:
# url() abre uma conexão com arquivo web
con <- url("http://www.tribunadonorte.com.br/", "r", 10)
x <- readLines(con)
x[1:10]
close(con)
Os objetos do R podem ser salvos em arquivos .RData por meio da função save()
. Uma quantidade indeterminada de objetos podem ser salvos no mesmo arquivo .RData.
save(unido, biometria, esportes, file = "arquivo.RData")
Outra funcionalidade útil é a exportação de objetos tabulares do R para arquivos de texto. Para isso, usamos a função write.table()
. Esta função possui argumentos semelhantes aos da função read.table()
.
Ao usar a função write.table()
, é importante definir o diretório no qual o arquivo será salvo e o tipo de separador usado para separar os elementos (argumento sep
). Segue a seguinte estrutura:
write.table(<objeto>, file = <diretório de destino>, sep = <separador>)
Exemplo:
write.table(table1, file = "arquivo.txt", sep = "\t", row.names = FALSE, quote = FALSE)
Além disso, também como a função read.table()
, write.table()
possui outras funções genéricas como write.csv()
, por exemplo, a qual possui o argumento sep = ","
por default.
A capacidade de escrever funções otimiza a execução de tarefas repetitivas e torna o usuário um desenvolvedor de conteúdo.
Uma função é um objeto capaz de realizar uma ação. Por exemplo, a função mean()
obtém a média de um vetor numérico e a função sqrt()
realiza o cálculo da raiz quadrada de cada elemento de um vetor numérico.
# O resultado da função unique() é usado pela função length()
length(unique(mtcars$cyl))
A correspondência dos argumentos de uma função pode ser feita por meio do nome do argumento ou por meio da posição. Vamos tomar como exemplo a função rnorm()
, que gera um vetor de n elementos que possui valores que obedecem à distribuição normal.
A função possui 3 argumentos: n
(tamanho do vetor a ser criado), mean
(média da distribuição) e sd
(desvio padrão da distribuição), nesta ordem. Se os nome dos argumentos não forem definidos na chamada da função, ela assumirá que o primeiro argumento corresponde ao n, o segundo ao mean e o terceiro ao sd.
Vamos criar um vetor de 100 elementos com média 1 e desvio padrão 2.
# Argumentos da função rnorm
args(rnorm)
## function (n, mean = 0, sd = 1)
## NULL
# Fazendo a correspondência pela posição dos argumentos
rnorm(100, 1, 2)
# Fazendo a correspondência pelo nome dos argumentos
rnorm(mean = 1, n = 100, sd = 2)
Ambas as utilizações irão gerar e mesmo resultado.
Observe, ainda, que as funções podem apresentar argumentos que já possuem uma valor pré-definido. Na função rnorm()
, os argumentos mean()
e sd()
possuem valores pré-definidos.
# A função irá executar mesmo sem o fornecimento dos outros argumentos.
rnorm(n = 100)
Entretanto, observe que o argumento n
não possui valor pré-definido. A ausência deste argumento impossibilita a execução da função.
rnorm()
## Error in rnorm(): argument "n" is missing, with no default
As funções possuem três elementos primordiais:
Algumas propriedades das funções:
function()
cria funções definidas pelo próprio usuário:my_fun <- function(arg1, arg2) { # Argumentos
# Corpo da função
}
# Imprime 12. Não possui argumentos.
f <- function() {
12
}
f()
## [1] 12
# Simplesmente imprime "BU!" com qualquer argumento.
f1 <- function(x) {
"BU!"
}
f1()
## [1] "BU!"
# y possui um valor pré-definido
f2 <- function(x, y = 10) {
x + y
}
f2(2)
## [1] 12
f2(2, 4)
## [1] 6
return()
ou print()
:# Imprimir o resultado calculado
f3 <- function(a, b) {
res <- c()
res[1] <- a^2
res[2] <- b + 1
print(res)
}
f3(2, 4)
## [1] 4 5
make.power <- function(n) {
pow <- function(x) {
x^n
}
pow
}
cube <- make.power(3)
square <- make.power(2)
cube(3)
## [1] 27
square(2)
## [1] 4
Antes de qualquer coisa, precisamos entender o conceito de variáveis livres. As variáveis livres são variáveis que não são argumentos das funções e nem foram definidas dentro da função (no escopo da função). As regras de escopo definem como o R irá tentar buscar o valor correspondente a essa variável livre. Por exemplo:
fun <- function(x, y) {
x + y + z
}
A função acima possui a variável z, porém ela não foi definida nem como argumento nem no escopo da função.
Ambientes correspondem a um conceito abstrato para definir um conjunto de objetos. O ambiente mais usado interativamente pelo usuário é o Global Environment ou ambiente global, que guarda as objetos e funções que construímos em uma sessão do R. Quando estamos trabalhando no console e queremos obter o valor de um objeto, o R irá procurar pelo objeto primeiramente no ambiente global e, se não encontrar, irá procurar nos outros ambientes.
Para se ter uma ideia de quantos e quais os ambientes podem existir, podemos usar a função search()
.
search()
## [1] ".GlobalEnv" "package:BiocStyle" "package:stats"
## [4] "package:graphics" "package:grDevices" "package:utils"
## [7] "package:datasets" "package:methods" "Autoloads"
## [10] "package:base"
Tendo em vista a ideia de ambiente, consideremos a função fun()
definida anteriormente. O valor da variável z é buscado inicialmente no escopo da função, em seguida no ambiente global e, se não encontrado, é buscado nos outros ambientes. Se, após o término da busca, o valor desta variável não for encontrado, a função retornará um erro:
fun <- function(x, y) {
x + y + z
}
fun(1, 3)
## Error in fun(1, 3): object 'z' not found
Mais exemplos:
## Warning in rm(z): object 'z' not found
f4 <- function(x, y) {
x^2 + y/z
}
f4(2, 4)
## Error in f4(2, 4): object 'z' not found
No caso a seguir, o valor da variável z é definido no ambiente global e possibilita a execução da função.
z <- 3
f4 <- function(x, y) {
x^2 + y/z
}
f4(2, 4)
## [1] 5.333333
Criando uma função para adicionar dois números:
# x e y são os argumentos da função definida
# O que a função faz: adiciona dois números
add_num <- function(x, y) {
x + y
}
add_num(x = 2, y = 3)
## [1] 5
Criando uma função para calcular a média de um vetor numérico:
calc_media <- function(vetor) {
sum(vetor)/length(vetor)
}
calc_media(c(1, 2, 3, 4))
## [1] 2.5
Criando uma função que obtenha os valores extremos de um vetor numérico:
# Após criar uma variável dentro do escopo da função, devemos retornar o valor da variável.
obter_extremos <- function(vetor) {
res <- c(min(vetor, na.rm = TRUE), max(vetor, na.rm = TRUE))
print(res)
}
obter_extremos(c(1, 2, 3, 4))
## [1] 1 4
As estruturas de controle permitem a execução de um conjunto de ações seguindo uma ordem lógica. Elas são usadas principalmente quando construímos funções ou expressões mais extensas.
if
/ else
Estas estruturas testam se uma condição é verdadeira e desenvolvem ações a partir desta avaliação.
O controle do fluxo do código é feito por alguns operadores lógicos:
Metacaractere | Funcionalidade |
---|---|
& | Retorna TRUE se todas as expressões forem TRUE |
&& | Avalia apenas o primeiro elemento, retorna TRUE se a expressão for TRUE |
| | Retorna TRUE se pelo menos um elemento da expressão for TRUE |
|| | Avalia apenas o primeiro elemento, retorna TRUE se um dos elementos for TRUE |
! | Inverte o valor lógico |
Estrutura geral:
if (condition) {
# Executar caso a condição acima seja verdadeira
} else {
# Executar caso a condição acima seja falsa
}
if
. Neste caso, se a condição for falsa, nenhuma ação será executada:x <- 10
if (x < 20) {
print("Hello!")
}
## [1] "Hello!"
x <- 30
if (x < 20) {
print("Hello!")
}
# Se x for maior de que 10 a função fará a raiz quadrada de x
x <- 12
if (x > 10) {
sqrt(x)
} else {
x^2
}
## [1] 3.464102
if (x > 15) {
sqrt(x)
} else if (x <= 15 & x > 10) {
x
} else {
x^2
}
## [1] 12
if
/else
para definir uma função:humor <- function(salario) {
if (salario > 10000) {
print(":)")
} else {
print(":(")
}
}
humor(7000)
## [1] ":("
humor(12000)
## [1] ":)"
ifelse
, que apresenta a seguinte estrutura:ifelse( <condição>, <executar, se verdadeiro>, <executar, se falso>)
humor1 <- function(salario) {
ifelse(salario > 10000, ":)", ":(")
}
humor1(7000)
## [1] ":("
humor1(12000)
## [1] ":)"
humor2 <- function(salario) {
ifelse(salario > 10000, ":)", ifelse(salario <= 10000 & salario > 5000, ":|", ":("))
}
humor2(4000)
## [1] ":("
humor2(7000)
## [1] ":|"
humor2(12000)
## [1] ":)"
for
loopO for
loop realiza uma ação por uma quantidade definida de vezes.
Estrutura geral:
for (i in 1:x) {
# Executar comandos tantas vezes quantos elementos houverem na sequência
}
Exemplos:
# A função imprime os resultados subsequentemente
for (i in 1:10){
print(i)
}
## [1] 1
## [1] 2
## [1] 3
## [1] 4
## [1] 5
## [1] 6
## [1] 7
## [1] 8
## [1] 9
## [1] 10
# A função cria um objeto que recebe os valores
f <- function(x) {
res <- c()
for (i in 1:x) {
res[i] <- i
}
res
}
f(3)
## [1] 1 2 3
while
Realiza uma ação enquanto uma determinada condição for verdadeira.
z <- 0
# Executa o loop ate a condição deixar de ser verdadeira
while (z < 5) {
z <- z + 2
print(z)
}
## [1] 2
## [1] 4
## [1] 6
loteria1<-function(jogo, dezenas=60){
if(max(jogo)>dezenas){
stop("Erro: numero jogado maior que numeros possiveis de serem sorteados")
} else {
universo<-1:dezenas
sorteio<-sample(universo, size = length(jogo), replace = FALSE)
match<-sorteio%in%jogo
tentativas<-1
while (sum(match)!=length(jogo)){
tentativas<-tentativas+1
sorteio<-sample(universo, size = length(jogo), replace = FALSE)
match<-jogo%in%sorteio
}
tentativas
}
}
loteria1(c(1, 3, 6, 9, 2, 18), dezenas=18)
## [1] 12892
Assim como existe a função ifelse()
como alternativa à estrutura do if
/ else
para testar condições e executar ações, há funções de loop que podem substituir o for
. Dentre elas, temos a família de funções do apply()
.
apply()
: Aplica uma função sobre as margens de uma matriz (linhas ou colunas). Retorna um vetor.lapply()
: Aplica uma função em cada elemento de uma lista. Retorna uma lista.sapply()
: Aplica uma função em cada elemento de uma lista. Retorna o formato mais simples possível.tapply()
: Aplica uma função sobre subsets de um vetor. Retorna uma lista.Vamos considerar os objetos a seguir:
# Matriz 10x10
m <- matrix(rnorm(100), 10, 10)
# Vetor numérico
x <- sort(m[, 1])
# Vetor de inteiros
y <- 1:20
# Lista contendo os objetos acima
ls <- list(m, x, y)
Vamos supor que queremos calcular a média de cada um dos objetos m, x e y. Com o for
, poderíamos fazer a seguinte operação:
medias <- c()
for (i in 1:length(ls)) {
medias[i] <- mean(ls[[i]])
}
medias
## [1] -0.07641275 -0.09638557 10.50000000
Este resultado pode ser conseguido por meio das funções de loop:
lapply()
Esta função irá calcular a média de cada um dos elementos da lista ls e irá retornar uma lista.
lapply(X = ls, FUN = mean)
## [[1]]
## [1] -0.07641275
##
## [[2]]
## [1] -0.09638557
##
## [[3]]
## [1] 10.5
Observe que a função possui os argumentos X
, que corresponde a lista a ser passada, e FUN
, que corresponde a função a ser executada sobre os elementos da lista.
sapply()
A função sapply()
difere da lapply()
no tipo de objeto que ela retorna. Sempre que possível, a função retornará um vetor atômico ou uma matriz.
sapply(X = ls, FUN = mean)
## [1] -0.07641275 -0.09638557 10.50000000
sapply()
#separando string usando regex
x <- c("16_24cat", "25_34cat", "35_44catch", "45_54Cat", "55_104fat")
# separa o string e gera uma lista
strsplit(x, split = "_")
## [[1]]
## [1] "16" "24cat"
##
## [[2]]
## [1] "25" "34cat"
##
## [[3]]
## [1] "35" "44catch"
##
## [[4]]
## [1] "45" "54Cat"
##
## [[5]]
## [1] "55" "104fat"
# sapply pode organizar a saida em um vetor
sapply(strsplit(x, split = "_"), "[", 2)
## [1] "24cat" "34cat" "44catch" "54Cat" "104fat"
tapply()
Esta função aplicará uma função em cada subgrupo do vetor, divididos de acordo com um fator (categorias). No exemplo abaixo, temos um dataframe com 3 variáveis. Desejamos calcular a média de peso por gênero. Para isso, a função possui o argumento INDEX
, que corresponde a variável categórica que irá dividir o dado em subsets para que a função seja executada em cada um deles.
dt <- data.frame(altura = c("carlos", "jorge", "maria", "denise", "claudia"),
peso = c(75, 87, 50, 67, 60),
genero = c("m", "m", "f", "f", "f"),
stringsAsFactors = F)
dt$genero <- as.factor(dt$genero)
tapply(X = dt$peso, INDEX = dt$genero , FUN = mean)
## f m
## 59 81
apply()
O apply aplicará uma função a uma das margens de uma matriz. As margens são representadas por números: 1 para as linhas e 2 para as colunas. Assim, pode-se aplicar funções sobre cada linha ou cada coluna.
# Função range sobre cada uma das colunas da matriz m
apply(m, 2, range)
## [,1] [,2] [,3] [,4] [,5] [,6] [,7]
## [1,] -1.919747 -1.915195 -1.408567 -1.438685 -0.5563506 -2.171266 -3.536515
## [2,] 1.628870 1.491164 2.060674 2.382165 1.2963766 1.722426 2.142718
## [,8] [,9] [,10]
## [1,] -1.173629 -1.791435 -0.8344695
## [2,] 1.048176 1.747617 1.3406172
# Função range sobre cada uma das linhas da matriz m
apply(m, 1, range)
## [,1] [,2] [,3] [,4] [,5] [,6] [,7]
## [1,] -0.8152324 -3.536515 -0.9018107 -2.889308 -1.419150 -1.574196 -2.171266
## [2,] 2.0606739 1.340617 1.7476171 1.722426 2.382165 1.628870 2.142718
## [,8] [,9] [,10]
## [1,] -1.671483 -1.9197473 -2.551928
## [2,] 1.048176 0.2811705 1.390243
split()
Além da função tapply()
, outra estratégia pode ser usada para aplicar uma função a um subgrupo de um vetor. A função split()
divide um vetor com base em fatores. O resultado dela é uma lista e pode ser usada pela função lapply()
, por exemplo.
x <- c(rnorm(10), runif(10), rnorm(10,1))
# gl() cria fatores
f <- gl(3,10)
# Função split divide um dataframe por um fator
split(x, f)
## $`1`
## [1] 1.51059744 -1.41333785 0.90986670 -0.22241957 0.08483992 -0.32907629
## [7] 0.27191310 0.07693520 0.50195791 -2.06781611
##
## $`2`
## [1] 0.88499425 0.40734387 0.25360591 0.78316510 0.70596249 0.08501087
## [7] 0.74151830 0.87123827 0.95206538 0.35276519
##
## $`3`
## [1] 1.1480375 2.8192390 0.8440176 1.2503488 0.6882930 1.0207541
## [7] 0.4090263 -0.9195312 0.1745574 1.8782829
lapply(split(x, f), mean)
## $`1`
## [1] -0.06765396
##
## $`2`
## [1] 0.603767
##
## $`3`
## [1] 0.9313026
Funções anônimas são aquelas que não são atribuídas a nenhum objeto. Como qualquer outra função, podem ser usadas dentro das funções de loop.
s <- split(airquality, airquality$Month)
# Retorna uma lista
lapply(s, function(x) colMeans(x[, c("Ozone","Solar.R","Wind")]))
## $`5`
## Ozone Solar.R Wind
## NA NA 11.62258
##
## $`6`
## Ozone Solar.R Wind
## NA 190.16667 10.26667
##
## $`7`
## Ozone Solar.R Wind
## NA 216.483871 8.941935
##
## $`8`
## Ozone Solar.R Wind
## NA NA 8.793548
##
## $`9`
## Ozone Solar.R Wind
## NA 167.4333 10.1800
# Retorna uma matriz
sapply(s, function(x) colMeans(x[, c("Ozone","Solar.R","Wind")]))
## 5 6 7 8 9
## Ozone NA NA NA NA NA
## Solar.R NA 190.16667 216.483871 NA 167.4333
## Wind 11.62258 10.26667 8.941935 8.793548 10.1800
# Retorna o vetor sem os NA
sapply(s, function(x) colMeans(x[, c("Ozone","Solar.R","Wind")], na.rm = TRUE))
## 5 6 7 8 9
## Ozone 23.61538 29.44444 59.115385 59.961538 31.44828
## Solar.R 181.29630 190.16667 216.483871 171.857143 167.43333
## Wind 11.62258 10.26667 8.941935 8.793548 10.18000
Uma das maiores aplicações do R na ciência de dados consiste em oferecer uma plataforma gratuita para a análise de virtualmente todos os tipos de dados, especialmente aqueles voltados para a bioinformática. Além disso, outra grande motivação é a geração de gráficos de alta qualidade para publicações. Neste curso, utilizaremos o sistema de plotagem básico do R, que oferece a opção de construção de uma grande quantidade de gráficos e com grande capacidade de customização. É importante estar ciente que existem outros sistemas de plotagem, todos com seus pontos fortes e suas desvantagens. À medida que avançamos no conhecimento da linguagem, vamos descobrindo o que mais nos serve.
Antes de construir gráficos no R, é importante organizar seus dados em data.frames.
Vamos trabalhar com o dataset DNase
, um data.frame contendo dados de um experimento de ELISA para medir a concentração de ma DNase recombinante em soro de rato.
head(DNase)
## Run conc density
## 1 1 0.04882812 0.017
## 2 1 0.04882812 0.018
## 3 1 0.19531250 0.121
## 4 1 0.19531250 0.124
## 5 1 0.39062500 0.206
## 6 1 0.39062500 0.215
Os gráficos são visualizados na aba Plots. Por meio dela, é possível visualizar os outros gráficos que foram construídos (1), dar zoom (2), salvar seu gráfico (3), deletar o gráfico criado (4), ou deletar todos os graficos criados (5).
plot()
A principal função do sistema de plotagem básico do R é a função plot()
.
Esta é uma função genérica e o seu resultado depende do tipo de objeto que ela recebe.
plot(DNase)
A função plot()
irá plotar gráficos combinando todas as variáveis presentes no data.frame.
Apesar de ser útil para termos uma visão geral sobre como as variáveis se relacionam entre si, este tipo de gráfico não é indicado para comunicar nossos resultados com o público.
Alternativamente, podemos estabelecer as variáveis que desejamos para avaliar.
Vamos criar um gráfico de dispersão para avaliar a relação entre duas variáveis: a concentração da enzima no soro (conc
) e a densidade estimada (density
). Para isso, passamos para os eixos x e y do gráfico as colunas do dataframe:
plot(x = DNase$conc, y = DNase$density)
plot()
A função plot()
é útil para a construir gráficos que relacionem duas variáveis. Ao determinar as variáveis do data.frame a serem plotadas, a função se encarrega de plotar automaticamente os nomes dos eixos, o intervalo de cada eixo, o tipo de ponto a ser presentado. Entretanto, todas estas características podem ser customizadas.
Além dos argumentos x
e y
(os eixos do gráfico), a função plot()
recebe outros argumentos:
type
: tipo de plot a ser criado (padrão: “p”, ou gráfico de dispersão)
main
: título do gráficosub
: subtítulo do gráficoxlab
: nome do eixo xylab
: nome do eixo yA função plot()
pode receber ainda outros argumentos secundários relacionados aos parâmetros estéticos do gráfico. Podemos visualizá-los por meio da função par()
.
names(par())
## [1] "xlog" "ylog" "adj" "ann" "ask" "bg"
## [7] "bty" "cex" "cex.axis" "cex.lab" "cex.main" "cex.sub"
## [13] "cin" "col" "col.axis" "col.lab" "col.main" "col.sub"
## [19] "cra" "crt" "csi" "cxy" "din" "err"
## [25] "family" "fg" "fig" "fin" "font" "font.axis"
## [31] "font.lab" "font.main" "font.sub" "lab" "las" "lend"
## [37] "lheight" "ljoin" "lmitre" "lty" "lwd" "mai"
## [43] "mar" "mex" "mfcol" "mfg" "mfrow" "mgp"
## [49] "mkh" "new" "oma" "omd" "omi" "page"
## [55] "pch" "pin" "plt" "ps" "pty" "smo"
## [61] "srt" "tck" "tcl" "usr" "xaxp" "xaxs"
## [67] "xaxt" "xpd" "yaxp" "yaxs" "yaxt" "ylbias"
Dentre os mais usados, temos:
col
: define cores dos elementos do gráficocex
: número (em proporção) que um elemento gráfico deve ser aumentado ou diminuídolwd
: espessura das linhas plotadaslty
: tipo de linha plotada:
las
: estilo dos nomes dos eixos:
pch
: tipo de ponto; etcCom estes argumentos, podemos ter o controle de alguns aspectos do nosso gráfico.
De acordo com os parâmetros vistos anteriormente, vamos plotar novamente nosso gráfico de dispersão customizando estes parâmetros.
plot(DNase$conc, DNase$density,
main = "Concentração x Densidade", xlab = "Concentração",
ylab = "Densidade", pch = 17, col = "violet",
xlim = c(0, 15), ylim = c(0, 3), las = 1)
O pacote básico do R possui uma paleta de cores própria que podem ser usadas para colorir os objetos gráficos produzidos. Ela pode ser listada pela função colors()
:
head(sample(colors()))
## [1] "gray79" "grey60" "grey86" "salmon4" "grey43" "gainsboro"
Como vimos, a função plot()
é a principal função para a construção de gráficos. Entretanto, existem outras funções que controlam isoladamente parâmetros da função plot()
. Dentre elas, temos:
points()
: plota um conjunto de pontos ao gráficolines()
: plota linhas ao gráficotitle()
: define o título do gráficolegend()
: define as legendas do gráficoabline()
: plota uma linha de referência ao gráfico (por exemplo, uma linha média)Estas funções são complementares à função plot()
. Esta, quando usada, dá origem a um novo gráfico e as funções auxiliares citadas acima passam a plotar as informações sobre o gráfico já criado.
# Fazendo o subset do dataset para as duas corridas
run1 <- DNase[DNase$Run == 1,]
run2 <- DNase[DNase$Run == 2,]
# Plotar primeiro a corrida 1 (run1)
plot(run1$conc, run1$density, col = "red",
pch = 16, xlab = "Concentração", ylab = "Densidade")
# Adicionar título ao gráfico
title("Concentração x Densidade")
# Com a função points(), adicionar ao gráfico os pontos da corrida 2 (run2)
points(run2$conc, run2$density, col = "blue",
pch = 17, xlab = "Concentração", ylab = "Densidade")
# Adicionar a legenda
legend(x = "topleft", col = c("red", "blue"), pch = c(16, 17),
legend = c("Run 1", "Run 2"))
Vamos criar um gráfico de dispersão e adicionar a ele o modelo linear da relação entre as duas variáveis.
set.seed(20)
# Criando a variável x
x <- rnorm(100)
e <- rnorm(100, 0, 2)
# Criando a variável y
y <- 0.5 + 2 * x + e
# Plotando
plot(x, y, xlab = "x", ylab = "y")
# Usando a função lm() para criar um modelo linear que explica a relação entre x e y.
model <- lm(y ~ x)
summary(model)
##
## Call:
## lm(formula = y ~ x)
##
## Residuals:
## Min 1Q Median 3Q Max
## -3.9170 -1.3303 0.1328 1.5261 3.6446
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 0.6777 0.1983 3.417 0.000922 ***
## x 2.3596 0.2013 11.719 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 1.983 on 98 degrees of freedom
## Multiple R-squared: 0.5836, Adjusted R-squared: 0.5793
## F-statistic: 137.3 on 1 and 98 DF, p-value: < 2.2e-16
# Usando a função abline() para adicionar o modelo ao gráfico
abline(model, lwd = 1, col = "red")
Além da função plot()
, há outras funções importantes que permitem a construção de outros tipos de gráficos além dos gráficos de dispersão.
Estas funções possuem seus argumentos particulares, mas de forma geral, os gráficos construídos podem ser personalizados de acordo com os parâmetros já discutidos anteriormente.
barplot()
Vamos usar o dataset mtcars
para criar um gráfico de barras que represente o peso dos carros. Para isso, usamos a função barplot()
. Para criar o gráfico de barras, devemos ter um vetor numérico:
# Ordenar os valores
mtcars <- mtcars[order(mtcars$wt),]
# Plotar
barplot(mtcars$wt, las = 2, names.arg = rownames(mtcars), cex.names = 0.6, ylim = c(0, 7), col = "lightgreen")
Vamos adicionar as barras de erro no topo de cada barra em um gráfico de barras.
# Criar um dataframe myData com as informacoes da media, desvio padrao e quantidade de elementos
# para cada categoria de cilindros e gear
myData <- aggregate(mtcars$mpg,
by = list(cyl = mtcars$cyl, gears = mtcars$gear),
FUN = function(x) c(mean = mean(x), sd = sd(x),
n = length(x)))
# Criar colunas para a media, desvio padrao e quantidade de elementos
myData <- do.call(data.frame, myData)
# Calcular o erro
myData$se <- myData$x.sd / sqrt(myData$x.n)
# Nomear as colunas
colnames(myData) <- c("cyl", "gears", "mean", "sd", "n", "se")
# Nomear os grupos
myData$names <- c(paste(myData$cyl, "cyl /",
myData$gears, " gear"))
# Organizar as margens para caber todos os valores
par(mar = c(5, 6, 4, 5) + 0.1)
# Calcular o valor maximo de y para caber os valores da barra de erro
plotTop <- max(myData$mean) +
myData[myData$mean == max(myData$mean), 6] * 3
# Plotar o grafico e obter os valores do centro de cada barra
barCenters <- barplot(height = myData$mean,
names.arg = myData$names,
beside = true, las = 2,
ylim = c(0, plotTop),
cex.names = 0.75, xaxt = "n",
main = "Milhagem por número de cilindros e engrenagens",
ylab = "Milhas por galão",
border = "black", axes = TRUE)
# Adicionar o texto do eixo x
text(x = barCenters, y = par("usr")[3] - 1, srt = 45,
adj = 1, labels = myData$names, xpd = TRUE)
# Adicionar os segmentos
segments(barCenters, myData$mean - myData$se * 2, barCenters,
myData$mean + myData$se * 2, lwd = 1.5)
# Adicionar as barras superiores
arrows(barCenters, myData$mean - myData$se * 2, barCenters,
myData$mean + myData$se * 2, lwd = 1.5, angle = 90,
code = 3, length = 0.05)
boxplot()
Vamos agora ter uma ideia da distribuição dos dados em uma ou mais variáveis. Para isso, podemos usar o boxplot.
boxplot(mtcars$mpg)
Além disso, podemos plotar a distribuição do consumo (mpg
) em função da quantidade de cilindros de cada carro (cyl
), usando a notação mtcars$mpg ~ mtcars$cyl
, que quer dizer: a variável mpg
em função da variável cyl
.
# Plotar o boxplot
boxplot(formula = mtcars$mpg ~ mtcars$cyl, main = "Boxplot",
xlab = "Cilindros", ylab = "Milhas por galão",
col = "cornflowerblue", border = "darkblue")
# Calcular média
media <- tapply(mtcars$mpg, mtcars$cyl, mean)
# Plotar a média
points(media, pch = 16, col = "red")
hist()
O histograma também é conhecido como gráfico de distribuição de frequências.
# Simular um vetor numérico que apresente uma distribuição normal
normal <- rnorm(10000, mean = 0, sd = 1)
# Plotar gráfico de dispersão
plot(normal)
# Plotar o histograma
hist(normal, breaks = 100)
O dataset airquality
mostra dados da qualidade do ar na cidade de Nova York. Vamos avaliar a distribuição da concentração de ozônio na cidade durante o período observado.
# Plotar histograma
hist(airquality$Ozone, col = "red", xlab = "Ozônio")
# Plotar as observações
rug(airquality$Ozone)
# Plotar a mediana
abline(v = median(airquality$Ozone, na.rm = T),col = "blue", lwd = 4)
par()
A função par()
contém diversos elementos estéticos dos gráficos. Seus argumentos podem ser usados nas funções principais, como na função plot()
. Entretanto, a função par()
pode ser usada para setar de forma global os parâmetros dos gráficos criados.
Por exemplo: par(col = "red")
irá setar a coloração de todos os gráficos criados adiante na cor vermelha.
Uma função útil desse recurso é o uso do parâmetro mfrow
. Este permite plotar gráficos lado a lado. Ele recebe um vetor numérico de dois elementos, que representam o número de linhas e de colunas que representação deverá ter:
# Plotar dois gráficos lado a lado (1 linha e 2 colunas)
par(mfrow = c(1, 2))
# Plotar os gráficos
plot(mtcars$mpg, mtcars$cyl)
plot(mtcars$hp, mtcars$wt)
Após a construção dos gráficos, pode-se salvá-los por meio do botão exportar na aba Plots do RStudio.
A própria aba Plots é um dispositivo de visualização (device). Existem outros devices, que fornecem outras formas de visualizar e salvar os gráficos criados. Dentre eles, temos as funções pdf()
, png()
e jpeg()
, por exemplo.
Aqui está um exemplo do uso da função pdf()
para salvar um plot criado em formato pdf:
# Criar um arquivo "plot1.pdf". Ele será criado no diretório de trabalho atual.
pdf(file = "plot1.pdf", width = 10, height = 10)
# Plotar gráficos
plot(mtcars$mpg)
hist(mtcars$wt)
barplot(mtcars$wt)
# Fechar a conexão com o device
dev.off()
Com isso, os gráficos até o fechamento do device (dev.off()
) serão salvos no arquivo criado. O mesmo pode ser feito com as funções png()
e jpeg()
para salvar os gráficos nos formatos png e jpeg.
Pode-se representar os dados presentes em objetos multimensionais, como as matrizes.
# Construir uma matriz
mt <- matrix(1, 10, 10)
mt[4, 6] <- 0
# Construir uma imagem da matriz
image(mt)
# Plot do contorno da matriz
contour(mt)
# Plot da matriz em perspectiva
persp(mt, expand = 0.2)
A matriz volcano
possui informações sobre o relevo de um vulcão ativo na Nova Zelândia.
head(volcano)
## [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13] [,14]
## [1,] 100 100 101 101 101 101 101 100 100 100 101 101 102 102
## [2,] 101 101 102 102 102 102 102 101 101 101 102 102 103 103
## [3,] 102 102 103 103 103 103 103 102 102 102 103 103 104 104
## [4,] 103 103 104 104 104 104 104 103 103 103 103 104 104 104
## [5,] 104 104 105 105 105 105 105 104 104 103 104 104 105 105
## [6,] 105 105 105 106 106 106 106 105 105 104 104 105 105 106
## [,15] [,16] [,17] [,18] [,19] [,20] [,21] [,22] [,23] [,24] [,25] [,26]
## [1,] 102 102 103 104 103 102 101 101 102 103 104 104
## [2,] 103 103 104 105 104 103 102 102 103 105 106 106
## [3,] 104 104 105 106 105 104 104 105 106 107 108 110
## [4,] 105 105 106 107 106 106 106 107 108 110 111 114
## [5,] 105 106 107 108 108 108 109 110 112 114 115 118
## [6,] 106 107 109 110 110 112 113 115 116 118 119 121
## [,27] [,28] [,29] [,30] [,31] [,32] [,33] [,34] [,35] [,36] [,37] [,38]
## [1,] 105 107 107 107 108 108 110 110 110 110 110 110
## [2,] 107 109 110 110 110 110 111 112 113 114 116 115
## [3,] 111 113 114 115 114 115 116 118 119 119 121 121
## [4,] 117 118 117 119 120 121 122 124 125 126 127 127
## [5,] 121 122 121 123 128 131 129 130 131 131 132 132
## [6,] 124 126 126 129 134 137 137 136 136 135 136 136
## [,39] [,40] [,41] [,42] [,43] [,44] [,45] [,46] [,47] [,48] [,49] [,50]
## [1,] 110 110 108 108 108 107 107 108 108 108 108 108
## [2,] 114 112 110 110 110 109 108 109 109 109 109 108
## [3,] 120 118 116 114 112 111 110 110 110 110 109 109
## [4,] 126 124 122 120 117 116 113 111 110 110 110 109
## [5,] 131 130 128 126 122 119 115 114 112 110 110 110
## [6,] 136 135 133 129 126 122 118 116 115 113 111 110
## [,51] [,52] [,53] [,54] [,55] [,56] [,57] [,58] [,59] [,60] [,61]
## [1,] 107 107 107 107 106 106 105 105 104 104 103
## [2,] 108 108 108 107 107 106 106 105 105 104 104
## [3,] 109 109 108 108 107 107 106 106 105 105 104
## [4,] 109 109 109 108 108 107 107 106 106 105 105
## [5,] 110 110 109 109 108 107 107 107 106 106 105
## [6,] 110 110 110 109 108 108 108 107 107 106 106
# Contorno
contour(volcano)
# Perspectiva
persp(volcano, expand = 0.2)
# Imagem
image(volcano)
Pacotes agrupam funções projetadas para atacar um problema específico. Como exemplo é possível citar o pacote data.table
do CRAN, que possui funções para manipulação de grandes quantidades de dados. Pacotes disponíveis em repositórios (como o CRAN, Bioconductor e Github) podem ser instalados por meio de poucas linhas de comando.
Verificando se um pacote já está instalado:
require(affy)
O CRAN é o principal repositório de pacotes do R e possui pacotes com finalidades variadas: importação e exportação de dados, manipulação de grafos, desenvolvimento de pacotes, plotagem, paralelismo.
Instalando o pacote devtools
do CRAN:
install.packages("devtools")
O Bioconductor é o principal repositório de pacotes voltados para a bioinformática. Todo pacote do Bioconductor é classificado em uma de três categorias: pacote de anotação (bancos de dados e dicionários), pacote de dados de experimentos (datasets relacionados a um experimento) ou pacote de software (funcionalidades).
Instalando o pacote geneplast
do Bioconductor:
# tente http:// caso URLs https:// URLs não sejam suportadas
source("https://bioconductor.org/biocLite.R")
biocLite("geneplast")
O Github é um repositório usado por desenvolvedores, individualmente ou em equipe, e possui pacotes feitos em diversas linguagens.
Instalando o pacote transcriptogramer
a partir do Github (requer o pacote devtools
):
# carrega o pacote devtools
library(devtools)
# o pacote transcriptogramer pertence ao usuário arthurvinx
install_github("arthurvinx/transcriptogramer")
A instalação a partir do Github pode ser problemática, pois sistemas operacionais diferentes requerem a instalação de dependências diferentes. O Windows, por exemplo, requer a instalação do Rtools. Como o Github é um repositório pessoal, alguns pacotes podem não conter vinhetas, ou necessitam do argumento adicional da função install_github()
, build_vignettes = T
, para que a vinheta seja construída. Apesar destas barreiras, alguns pacotes encontram-se disponíveis apenas no Github, por falta de interesse do desenvolvedor em publicar o pacote no CRAN/Bioconductor, ou pela dificuldade em cumprir os requisitos impostos pelos repositórios.
Todos os pacotes do Bioconductor possuem uma vinheta, um documento que apresenta a finalidade do pacote. A vinheta de um pacote pode ser visualizada com a função vignette()
:
# transcriptogramer pode ser substituído pelo nome de qualquer outro pacote instalado
vignette("transcriptogramer")
Pacotes também possuem documentações detalhadas das suas funções. Na vinheta do pacote transcriptogramer
é utilizado o dataset GPL570
e a função clusterEnrichment()
, para saber mais detalhes podem ser usados os comandos de ajuda:
??clusterEnrichment
??GPL570
??transcriptogramer
Também é possível navegar pela documentação utilizando a aba Help
do RStudio.
Para saber como um pacote deve ser citado num artigo utilize a função citation()
:
citation("transcriptogramer")
O RStudio
oferece a opção de criação de pacotes com a opção File > New Project
. Ao utilizar esta opção é criada a estrutura básica de um pacote:
DESCRIPTION: Um arquivo de texto a ser editado com as informações do pacote, tais como versão, pacotes requeridos, autores e descrição. As informações deste arquivo são usadas para verificar o conteúdo do pacote e para instalá-lo. A regra de versionamento sugere que a versão do pacote seja composta por X
.Y
.Z
, sendo o Z
incrementado a cada alteração, o Y
sendo incrementado a cada lançamento ou adição de funcionalidades, e o X
sendo incrementado em casos raros de mudanças bruscas ou grandes alterações.
NAMESPACE: Este arquivo descreve tudo que é importado e exportado pelo pacote, e nunca deve ser editado manualmente
. Este arquivo é essencial e deve ser consistente com o que o pacote utiliza e o que se deseja disponibilizar para os usuários. Para descrever isto é necessário o uso de comentários roxygen
, interpretados pelo pacote roxygen2
do CRAN para gerar a documentação das funções.
man: Um diretório que armazena a documentação das funções. Seu conteúdo é gerado e atualizado pela função document()
do pacote devtools
, que gera arquivos .Rd
a partir de comentários roxygen
. A função document()
também atualiza o conteúdo do arquivo NAMESPACE
.
R: Todos os arquivos .R
, contendo códigos referentes às funcionalidades, devem ser armazenados neste diretório.
Outros diretórios podem ser criados manualmente ou por funções.
vignettes: Criado pela função use_vignette()
do pacote devtools
, armazena arquivos para a geração da vinheta.
inst/doc: Os diretórios inst
e doc
podem ser gerados pela função build_vignettes()
do pacote devtools
. O diretório inst
pode ser utilizado para armazenar o arquivo CITATION
, NEWS
e testes unitários além de armazenar o diretório doc
.
src: Este diretório é utilizado para armazenar arquivos feitos em outras linguagens, como arquivos feitos em C
ou C++
.
data: Este diretório é utilizado para armazenar todos os arquivos binários referentes aos datasets do pacote.