5 Tipos de objetos

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().

5.1 Vetores

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

5.2 Matrizes

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:

\begin {eqnarray*} \left \{ \begin {array}{ll} x + 3 y - z & = 10 \\ 5x - 2y + z & = 15 \\ 2x + y - z & = 7 \end {array} \right . \end {eqnarray*}

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:

\begin {equation} \hat {\beta } = ( X^\prime X )^{-1} X^\prime y \;\; , \end {equation}

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.

Tabela 1: Valores da variável preditora e resposta para uma regressão linear simples.

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:

1.

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.

2.

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.

3.

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.

5.3 Arrays

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.

1.

quantas pessoas havia no total?

> sum(Titanic)

[1] 2201
2.

quantas pessoas havia na tripulação (crew)?

> sum(Titanic[4,,,])

[1] 885
3.

quantas pessoas sobreviveram e quantas morreram?

> apply(Titanic, 4, sum)

  No  Yes 
1490  711
4.

quantas crianças sobreviveram?

> sum(Titanic[,,1,2])

[1] 57
5.

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

5.4 Data-frames

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)

PIC

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

5.5 Listas

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

5.6 Funções

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.

5.7 Que tipo de objeto eu tenho?

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

5.8 Exercícios

1.

Mostrar comandos que podem ser usados para criar os objetos e/ou executar as instruções a seguir.

(a)

o vetor

[1] 4 8 2
(b)

selecionar o primeiro e terceiro elemento do vetor acima

(c)

 [1] 10 11 12 13 14 15 16 17 18 19 20
(d)

o vetor com a sequência de valores

[1] -3 -2 -1  0  1  2  3
(e)

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
(f)

o vetor

 [1]  1  3  5  7  9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39
(g)

o vetor

[1]  1  3  5  7  9 11 14 17 20
(h)

o vetor de sequência repetida

 [1] 1 1 1 2 2 2 3 3 3 4 4 4
(i)

o vetor de sequência repetida

 [1] 4 4 4 3 3 3 2 2 2 1 1 1
(j)

o vetor de elementos repetidos

 [1] 1 2 3 1 2 3 1 2 3 1 2 3
(k)

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
(l)

o vetor

 [1] 11 10  9  8  7  6  5  4  3  2  1
(m)

o vetor alfanumérico

[1] "Parana"       "Sao Paulo"    "Minas Gerais"
(n)

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
(o)

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
2.

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.

3.

Construa um data-frame com uma tabela com três colunas: \(x\), \(x^2\) e \(\exp (x)\), com \(x\) variando de 0 a 50.

4.

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:

5.

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:

(a)

Qual a proporção de homens e mulheres na amostra?

(b)

Quantos são os homens de cabelos pretos?

(c)

Quantas mulheres tem cabelos loiros?

(d)

Qual a proporção de homens e mulheres entre as pessoas ruivas?

(e)

Quantas pessoas tem olhos verdes?

6.

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

(a)

qual o número total de pessoas?

(b)

quantos são os fumantes e os não fumantes?

(c)

quantos são homens?

(d)

quantas mulheres são não fumantes?

(e)

quais as proporções de fumantes entre homens e mulheres?