Primeiros Passos com o R
|
Parte 2 - Estruturas, seleção e indexação
No R podemos gerar estruturas como:
Para indexar e selecionar elementos pertencentes às diferentes estruturas existem operadores como:
[ ]
: é um seletor que retorna um objeto da mesma classe que o objeto original.
[[ ]]
é usado para extrair elementos de uma lista ou data frame.
$
é usado para extrair elementos nomeados de uma lista ou data frame.
Vamos discutir as principais características das estruturas mencionadas:
Vetores são estruturas de dados básicas do R, que permitem armazenar um conjunto de valores numéricos, caracteres ou lógicos num único objeto. Podemos criar vetores através da função c()
:
## [1] "numeric"
## [1] "character"
## [1] "logical"
Outra forma de obter vetores lógicos é através de uma expressão condicional em que utiliza-se um operador lógico. Os operadores lógicos utilizados no R são:
Operador | Operação |
---|---|
> | Maior que |
< | Menor que |
>= | Maior ou igual que |
<= | Menor ou igual que |
== | Igual |
!= | Diferente |
Além dos operadores lógicos temos os operadores relacionais: &, | e ! (e, ou e não).
Podemos testar, por exemplo, se cada um dos elementos de um dado vetor é exatamente igual a um valor, bem como qualquer outra das operações disponíveis e ainda combiná-las fazendo uso dos operadores & e |. Considere o vetor:
## [1] FALSE TRUE TRUE FALSE FALSE FALSE FALSE TRUE FALSE TRUE
## [1] TRUE FALSE FALSE TRUE FALSE TRUE FALSE FALSE FALSE FALSE
## [1] TRUE TRUE TRUE FALSE TRUE TRUE TRUE TRUE TRUE TRUE
## [1] TRUE TRUE TRUE TRUE TRUE FALSE TRUE TRUE TRUE TRUE
## [1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
Caso estejamos interessados em saber quantos dos elementos atendem a condição de interesse, basta somar o vetor lógico resultante com a função sum()
que soma elementos de um vetor. Internamente o R interpreta resultados TRUE como 1 e FALSE como 0. Então, no caso que verificamos quais dos elementosestão entre 0 e 3, podemos verificar quantos elementos atendem a condição da seguinte forma:
## [1] 9
Através da função length()
verificamos quantos elementos há no vetor, e podemos obter dessa forma a proporção de elementos que atendem a condição:
## [1] 10
## [1] 0.9
Um tipo especial de vetor é chamado fator, trata-se de um vetor de caracteres no qual os elementos são tratados como níveis:
## [1] "factor"
## [1] alto medio baixo medio alto alto baixo
## Levels: alto baixo medio
A ordenação dos níveis pode ser alterada através do argumento levels
:
fator <- factor(c("alto", "medio", "baixo", "medio", "alto", "alto", "baixo"),
levels = c("alto", "medio", "baixo"))
class(fator)
## [1] "factor"
## [1] alto medio baixo medio alto alto baixo
## Levels: alto medio baixo
Os elementos pertencentes ao vetor definem sua classe e lembre-se: todos os elementos do vetor devem ser de mesma classe. Caso isso não seja verdade o R forçará os elementos a mudarem de classe, veja:
## [1] "character"
Mesmo possuindo um elemento de cada tipo o R forçou com que todo o vetor passasse a ser da classe character.
Eventualmente, pode ser necessário gerar números aleatórios ou sequências numéricas e armazenar os valores em um vetor. Vejamos algumas funções com estes objetivos (lembre-se de ler a documentação e verificar os argumentos):
seq()
A função seq()
é utilizada para gerar sequências:
## [1] 1 2 3 4 5 6 7 8 9 10
## [1] 1 3 5 7 9
## [1] 1.00 3.25 5.50 7.75 10.00
rep()
A função rep
é utilizada para repetir números:
## [1] 1 1 1 1 1 1 1 1 1 1
## [1] 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3
## [1] 1 1 1 1 1 2 2 2 2 2 3 3 3 3 3
runif
A função runif()
gera números de uma distribuição uniforme, isto é, gera \(n\) números aleatórios entre um limite inferior e um limite superior, em que todos os valores tem a mesma probabilidade de serem sorteados:
## [1] 0.44277246 0.86537281 0.67958720 0.15701933 0.16960730 0.51418147
## [7] 0.62363342 0.07312191 0.92174583 0.34580121
## [1] 14.22720 14.29567 13.53335 14.02630 14.15890 10.92889 13.13355
## [8] 13.91124 14.41972 14.30226
Operações podem ser feitas entre um vetor e um número, como por exemplo multiplicar todos os elementos de um vetor por uma quantidade. Também é possível realizar operações entre vetores de mesmo comprimento.
## [1] 6 4 2 9 10 6 3 3 2 3
## [1] 7 5 3 10 11 7 4 4 3 4
## [1] 12 8 4 18 20 12 6 6 4 6
## [1] 12 8 4 18 20 12 6 6 4 6
## [1] 36 16 4 81 100 36 9 9 4 9
Além disso podemos obter algumas medidas relacionadas a um vetor, tais como comprimento, média, desvio padrão, variância, soma dos elementos, etc. Estas medidas serão vistas com mais detalhes no material em que será apresentada uma análise exploratória completa.
## [1] 10
## [1] 4.8
## [1] 8.177778
## [1] 2.859681
## [1] 48
## [1] 2 10
## [1] 2.0 3.0 3.5 6.0 10.0
O principal operador para seleção em vetores são os colchetes. Vejamos alguns exemplos:
## [1] 90
## [1] 1 23 3 47 6
## [1] 1 23 3
## [1] 1 23 47 90 6 7 8 5 6 10 45
## [1] 23 3 90 6 7 8 5 6 10 45
O uso da seleção condicional é feito quando necessitamos obter elementos do vetor que atendem determinada condição. Na prática, podemos estar interessados em um vetor resultado composto de TRUE ou FALSE ou dos elementos que atendem a dondição de interesse. Vejamos de que forma podemos obter tais resultados:
## [1] TRUE FALSE TRUE TRUE FALSE FALSE FALSE
## [1] 18 31 56
## [1] FALSE FALSE TRUE TRUE FALSE FALSE FALSE
## [1] 31 56
## [1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE
## [1] 18 12 31 56 7 5 9
Matrizes são estruturas que, assim como os vetores, são capazes de armazenar apenas um tipo de informação. Isto é, todos os elementos da matriz devem ser de alguma das classes básicas: numeric, integer, character, complex ou logical. Contudo as matrizes são estruturas bidimensionais, isso significa que possuem linha e coluna. No R, para criação de uma matriz utiliza-se a função matrix()
na qual o usuário informa os elementos sequencialmente por coluna.
## [1] "matrix"
## [,1] [,2] [,3]
## [1,] 1 4 7
## [2,] 2 5 8
## [3,] 3 6 9
Para alterar o preenchimento de forma que seja feito por linha basta utilizar o argumento lógico byrow
. Reforçando: sempre leia a documentação da função.
## [,1] [,2] [,3]
## [1,] 1 2 3
## [2,] 4 5 6
## [3,] 7 8 9
A função dim()
tem duas finalidades: a primeira delas é verificar a dimensão da estrutura, isto é, o número de linhas e o número de colunas. A segunda é gerar uma matriz através de um vetor. Outra forma de verificar número de linhas e colunas é através das funções ncol()
e nrow()
.
## [1] 1 2 3 4 5 6 7 8 9
## NULL
## [,1] [,2] [,3]
## [1,] 1 4 7
## [2,] 2 5 8
## [3,] 3 6 9
## [1] 3 3
## [1] 3
## [1] 3
Para acrescentar linhas e colunas a uma matriz existente basta utilizar as funções rbind()
e cbind()
para linha e coluna respectivamente.
## [,1] [,2]
## [1,] 1 3
## [2,] 2 4
## [,1] [,2]
## [1,] 1 3
## [2,] 2 4
## [3,] 10 10
## [,1] [,2] [,3]
## [1,] 1 3 20
## [2,] 2 4 20
Outras funções importantes para quando trabalhamos com matrizes estão relacionadas à transposição, inversão e criação de matrizes diagonais.
t()
:## [,1] [,2]
## [1,] 1 2
## [2,] 3 4
solve()
:## [,1] [,2]
## [1,] -2 1.5
## [2,] 1 -0.5
diag()
:## [,1] [,2] [,3]
## [1,] 1 0 0
## [2,] 0 4 0
## [3,] 0 0 6
Todas as operações matemáticas que fazem uso de matrizes podem ser feitas no R, contudo com cautela, principalmente quando trabalhamos com multiplicação de matrizes.
Vamos considerar duas matrizes:
## [,1] [,2] [,3]
## [1,] 1 4 7
## [2,] 2 5 8
## [3,] 3 6 9
## [,1] [,2] [,3]
## [1,] 1 1 1
## [2,] 2 2 2
## [3,] 3 3 3
E vejamos como funcionam as operações adição, subtração, multiplicação por escalar, divisão, multiplicação elemento a elemento e multiplicação matricial.
## [,1] [,2] [,3]
## [1,] 2 5 8
## [2,] 3 6 9
## [3,] 4 7 10
## [,1] [,2] [,3]
## [1,] -1 -1 -1
## [2,] 0 0 0
## [3,] 1 1 1
## [,1] [,2] [,3]
## [1,] 2 8 14
## [2,] 4 10 16
## [3,] 6 12 18
## [,1] [,2] [,3]
## [1,] 0.5 2.0 3.5
## [2,] 1.0 2.5 4.0
## [3,] 1.5 3.0 4.5
## [,1] [,2] [,3]
## [1,] 1 4 7
## [2,] 4 10 16
## [3,] 9 18 27
## [,1] [,2] [,3]
## [1,] 30 30 30
## [2,] 36 36 36
## [3,] 42 42 42
A indexação funciona de forma muito parecida com o que foi apresentado para vetores, contudo precisamos especificar agora a linha e a coluna para selecionar elementos pertencentes à matriz. Considerando uma das matrizes anteriormente utilizadas:
## [,1] [,2] [,3]
## [1,] 1 4 7
## [2,] 2 5 8
## [3,] 3 6 9
## [1] 4
## [1] 1 4 7
## [1] 4 5 6
## [,1]
## [1,] 4
## [2,] 5
## [3,] 6
E alguns exemplos para seleção condicional em matrizes são:
## [,1] [,2] [,3]
## [1,] TRUE FALSE FALSE
## [2,] FALSE FALSE FALSE
## [3,] FALSE FALSE FALSE
## [1] 1
## [,1] [,2] [,3]
## [1,] FALSE FALSE TRUE
## [2,] FALSE TRUE TRUE
## [3,] FALSE TRUE TRUE
## [1] 5 6 7 8 9
## [,1] [,2] [,3]
## [1,] FALSE TRUE FALSE
## [2,] FALSE TRUE FALSE
## [3,] FALSE FALSE FALSE
## [1] 4 5
## [,1] [,2] [,3]
## [1,] TRUE FALSE FALSE
## [2,] FALSE TRUE FALSE
## [3,] FALSE FALSE FALSE
## [1] 1 5
Um data frame é composto por diversos vetores de mesmo tamanho que são postos lado a lado numa mesma estrutura. Algo interessante é que não necessariamente estes vetores precisam ser do mesmo tipo.
É o formato mais utilizado para se trabalhar com dados pois comporta a maior parte das situações. Por exemplo, imagine que cada linha representa um indivíduo e cada coluna uma característica de interesse como peso, altura, sexo, etc. Com o data frame é possível organizar a informação de diversos indivíduos e características numa mesma estrutura.
Para criar um data frame no R utilizamos a função data.frame()
e todas as funções para descrição da estrutura funcionam.
df <- data.frame(id = c(1,2,3,4),
nome = c("Pedro", "Maria", "Paulo", "Ana"),
altura = c(1.80, 1.74, 1.90, 1.65),
peso = c(85, 70, 97, 72),
sexo = c("M", "F", "M", "F"))
df
## id nome altura peso sexo
## 1 1 Pedro 1.80 85 M
## 2 2 Maria 1.74 70 F
## 3 3 Paulo 1.90 97 M
## 4 4 Ana 1.65 72 F
## [1] "id" "nome" "altura" "peso" "sexo"
## [1] "data.frame"
## [1] 4 5
## [1] 5
## 'data.frame': 4 obs. of 5 variables:
## $ id : num 1 2 3 4
## $ nome : Factor w/ 4 levels "Ana","Maria",..: 4 2 3 1
## $ altura: num 1.8 1.74 1.9 1.65
## $ peso : num 85 70 97 72
## $ sexo : Factor w/ 2 levels "F","M": 2 1 2 1
## [1] 4
## [1] 5
Tal como para matrizes, as funções cbind()
e rbind()
funcionam, contudo é possível acrescentar linhas e colunas de outras maneiras.
## id nome altura peso sexo coluna
## 1 1 Pedro 1.80 85 M 0
## 2 2 Maria 1.74 70 F 0
## 3 3 Paulo 1.90 97 M 0
## 4 4 Ana 1.65 72 F 0
## id nome altura peso sexo
## 1 1 Pedro 1.80 85 M
## 2 2 Maria 1.74 70 F
## 3 3 Paulo 1.90 97 M
## 4 4 Ana 1.65 72 F
## 5 0 nome 0.00 0 x
No caso de acrescentar uma nova coluna a um data frame é possível utilizar o operador $.
## id nome altura peso sexo coluna_nova
## 1 1 Pedro 1.80 85 M 0
## 2 2 Maria 1.74 70 F 0
## 3 3 Paulo 1.90 97 M 0
## 4 4 Ana 1.65 72 F 0
Para indexação ainda é possível utilizar os colchetes, tal como o que foi visto para vetores e matrizes. O operador $ também é válido para selecionar uma coluna inteira.
## [1] 85
## id nome altura peso sexo coluna_nova
## 3 3 Paulo 1.9 97 M 0
## [1] Pedro Maria Paulo Ana
## Levels: Ana Maria Paulo Pedro
## [1] Pedro Maria Paulo Ana
## Levels: Ana Maria Paulo Pedro
A seleção condicional pode ser feita de duas formas: uma que segue o mesmo raciocínio do que foi apresentado para as demais estruturas e outra que utiliza a função subset()
. Se corretamente utilizadas, ambas retornam o mesmo resultado.
## id nome altura peso sexo coluna_nova
## 2 2 Maria 1.74 70 F 0
## 4 4 Ana 1.65 72 F 0
## id nome altura peso sexo coluna_nova
## 2 2 Maria 1.74 70 F 0
## 4 4 Ana 1.65 72 F 0
Uma lista pode ser interpretada como um caso especial de vetor, em que cada elemento pode ser uma diferente estrutura. Ou seja, em cada posição da lista podemos armazenar vetores, matrizes, data frames e até mesmo outras listas. Criamos listas através da função list()
.
lista <- list(vetor = c(runif(10)),
matriz = matrix(runif(9), nrow = 3, ncol = 3),
df = data.frame(x = runif(10), y = runif(10)))
lista
## $vetor
## [1] 0.27979550 0.68880731 0.06201166 0.17210869 0.11291905 0.91536054
## [7] 0.84500293 0.61228082 0.09481930 0.14068507
##
## $matriz
## [,1] [,2] [,3]
## [1,] 0.2942782 0.88786446 0.1468437
## [2,] 0.4749152 0.02456385 0.9334984
## [3,] 0.5277088 0.48953694 0.3636645
##
## $df
## x y
## 1 0.81135759 0.65612025
## 2 0.09803007 0.58897782
## 3 0.33648236 0.35317954
## 4 0.62803376 0.07791821
## 5 0.16026588 0.75177904
## 6 0.07723845 0.10186752
## 7 0.35278623 0.21917192
## 8 0.26772165 0.44210850
## 9 0.77872338 0.58560339
## 10 0.03944016 0.43510060
## [1] "list"
## [1] "vetor" "matriz" "df"
## [1] 3
## List of 3
## $ vetor : num [1:10] 0.28 0.689 0.062 0.172 0.113 ...
## $ matriz: num [1:3, 1:3] 0.2943 0.4749 0.5277 0.8879 0.0246 ...
## $ df :'data.frame': 10 obs. of 2 variables:
## ..$ x: num [1:10] 0.811 0.098 0.336 0.628 0.16 ...
## ..$ y: num [1:10] 0.6561 0.589 0.3532 0.0779 0.7518 ...
A indexação pode ser feita com os colchetes ou com o $, o que muda nas duas abordagens é a estrutura do output. Utilizando os colchetes o resultado será uma lista, enquanto que com o $ a estrutura será a mesma do elemento selecionado na lista. Uma outra forma que resulta no mesmo output do operador $ é através do duplo colchete [[]].
## [1] "list"
## $vetor
## [1] 0.27979550 0.68880731 0.06201166 0.17210869 0.11291905 0.91536054
## [7] 0.84500293 0.61228082 0.09481930 0.14068507
## [1] "numeric"
## [1] 0.27979550 0.68880731 0.06201166 0.17210869 0.11291905 0.91536054
## [7] 0.84500293 0.61228082 0.09481930 0.14068507
## [1] "numeric"
## [1] 0.27979550 0.68880731 0.06201166 0.17210869 0.11291905 0.91536054
## [7] 0.84500293 0.61228082 0.09481930 0.14068507
É possível ainda combinar os mecanismos de seleção vistos para acessar elementos de dentro da lista.
## [1] 0.27979550 0.68880731 0.06201166
## [1] 0.47491519 0.02456385 0.93349842
## [1] 0.65612025 0.58897782 0.35317954 0.07791821 0.75177904 0.10186752
## [7] 0.21917192 0.44210850 0.58560339 0.43510060
O mesmo raciocínio é válido para seleção condicional.
## numeric(0)
## [1] 0.4749152 0.4895369 0.3636645
## x y
## 1 0.8113576 0.65612025
## 4 0.6280338 0.07791821
## 9 0.7787234 0.58560339
Em algumas situações podemos estar interessados em converter estruturas, ou seja, transformar uma estrutura em outra. A esta tarefa dá-se o nome de coerção. No R existem dois grupos de funções: as do tipo is.
e as do tipo as.
. As do primeiro tipo verificam se um objeto é de uma determinada classe, enquanto as do segundo são responsáveis pela conversão para uma nova classe.
Considerando os exemplos:
vetor = c(runif(10))
matriz = matrix(runif(9), nrow = 3, ncol = 3)
df = data.frame(x = runif(10), y = runif(10))
## [1] TRUE
## [1] TRUE
## [1] TRUE
## [1] FALSE
## [1] FALSE
## [1] FALSE
## [,1]
## [1,] 0.91889926
## [2,] 0.13961401
## [3,] 0.50599602
## [4,] 0.20003549
## [5,] 0.11221054
## [6,] 0.21848078
## [7,] 0.01783528
## [8,] 0.09407082
## [9,] 0.43920156
## [10,] 0.97206441
## vetor
## 1 0.91889926
## 2 0.13961401
## 3 0.50599602
## 4 0.20003549
## 5 0.11221054
## 6 0.21848078
## 7 0.01783528
## 8 0.09407082
## 9 0.43920156
## 10 0.97206441
## V1 V2 V3
## 1 0.7379016 0.1003507 0.35812702
## 2 0.7274921 0.5124829 0.74684495
## 3 0.5637241 0.9224633 0.05369693
## [1] 0.73790162 0.72749214 0.56372408 0.10035073 0.51248287 0.92246330
## [7] 0.35812702 0.74684495 0.05369693
## x y
## [1,] 0.44795601 0.57224154
## [2,] 0.11089801 0.50524654
## [3,] 0.34964420 0.08145900
## [4,] 0.69083108 0.87221093
## [5,] 0.14376272 0.07318994
## [6,] 0.61976771 0.18520698
## [7,] 0.83918824 0.69227319
## [8,] 0.06187371 0.25415830
## [9,] 0.75435727 0.43582136
## [10,] 0.07261673 0.55226260
Valores perdidos, também chamados de missing, são informações que por algum motivo não puderam ser obtidas. Fique atento, um valor perdido não é 0. Valores perdidos são definidos como NA (not available).
## [1] 1 NA 3 7 NA
A presença de valores perdidos não altera a classe do objeto:
## [1] "numeric"
E podemos verificar se existe algum NA no objeto através da função is.na
.
## [1] FALSE TRUE FALSE FALSE TRUE
Caso seja necessário excluir os valores ausentes pode-se usar a função na.omit(x)
.
## [1] 1 3 7
## attr(,"na.action")
## [1] 2 5
## attr(,"class")
## [1] "omit"
Outros valores especiais similares ao NA são o NaN (not a number), Inf e -Inf (mais ou menos infinito).
## [1] NaN
## [1] Inf
## [1] -Inf
Recomendo fortemente a leitura dos seguintes materiais, os quais usei como base para produção desse texto:
Críticas e sugestões a este material sempre serão bem vindas.
Para entrar em contato comigo, envie uma mensagem para lineuacf@gmail.com.