Os tipos básicos de objetos do R são:
Os quatro primeiros tipos são objetos que armazenam dados e que diferem entre si na forma da armazenar e operar com os dados. O último (função) é um tipo objeto especial que recebe algum input e produz um output.
Experimente os comandos listados para se familiarizar com estas estruturas. Note que usamos as funções do tipo is.*() para testar se um objeto é de um determinado tipo. Estas funções são is.vector(), is.matrix(), is.array(), is.data.frame(), is.list(), is.function().
Vetores são o tipo básico e mais simples de objeto para armazenar dados no R. O R é uma linguagem vetorial, e portanto capaz de operar vetores e matrizes diretamente sem a necessidade de loops, como por exemplo em códigos C e/ou Fortran.
No exemplo a seguir mostramos algumas operações com vetores. A função c() ("c" de concatenar) é usada para criar um vetor. Os colchetes [ ] são usados para indicar seleção de elementos. As funções rep(), seq() e o símbolo ":" são usadas para facilitar a criação de vetores que tenham alguma lei de formação.
> x1 <- 10 > x1
[1] 10
> x2 <- c(1, 3, 6) > x2
[1] 1 3 6
> x2[1]
[1] 1
> x2[2]
[1] 3
> length(x2)
[1] 3
> is.vector(x2)
[1] TRUE
> is.matrix(x2)
[1] FALSE
> is.numeric(x2)
[1] TRUE
> is.character(x2)
[1] FALSE
> (x3 <- 1:10)
[1] 1 2 3 4 5 6 7 8 9 10
> (x4 <- seq(0,1, by=0.1))
[1] 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0
> x4[x4 > 0.5]
[1] 0.6 0.7 0.8 0.9 1.0
> x4 > 0.5
[1] FALSE FALSE FALSE FALSE FALSE FALSE TRUE TRUE TRUE TRUE TRUE
> (x5 <- seq(0,1, len=11))
[1] 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0
> x5
[1] 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0
> (x6 <- rep(1, 5))
[1] 1 1 1 1 1
> (x7 <- rep(c(1, 2), c(3, 5)))
[1] 1 1 1 2 2 2 2 2
> (x8 <- rep(1:3, rep(5,3)))
[1] 1 1 1 1 1 2 2 2 2 2 3 3 3 3 3
Um escalar é um vetor de comprimento igual a 1. Os vetores podem ser compostos de números e caracteres ou apenas de um destes tipos. Portanto, adicionando um caracter a um vetor numérico este é transformado em um vetor de caracteres.
> x2
[1] 1 3 6
> c("a", x2)
[1] "a" "1" "3" "6"
> c(x2, "a")
[1] "1" "3" "6" "a"
Diversas operações numéricas podem ser feitas sobre vetores. Uma característica importante da linguagem é a lei da reciclagem que permite operações sobre vetores de tamanhos diferentes.
> x2
[1] 1 3 6
> x2 + 3
[1] 4 6 9
> x2 + 1:3
[1] 2 5 9
> x2 + 1:6
[1] 2 5 9 5 8 12
> (1:3) * x2
[1] 1 6 18
> x2/(1:6)
[1] 1.00 1.50 2.00 0.25 0.60 1.00
> x2^(1:3)
[1] 1 9 216
Vetores são uma estrutura de dados sobre a qual podemos aplicar funções como por exemplo as que fornecem medidas estatísticas.
> (x9 <- round(rnorm(10, mean=70, sd=10)))
[1] 71 71 67 66 76 87 66 87 58 73
> sum(x9)
[1] 722
> mean(x9)
[1] 72.2
> var(x9)
[1] 84.62222
> min(x9)
[1] 58
> max(x9)
[1] 87
> summary(x9)
Min. 1st Qu. Median Mean 3rd Qu. Max. 58.00 66.25 71.00 72.20 75.25 87.00
> fivenum(x9)
[1] 58 66 71 76 87
Criando vetores com elementos repetidos
As funções rep() e seq() do R são úteis para criar vetores de dados que seguem um certo
padrão.
Clique aqui para ver um arquivo de dados. Os comandos a seguir podem ser usados para criar vetores
para cada uma das três colunas iniciais deste arquivo. A primeira coluna pode ser obtida com um dos
dois comandos mostrados inicialmente, a seguir. Os demais reproduzem a segunda e terceira coluna do
arquivo de dados.
> rep(1:4, each=12) > rep(1:4, rep(12,4)) > rep(rep(1:3, each=4),4) > rep(1:4, 12)
Vetores lógicos e seleção de elementos Como dito anteriormente os colchetes [] são usados para selecionar elementos de um vetor. No exemplo abaixo vemos como selecionar os 3 primeiros elementos do vetor x9 criado anteriormente e depois os elementos em posição par no vetor (segundo, quarto, sexto, oitavo e décimo). No terceiro comando são extraídos elementos de posições arbitrárias.
> x9[1:3]
[1] 71 71 67
> x9[2*(1:5)]
[1] 71 66 87 87 73
> x9[c(2,4,7)]
[1] 71 66 66
Entretanto, a seleção de elementos é mais geral podendo atender a critérios definidos pelo usuário. A seguir mostramos que podemos criar um vetor lógico ind.72 que indica se cada valor de x9 é ou não maior que 72. O vetor pode ser ainda convertido para o formato de uma variável indicadora (dummy).
> ind.72 <- x9 > 72 > ind.72
[1] FALSE FALSE FALSE FALSE TRUE TRUE FALSE TRUE FALSE TRUE
> as.numeric(ind.72)
[1] 0 0 0 0 1 1 0 1 0 1
> x10 <- x9[ind.72] > x10
[1] 76 87 87 73
Vetores de caracteres Vetores de caracteres também são criados por c() com elementos entre aspas. Há também algumas funções para criação automática.
> nomes <- c("fulano","beltrano","cicrano") > nomes
[1] "fulano" "beltrano" "cicrano"
> let5 <- letters[1:5] > let5
[1] "a" "b" "c" "d" "e"
> let10 <- LETTERS[11:20] > let10
[1] "K" "L" "M" "N" "O" "P" "Q" "R" "S" "T"
Uma função particularmente útil para criar vetores de caracteres são paste() e paste0(). Examine os seguintes comandos.
> paste(nomes, 1:3)
[1] "fulano 1" "beltrano 2" "cicrano 3"
> paste("fulano", 2)
[1] "fulano 2"
> paste("fulano", 2, sep="-")
[1] "fulano-2"
> paste("fulano", 2, sep="")
[1] "fulano2"
> paste0("fulano", 2)
[1] "fulano2"
> paste(letters[1:8], 2, sep="")
[1] "a2" "b2" "c2" "d2" "e2" "f2" "g2" "h2"
Portanto paste0() é um caso especial de paste() quando não se deseja caracter separador. Vejamos ainda mais um exemplo. Considere criar um vetor com elementos:
T1 T1 T1 T1 T2 T2 T2 T2 T3 T3 T3
> rep(paste("T", 1:3, sep=""), c(4,4,3))
[1] "T1" "T1" "T1" "T1" "T2" "T2" "T2" "T2" "T3" "T3" "T3"
Fatores Comentamos anteriormente que os vetores podem ser numéricos ou de caracteres. Entretanto há mais um tipo importante de objeto: os fatores. Por exemplo, ao criar um vetor de indicadores de tratamentos em uma análise de experimentos devemos declarar este vetor como um fator. Portanto revisitando o exemplo visto anteriormente temos que uma forma mais adequada de usar o vetor como variável indicadora de tratamentos é defini-lo como um fator. Note que neste caso, diferentemente do anterior, são registrados os “níveis” (levels) do fator.
> factor(rep(paste("T", 1:3, sep=""), c(4,4,3)))
[1] T1 T1 T1 T1 T2 T2 T2 T2 T3 T3 T3 Levels: T1 T2 T3
É importante notar a diferença entre um vetor de caracteres e um vetor que seja um fator que são objetos de classes diferentes. O primeiro simplesmente guarda os seus elementos enquanto o segundo possui atributos que nesta caso incluem os níveis do fator. Nos comandos abaixo esta distinção fica mais clara onde um vetor é criado inicialmente como caracteres e depois convertido para fator.
> estados <- c("PR", "SC", "RS") > estados
[1] "PR" "SC" "RS"
> class(estados)
[1] "character"
> attributes(estados)
NULL
> estados <- as.factor(estados) > estados
[1] PR SC RS Levels: PR RS SC
> class(estados)
[1] "factor"
> attributes(estados)
$levels [1] "PR" "RS" "SC" $class [1] "factor"
Fatores podem ser convertidos e interpretados como números. A associação é feita por ordem alfabética por default. Examine o exemplos a seguir
> estados <- c("PR","SC","RS") > as.numeric(estados)
Warning: NAs introduzidos por coerção
[1] NA NA NA
> estados <- factor(c("PR","SC","RS")) > as.numeric(estados)
[1] 1 3 2
Um fato relevante a respeito da manipulação de um fator é que uma seleção de parte dele que
exclua um certo valor não exclui este valor dos atributos do vetor como no caso abaixo, a menos que a
opção drop seja usada.
> estados.sel <- estados[-3] > estados.sel
[1] PR SC Levels: PR RS SC
> estados.seldrop <- estados[-3, drop=TRUE] > estados.seldrop
[1] PR SC Levels: PR SC
Da mesma forma pode-se criar um vetor e definir para ele níveis, mesmo que estes níveis não
estejam entre os elementos atualmente existentes no vetor. Note no exemplo abaixo o que acontece
com o valor "MG" em cada caso.
> est <- c("SC","PR","SC","PR","RS","SP","RS","SP","ES","PR","RJ","ES") > est
[1] "SC" "PR" "SC" "PR" "RS" "SP" "RS" "SP" "ES" "PR" "RJ" "ES"
> table(est)
est ES PR RJ RS SC SP 2 3 1 2 2 2
> sesul <- factor(est, levels = c("PR","SC","RS","MG","SP","RJ","ES")) > sesul
[1] SC PR SC PR RS SP RS SP ES PR RJ ES Levels: PR SC RS MG SP RJ ES
> table(sesul)
sesul PR SC RS MG SP RJ ES 3 2 2 0 2 1 2
Reagrupando níveis de fatores Pode-se reagrupar níveis de um fator usando-se levels. No exemplo a seguir começamos definindo um novo fator como cópia do original, listando os níveis originais dos fatores e depois o modificando de forma a agrupar os estados por regiões respeitando a ordem dos níveis originais.
> regiao <- sesul > levels(regiao)
[1] "PR" "SC" "RS" "MG" "SP" "RJ" "ES"
> levels(regiao) <- c("Sul","Sul","Sul","Sudeste","Sudeste","Sudeste","Sudeste") > regiao
[1] Sul Sul Sul Sul Sul Sudeste Sul Sudeste Sudeste [10] Sul Sudeste Sudeste Levels: Sul Sudeste
> table(regiao)
regiao Sul Sudeste 7 5
Fatores Ordenados
Um tipo especial de fator é dado pelos fatores ordenados que são fatores para os quais preserva-se
a ordenação natural dos níveis. No próximo exemplo vemos um vetor inicialmente definido como de
caracteres e a diferença entre defini-lo como não-ordenado ou ordenado. A ordenação segue a ordem
alfabética a menos que uma ordenação diferente seja definida pelo usuário no argumento
levels. Note ainda que pode-se usar duas funções diferentes para definir fatores ordenados:
factor(..., ord=T) ou ordered().
> grau <- c("medio","baixo","medio","alto","baixo","baixo","alto","medio","alto","medio" ) > factor(grau)
[1] medio baixo medio alto baixo baixo alto medio alto medio Levels: alto baixo medio
> factor(grau, ord=T)
[1] medio baixo medio alto baixo baixo alto medio alto medio Levels: alto < baixo < medio
> ordered(grau)
[1] medio baixo medio alto baixo baixo alto medio alto medio Levels: alto < baixo < medio
> factor(grau, ord=T, levels = c("baixo", "medio", "alto"))
[1] medio baixo medio alto baixo baixo alto medio alto medio Levels: baixo < medio < alto
> ordered(grau, levels = c("baixo", "medio", "alto"))
[1] medio baixo medio alto baixo baixo alto medio alto medio Levels: baixo < medio < alto
Mais algumas operações com vetores Considere o vetor vec obtido como se segue. As funções abaixo mostram como inverter a ordem dos elementos do vetor (rev()), ordenar os elementos (sort()) e a posição de cada elemento no vetor ordenado e encontrar o rank dos elementos (rank()). As operações %% e %% fornecem, respectivamente, o resto e a parte inteira de uma divisão.
> vec <- round(rnorm(7, m=70, sd=10)) > vec
[1] 68 78 62 61 65 64 72
> rev(vec)
[1] 72 64 65 61 62 78 68
> sort(vec)
[1] 61 62 64 65 68 72 78
> order(vec)
[1] 4 3 6 5 1 7 2
> vec[order(vec)]
[1] 61 62 64 65 68 72 78
> rank(vec)
[1] 5 7 2 1 4 3 6
> vec %% 5
[1] 3 3 2 1 0 4 2
> vec %/% 5
[1] 13 15 12 12 13 12 14
A função which() e suas variantes retorna a posição do(s) elemento(s) que obedece a certo critério.
> which(vec > 70)
[1] 2 7
> which.max(vec)
[1] 2
> which.min(vec)
[1] 4
Outra operação é a remoção de elementos de vetores através de índices negativos.
> vec
[1] 68 78 62 61 65 64 72
> vec[-5] ## exclui o 5o elemento
[1] 68 78 62 61 64 72
> vec[-(2:4)] ## exclui o 2 e o 4o elemento
[1] 68 65 64 72
Matrizes são montadas a partir da reorganização de elementos de um vetor em linhas e colunas. Por default a matriz é preenchida por colunas e o argumento opcional byrow=T inverte este padrão. A seleção de elementos ou submatrizes é feita usando [,] sendo que antes da vírgula indica-se a(s) linha(s) e depois a(s) coluna(s) a serem selecionadas. Opcionalmente matrizes podem ter nomes associados às linhas e colunas (rownames e colnames). Cada um destes componentes da matriz é um vetor de nomes. Os comandos a seguir ilustram todas estas funcionalidades.
> m1 <- matrix(1:12, ncol=3) > m1
[,1] [,2] [,3] [1,] 1 5 9 [2,] 2 6 10 [3,] 3 7 11 [4,] 4 8 12
> matrix(1:12, ncol=3, byrow=T)
[,1] [,2] [,3] [1,] 1 2 3 [2,] 4 5 6 [3,] 7 8 9 [4,] 10 11 12
> length(m1)
[1] 12
> dim(m1)
[1] 4 3
> nrow(m1)
[1] 4
> ncol(m1)
[1] 3
> m1[1,2]
[1] 5
> m1[2,2]
[1] 6
> m1[,2]
[1] 5 6 7 8
> m1[3,]
[1] 3 7 11
> m1[1:2, 2:3]
[,1] [,2] [1,] 5 9 [2,] 6 10
> dimnames(m1)
NULL
> dimnames(m1) <- list(c("L1", "L2", "L3","L4"), c("C1","C2","C3")) > dimnames(m1)
[[1]] [1] "L1" "L2" "L3" "L4" [[2]] [1] "C1" "C2" "C3"
> m1[c("L1","L3"),]
C1 C2 C3 L1 1 5 9 L3 3 7 11
> m1[c(1,3),]
C1 C2 C3 L1 1 5 9 L3 3 7 11
> m2 <- cbind(1:5, 6:10) > m2
[,1] [,2] [1,] 1 6 [2,] 2 7 [3,] 3 8 [4,] 4 9 [5,] 5 10
> m3 <- cbind(1:5, 6) > m3
[,1] [,2] [1,] 1 6 [2,] 2 6 [3,] 3 6 [4,] 4 6 [5,] 5 6
Matrizes são muitas vezes utilizadas para armazenar frequências de cruzamentos entre variáveis. Desta forma é comum surgir a necessidade de obter os totais marginais, isto é a soma dos elementos das linhas e/ou colunas das matrizes, o que pode ser diretamente obtido com margin.table(). No caso de matrizes estas operação produz o mesmo resultado que outras funções conforme mostramos a seguir.
> margin.table(m1, margin=1)
L1 L2 L3 L4 15 18 21 24
> apply(m1,1,sum)
L1 L2 L3 L4 15 18 21 24
> rowSums(m1)
L1 L2 L3 L4 15 18 21 24
> margin.table(m1, margin=2)
C1 C2 C3 10 26 42
> apply(m1,2,sum)
C1 C2 C3 10 26 42
> colSums(m1)
C1 C2 C3 10 26 42
Estes valores podem ainda ser representados por proporções, com opções para total por linha, por coluna ou geral da matriz, usando a função prop.table().
> prop.table(m1, margin = 1)
C1 C2 C3 L1 0.06666667 0.3333333 0.6000000 L2 0.11111111 0.3333333 0.5555556 L3 0.14285714 0.3333333 0.5238095 L4 0.16666667 0.3333333 0.5000000
> prop.table(m1, margin = 2)
C1 C2 C3 L1 0.1 0.1923077 0.2142857 L2 0.2 0.2307692 0.2380952 L3 0.3 0.2692308 0.2619048 L4 0.4 0.3076923 0.2857143
> prop.table(m1)
C1 C2 C3 L1 0.01282051 0.06410256 0.1153846 L2 0.02564103 0.07692308 0.1282051 L3 0.03846154 0.08974359 0.1410256 L4 0.05128205 0.10256410 0.1538462
Operações com matrizes Operações com matrizes são feitas diretamente assim como no caso de vetores. A lei da reciclagem permanece válida. Existem diversas operações sobre matrizes e vamos apresentar apenas algumas aqui. Note que as operações abaixo são todas realizadas elemento a elemento.
> m4 <- matrix(1:6, nc=3) > m5 <- matrix(10*(1:6), nc=3) > m4
[,1] [,2] [,3] [1,] 1 3 5 [2,] 2 4 6
> m5
[,1] [,2] [,3] [1,] 10 30 50 [2,] 20 40 60
> m4+m5
[,1] [,2] [,3] [1,] 11 33 55 [2,] 22 44 66
> m4*m5
[,1] [,2] [,3] [1,] 10 90 250 [2,] 40 160 360
> m5-m4
[,1] [,2] [,3] [1,] 9 27 45 [2,] 18 36 54
> m5/m4
[,1] [,2] [,3] [1,] 10 10 10 [2,] 10 10 10
A multiplicação de matrizes é feita usando o operador %*%. A função t() faz transposição e a inversão é obtida com solve(). O pacote MASS fornece ginv() para obtenção de inversa generalizada (inversa de Moore-Penrose).
> t(m4) %*% m5
[,1] [,2] [,3] [1,] 50 110 170 [2,] 110 250 390 [3,] 170 390 610
A função solve() na verdade é mais geral e fornece a solução de um sistema de equações lineares. Por exemplo, a solução do sistema:
pode ser obtida com:
> mat <- matrix(c(1,5,2,3,-2,1,-1,1,-1), nc=3) > vec <- c(10,15,7) > solve(mat,vec)
[1] 3.615385 3.307692 3.538462
Uma outra função muito útil para cálculos matriciais é crossprod() para produtos cruzados: crossprod(X) retorna \(X^\prime X\) enquanto crossprod(X,Y) retorna \(X^\prime Y\). Deve ser dada preferência a esta função sempre que possível pois é mais precisa e rápida do que o correspondente produto matricial com transposição do objeto do primeiro argumento.
Como exemplo vamos considerar as variáveis preditora e resposta com valores fornecidos na Tabela 1 e considere obter os coeficientes da regressão linear dados por:
onde \(X\) é a matriz com os valores da variável \(X\) acrescida de uma coluna de 1’s e \(y\) são os valores da variável resposta.
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
| 13.4 | 16.6 | 15.8 | 17.3 | 18.5 | 22.1 | 23.2 | 35.9 | 31.3 | 39.4 |
Nos comandos abaixo mostramos como entrar com os dados e como obter os resultados de duas formas: (i) usando operações de matrizes de forma "ineficiente" e (ii) usando uma forma computacionalmente mais adequada de obter o mesmo resultado.
> X <- cbind(1, 1:10) > y <- c(13.4, 16.6, 15.8, 17.3, 18.5, 22.1, 23.2, 35.9, 31.3, 39.4) > solve(t(X) %*% X) %*% t(X) %*% y
[,1] [1,] 8.06 [2,] 2.78
> solve(crossprod(X), crossprod(X,y))
[,1] [1,] 8.06 [2,] 2.78
> drop(solve(crossprod(X), crossprod(X,y)))
[1] 8.06 2.78
Notas:
existem formas ainda mais computacionalmente eficientes de obter o resultado acima no R, como por exemplo usando decomposições como a de Cholesky (chol()) e QR (qr()), mas o uso dessas não será discutido neste ponto.
na prática para ajustar regressões no R o usuário não precisa fazer operações como a indicada pois já existem funções no R (neste caso lm()) que efetuam o ajuste.
As operações retornam uma matriz de dimensão \(2\times 1\). A função drop reduz a dimensão do objeto (se possível) para um vetor de comprimento 2.
O conceito de array generaliza a ideia de matriz. Enquanto em uma matriz os elementos são organizados em duas dimensões (linhas e colunas), em um array os elementos podem ser organizados em um número arbitrário de dimensões.
No R um array é definido utilizando a função array(). Defina um array com o comando a seguir e inspecione o objeto certificando-se que você entendeu como arrays são criados.
> ar1 <- array(1:24, dim=c(3,4,2)) > ar1
, , 1 [,1] [,2] [,3] [,4] [1,] 1 4 7 10 [2,] 2 5 8 11 [3,] 3 6 9 12 , , 2 [,1] [,2] [,3] [,4] [1,] 13 16 19 22 [2,] 14 17 20 23 [3,] 15 18 21 24
Examine agora os resultados dos seguintes comandos para selecionar e operar elementos do array.
> ar1[,2:3,]
, , 1 [,1] [,2] [1,] 4 7 [2,] 5 8 [3,] 6 9 , , 2 [,1] [,2] [1,] 16 19 [2,] 17 20 [3,] 18 21
> ar1[2,,1]
[1] 2 5 8 11
> sum(ar1[,,1])
[1] 78
> sum(ar1[1:2,,1])
[1] 48
Podemos atribuir nomes às dimensões de um array.
> dimnames(ar1)
NULL
> dimnames(ar1) <- list(c("Baixo","Médio","Alto"), + paste("col", 1:4, sep=""), + c("Masculino","Feminino"))
Inspecione o “help” da função array (digite help(array)), rode e inspecione os exemplos contidos na documentação.
Veja agora um exemplo de dados já incluído no R no formato de array. Para “carregar” e visualizar os dados digite:
> data(Titanic) > Titanic
, , Age = Child, Survived = No Sex Class Male Female 1st 0 0 2nd 0 0 3rd 35 17 Crew 0 0 , , Age = Adult, Survived = No Sex Class Male Female 1st 118 4 2nd 154 13 3rd 387 89 Crew 670 3 , , Age = Child, Survived = Yes Sex Class Male Female 1st 5 1 2nd 11 13 3rd 13 14 Crew 0 0 , , Age = Adult, Survived = Yes Sex Class Male Female 1st 57 140 2nd 14 80 3rd 75 76 Crew 192 20
Para obter maiores informações sobre estes dados digite:
help(Titanic)
Agora vamos responder às seguintes perguntas, mostrando os comandos do R utilizados sobre o array de dados.
quantas pessoas havia no total?
> sum(Titanic)
[1] 2201
quantas pessoas havia na tripulação (crew)?
> sum(Titanic[4,,,])
[1] 885
quantas pessoas sobreviveram e quantas morreram?
> apply(Titanic, 4, sum)
No Yes 1490 711
quantas crianças sobreviveram?
> sum(Titanic[,,1,2])
[1] 57
quais as proporções de sobreviventes entre homens e mulheres?
Vamos fazer por partes obtendo primeiro o número de homens e mulheres, depois dentre estes os
que sobreviveram e depois obter as percentagens pedidas.
> apply(Titanic, 2, sum)
Male Female 1731 470
> apply(Titanic[,,,2],2,sum)
Male Female 367 344
> 100*apply(Titanic[,,,2],2,sum)/apply(Titanic, 2, sum)
Male Female 21.20162 73.19149
Note-se ainda que assim como em matrizes, margin.table() poderia ser utilizada para obter os totais marginais para cada dimensão do array de dados, fornecendo uma maneira alternativa à alguns dos comandos mostrados acima.
> margin.table(Titanic, margin=1)
Class 1st 2nd 3rd Crew 325 285 706 885
> margin.table(Titanic, margin=2)
Sex Male Female 1731 470
> margin.table(Titanic, margin=3)
Age Child Adult 109 2092
> margin.table(Titanic, margin=4)
Survived No Yes 1490 711
Esta função admite ainda índices múltiplos que permitem outros resumos da tabela de dados. Por exemplo mostramos a seguir como obter o total de sobreviventes e não sobreviventes, separados por sexo e depois as porcentagens de sobreviventes para cada sexo.
> margin.table(Titanic, margin=c(2,4))
Survived Sex No Yes Male 1364 367 Female 126 344
> prop.table(margin.table(Titanic, margin=c(2,4)), margin=1)
Survived Sex No Yes Male 0.7879838 0.2120162 Female 0.2680851 0.7319149
Vetores, matrizes e arrays forçam todos os elementos a serem do mesmo "tipo" i.e., ou numérico ou caracter. O data-frame é uma estrutura semelhante à uma matriz porém com cada coluna sendo tratada separadamente. Desta forma podemos ter colunas de valores numéricos e colunas de caracteres no mesmo objeto. Note entretanto que dentro de uma mesma coluna todos elementos ainda serão forçados a serem do mesmo tipo.
A seguir criamos um data-frame, vemos os nomes de suas colunas e extraímos cada coluna.
> d1 <- data.frame(X = 1:10, Y = c(51, 54, 61, 67, 68, 75, 77, 75, 80, 82)) > d1
X Y 1 1 51 2 2 54 3 3 61 4 4 67 5 5 68 6 6 75 7 7 77 8 8 75 9 9 80 10 10 82
> names(d1)
[1] "X" "Y"
> d1$X
[1] 1 2 3 4 5 6 7 8 9 10
> d1$Y
[1] 51 54 61 67 68 75 77 75 80 82
Para fazer um gráfico com os dados pode-se fazer
> plot(d1)
Se houverem mais de duas colunas o comando plot() irá produzir diagramas de dispersão duas a duas. Para especificar as colunas pode-se usar um dos comandos a seguir que produzem o mesmo gráfico visto anteriormente.
> plot(d1$X, d1$Y) > plot(X ~ Y, data = d1) > plot(Y ~ X, data = d1) > with(d1, plot(X, Y))
Vejamos a seguir uma estrutura de dados com grupos.
> d2 <- data.frame(Y= c(10+rnorm(5, sd=2), 16+rnorm(5, sd=2), 14+rnorm(5, sd=2))) > d2$lev <- gl(3,5) > d2
Y lev 1 9.747865 1 2 11.329726 1 3 8.700255 1 4 8.348289 1 5 11.437184 1 6 16.776116 2 7 16.844483 2 8 16.648475 2 9 18.716013 2 10 15.377763 2 11 16.296121 3 12 15.376397 3 13 12.337456 3 14 10.785550 3 15 14.901564 3
A função gl() é um atalho para o uso de seq() e rep() vistos anteriormente e que já retorna um fator. Tipicamente é usada para criar fatores indicadores da estrutura de experimentos.
O seguinte comando produz um resumo dos dados de cada grupo.
> with(d2, by(Y, lev, summary))
lev: 1 Min. 1st Qu. Median Mean 3rd Qu. Max. 8.348 8.700 9.748 9.913 11.330 11.437 ------------------------------------------------------------ lev: 2 Min. 1st Qu. Median Mean 3rd Qu. Max. 15.38 16.65 16.78 16.87 16.84 18.72 ------------------------------------------------------------ lev: 3 Min. 1st Qu. Median Mean 3rd Qu. Max. 10.79 12.34 14.90 13.94 15.38 16.30
Há funções que facilitam a criação de variáveis. Na criação de data-frame, expand.grid() pode ser muito útil gerando automaticamente combinações de valores.
> d3 <- expand.grid(1:3, 4:5) > d3
Var1 Var2 1 1 4 2 2 4 3 3 4 4 1 5 5 2 5 6 3 5
Outro exemplo:
> expand.grid(1:3, 1:2)
Var1 Var2 1 1 1 2 2 1 3 3 1 4 1 2 5 2 2 6 3 2
Listas são estruturas genéricas e flexíveis que permitem armazenar diversos formatos em um único objeto. A lista a seguir contém um vetor, um caractere e uma matriz.
> lis1 <- list(A=1:10, B="THIS IS A MESSAGE", C=matrix(1:9, ncol=3)) > lis1
$A [1] 1 2 3 4 5 6 7 8 9 10 $B [1] "THIS IS A MESSAGE" $C [,1] [,2] [,3] [1,] 1 4 7 [2,] 2 5 8 [3,] 3 6 9
Muitas funções retornam uma lista. A função lm() ajusta um modelo linear. No exemplo a seguir é feito um ajuste de uma regressão linear simples.
> lis2 <- lm(Y ~ X, data=d1) > lis2
Call: lm(formula = Y ~ X, data = d1) Coefficients: (Intercept) X 50.067 3.442
> is.list(lis2)
[1] TRUE
> class(lis2)
[1] "lm"
> summary(lis2)
Call: lm(formula = Y ~ X, data = d1) Residuals: Min 1Q Median 3Q Max -2.9515 -2.5045 -0.2212 2.3076 4.2788 Coefficients: Estimate Std. Error t value Pr(>|t|) (Intercept) 50.0667 1.9674 25.45 6.09e-09 *** X 3.4424 0.3171 10.86 4.58e-06 *** --- Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1 Residual standard error: 2.88 on 8 degrees of freedom Multiple R-squared: 0.9364, Adjusted R-squared: 0.9285 F-statistic: 117.9 on 1 and 8 DF, p-value: 4.579e-06
> anova(lis2)
Analysis of Variance Table Response: Y Df Sum Sq Mean Sq F value Pr(>F) X 1 977.65 977.65 117.88 4.579e-06 *** Residuals 8 66.35 8.29 --- Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
> names(lis2)
[1] "coefficients" "residuals" "effects" "rank" [5] "fitted.values" "assign" "qr" "df.residual" [9] "xlevels" "call" "terms" "model"
> lis2$fitted
1 2 3 4 5 6 7 8 53.50909 56.95152 60.39394 63.83636 67.27879 70.72121 74.16364 77.60606 9 10 81.04848 84.49091
> lis2$res
1 2 3 4 5 6 7 -2.5090909 -2.9515152 0.6060606 3.1636364 0.7212121 4.2787879 2.8363636 8 9 10 -2.6060606 -1.0484848 -2.4909091
No próximo exemplo a função aov() faz o ajuste de um modelo de análise de variância e também retorna uma lista.
> lis3 <- aov(Y ~ lev, data=d2) > lis3
Call: aov(formula = Y ~ lev, data = d2) Terms: lev Residuals Sum of Squares 122.09738 35.02747 Deg. of Freedom 2 12 Residual standard error: 1.708495 Estimated effects may be unbalanced
> summary(lis3)
Df Sum Sq Mean Sq F value Pr(>F) lev 2 122.10 61.05 20.91 0.000123 *** Residuals 12 35.03 2.92 --- Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Uma lista é portanto uma coleção de objetos. Para listas há duas opções para se selecionar elementos: colchetes [ ] ou colchetes duplos [[ ]]. Entretanto os resultados retornados por cada um destes é diferente. O colchete simples ([ ]) retorna uma parte da lista, ou seja, retorna um objeto que ainda é uma lista. Já o colchete duplo ([[ ]]) retorna o objeto que está na posição indicada da lista. Examine o exemplo a seguir.
> lis1 <- list(nomes=c("Pedro","Joao","Maria"), mat=matrix(1:6, nc=2)) > lis1
$nomes [1] "Pedro" "Joao" "Maria" $mat [,1] [,2] [1,] 1 4 [2,] 2 5 [3,] 3 6
> lis1[1]
$nomes [1] "Pedro" "Joao" "Maria"
> lis1[2]
$mat [,1] [,2] [1,] 1 4 [2,] 2 5 [3,] 3 6
> lis1[[2]]
[,1] [,2] [1,] 1 4 [2,] 2 5 [3,] 3 6
O conteúdo das funções podem ser vistos digitando o nome da função (sem os parênteses).
lm glm plot plot.default
Entretanto isto não é disponível desta forma para todas as funções como por exemplo em min,
max, rnorm e lines. Nestes casos as funções não são escritas em linguagem R (em geral estão escritas
em C) e para visualizar o conteúdo das funções você tem que examinar os arquivos do código fonte do
R.
As funções do tipo is.*() mencionadas no início desta seção podem ser usadas para obter informações sobre a natureza de um objeto, o que pode ser muito útil quando se escreve funções em R. Entretanto, são pouco práticas para determinar qual o tipo de um objeto e retornam apenas um valor lógico TRUE ou FALSE.
Uma função mais rica em detalhes é str() retorna informações sobre a estrutura do objeto. Nos exemplos a seguir vemos que a função informa sobre objetos que criamos anteriormente: x1 é um vetor numérico, estados é um fator com três níveis, ar1 é um array, d1 é um data.frame com duas variáveis sendo uma delas de valores inteiros e a outra de valores numéricos e lis1 é uma lista de dois elementos sendo o primeiro um vetor de caracteres e o segundo uma matriz de seis elementos e de dimensão \(3\times 2\).
> str(x1)
num 10
> str(estados)
Factor w/ 3 levels "PR","RS","SC": 1 3 2
> str(ar1)
int [1:3, 1:4, 1:2] 1 2 3 4 5 6 7 8 9 10 ... - attr(*, "dimnames")=List of 3 ..$ : chr [1:3] "Baixo" "Médio" "Alto" ..$ : chr [1:4] "col1" "col2" "col3" "col4" ..$ : chr [1:2] "Masculino" "Feminino"
> str(d1)
'data.frame': 10 obs. of 2 variables: $ X: int 1 2 3 4 5 6 7 8 9 10 $ Y: num 51 54 61 67 68 75 77 75 80 82
> str(lis1)
List of 2 $ nomes: chr [1:3] "Pedro" "Joao" "Maria" $ mat : int [1:3, 1:2] 1 2 3 4 5 6
Mostrar comandos que podem ser usados para criar os objetos e/ou executar as instruções a seguir.
o vetor
[1] 4 8 2
selecionar o primeiro e terceiro elemento do vetor acima
[1] 10 11 12 13 14 15 16 17 18 19 20
o vetor com a sequência de valores
[1] -3 -2 -1 0 1 2 3
o vetor com a sequência de valores
[1] 2.4 3.4 4.4 5.4 6.4 7.4 8.4 9.4 10.4
o vetor
[1] 1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39
o vetor
[1] 1 3 5 7 9 11 14 17 20
o vetor de sequência repetida
[1] 1 1 1 2 2 2 3 3 3 4 4 4
o vetor de sequência repetida
[1] 4 4 4 3 3 3 2 2 2 1 1 1
o vetor de elementos repetidos
[1] 1 2 3 1 2 3 1 2 3 1 2 3
a sequência de valores
[1] 1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41 43 45 47 49 [26] 51 53 55 57 59 61 63 65 67 69 71 73 75 77 79 81 83 85 87 89 91 93 95 97 99
o vetor
[1] 11 10 9 8 7 6 5 4 3 2 1
o vetor alfanumérico
[1] "Parana" "Sao Paulo" "Minas Gerais"
o vetor indicador de tratamentos
[1] Trat_1 Trat_1 Trat_1 Trat_2 Trat_2 Trat_2 Trat_3 Trat_3 Trat_3 Trat_4 [11] Trat_4 Trat_4 Levels: Trat_1 Trat_2 Trat_3 Trat_4
um vetor indicador de blocos
[1] Bloco_1 Bloco_2 Bloco_3 Bloco_1 Bloco_2 Bloco_3 Bloco_1 Bloco_2 Bloco_3 [10] Bloco_1 Bloco_2 Bloco_3 Levels: Bloco_1 Bloco_2 Bloco_3
Mostre comando(s) para construir uma matriz \(10 \times 10\) tal que as entradas são iguais a \(i*j\), sendo \(i\) a linha e \(j\) a coluna.
Construa um data-frame com uma tabela com três colunas: \(x\), \(x^2\) e \(\exp (x)\), com \(x\) variando de 0 a 50.
A função sum(x) retorna a soma dos elementos do vetor \(x\). A expressão z<-rep(x,10) faz o vetor \(z\) igual a uma sequência de 10 vetores \(x\). Use estas e outras funções para calcular a soma dos 100 primeiros termos das séries:
Carregue o conjunto de dados com o comando
data(HairEyeColor)
e responda as seguintes perguntas fornecendo também o comando do R para obter a resposta:
Qual a proporção de homens e mulheres na amostra?
Quantos são os homens de cabelos pretos?
Quantas mulheres tem cabelos loiros?
Qual a proporção de homens e mulheres entre as pessoas ruivas?
Quantas pessoas tem olhos verdes?
Considere a tabela de frequências a seguir. Entre com os dados usando o tipo de objeto adequado e mostre os comandos para responder as perguntas abaixo.
| Fumante | Não Fumante | ||||
| Idade | Masculino | Feminino | Masculino | Feminino | |
| Menor que 20 | 50 | 30 | 55 | 41 | |
| 20 a 40 | 39 | 28 | 31 | 30 | |
| Maior que 40 | 37 | 36 | 25 | 15 | |
qual o número total de pessoas?
quantos são os fumantes e os não fumantes?
quantos são homens?
quantas mulheres são não fumantes?
quais as proporções de fumantes entre homens e mulheres?