Objetos de classe matrix ou data.frame são objetos bidimensionais (tem linhas e colunas), e constituem a forma como nossos dados estão organizados.
Precisamos entender a diferença entre essas classes e suas propriedades.
Objetos de classe matrix contêm linhas e colunas, mas os valores de toda a matriz são da mesma classe (numeric, character, ou logical, por exemplo).
Operações matemáticas com matrizes utilizam matrizes numéricas, portanto, de uma única classe, matrix.
Objetos de classe data.frame tambêm contém linhas e colunas, mas podem misturar colunas de classes diferentes (numeric e character, factor, e logical, por exemplo).
Quando importamos dados ao R, geralmente atribuímos os dados a um objeto de classe data.frame.
Podemos converter um objeto de classe matrix para data.frame e vice-versa, usando as funções as.data.frame() ou as.matrix().
Porém, quando convertemos os dados para um objeto de classe matrix, todos os dados passam a ser da mesma classe, geralmente havendo perda de dados.
3.1.1 Criando matrizes
Poder criar uma matriz no R é muito útil para várias finalidades como, por exemplo, simular dados em testes de permutação ou preencher uma tabela com resultados de uma análise.
Matrizes podem ser criadas de diferentes formas (e.g., pode juntar matrizes pelas linhas e colunas, ou pode extrair sub-matrizes de uma matriz).
Para criar matrizes, a função básica se chama matrix():
# veja o help da função?matrix# a função se usa assim: matrix(data = NA, nrow = 1, ncol = 1, byrow = FALSE, dimnames = NULL)# onde:# data = NA #um vetor de comprimento igual ao número de células desejadas que é nrow*ncol.# byrow = FALSE #A forma de preenchimento da planilha pelos dados em data. Se byrow=TRUE, então ele preenche pelas linhas, senão pelas# colunas# nrow = número de linhas# ncol = número de colunas# dimnames = um objeto do tipo lista (que ainda não vimos), com dois vetores, um com os nomes das linhas, outro com os nomes das colunas.
# exemplo 1 - matriz de 3x3 com zerosmm <-matrix(data =0, nrow =3, ncol =3, byrow = F, dimnames =NULL)mm
0
0
0
0
0
0
0
0
0
# note que data tem comprimento 1, apenas 1 valor. Pela regra da reciclagem ele é repetido até completar o total necessário dado por nrow*ncol# exemplo2 - matriz de 3x3 com valoresdd <-1:9# nove valoresmm <-matrix(data = dd, nrow =3, ncol =3, byrow = F, dimnames =NULL)mm
1
4
7
2
5
8
3
6
9
# mudando byrow para TRUE preenchemos pelas linhasmm2 <-matrix(data = dd, nrow =3, ncol =3, byrow =TRUE, dimnames =NULL)mm2
1
2
3
4
5
6
7
8
9
# exemplo3 - matriz de 3x3 com valores e nomes de colunas e linhas# define dimensaonrow <-3ncol <-3# define datadd <-1:9# nove valores# define nome de colunascln <-paste("coluna", 1:ncol, sep ="")# define nome de linhaslln <-paste("linha", 1:nrow, sep ="")mm <-matrix(data = dd, nrow = nrow, ncol = ncol, byrow = F, dimnames =list(lln, cln))mm
coluna1
coluna2
coluna3
linha1
1
4
7
linha2
2
5
8
linha3
3
6
9
Para unir ou criar matrizes (e data.frames) temos duas funções úteis:
rbind(), que vem do inglês row bind, ou seja, cole linhas;
cbind(), que vem do inglês column bind, ou seja, cole colunas.
# vetores numéricos de mesmo comprimentov1 <-1:10v2 <-10:1v3 <-11:20# essas duas condições devem ser verdadeiraslength(v1) ==length(v2)
## [1] TRUE
length(v1) ==length(v3)
## [1] TRUE
# entao posso criar uma matriz juntando esses vetores em linhas ou colunasmml <-rbind(v1, v2, v3)class(mml) # criou um matrix
## [1] "matrix" "array"
mml
v1
1
2
3
4
5
6
7
8
9
10
v2
10
9
8
7
6
5
4
3
2
1
v3
11
12
13
14
15
16
17
18
19
20
# oummc <-cbind(v1, v2, v3)class(mmc)
## [1] "matrix" "array"
# ou se eu já tenho uma matriz, posso usar essas funções para adicionar novas linhas ou colunasnovovetor <-31:40# por linhancol(mml) ==length(novovetor) # neste caso o número de colunas da matrix precisa ser igual ao número de elementos no vetor
## [1] TRUE
mml <-rbind(mml, novovetor) # junto a matrix existente com o novo vetor, adicionando uma nova linhamml
v1
1
2
3
4
5
6
7
8
9
10
v2
10
9
8
7
6
5
4
3
2
1
v3
11
12
13
14
15
16
17
18
19
20
novovetor
31
32
33
34
35
36
37
38
39
40
# note que a nova linha recebeu como nome o nome do objeto que continha o dado# por colunanrow(mmc) ==length(novovetor) # neste caso o número de linhas da matrix precisa ser igual ao número de elementos no vetor
## [1] TRUE
mmc <-cbind(mmc, novovetor) # junto a matrix existente com o novo vetor, adicionando uma nova colunammc
v1
v2
v3
novovetor
1
10
11
31
2
9
12
32
3
8
13
33
4
7
14
34
5
6
15
35
6
5
16
36
7
4
17
37
8
3
18
38
9
2
19
39
10
1
20
40
# note que a nova coluna recebeu como nome o nome do objeto que continha o dado
3.1.2 Criando data.frames
Objetos de classe data.frame são tabelas de dados, apresentam duas dimensões, e permitem misturar dados de classes diferentes, numéricos, texto (character ou factor) e lógicos.
Quando importamos nossos dados ao R, em geral criamos objetos de classe data.frame.
Para criar ou converter dados em data.frames, podemos usar as funções data.frame() e as.data.frame().
?data.frame # veja o help das funções acima
# a funcao que cria o objeto édata.frame(..., row.names =NULL, check.rows =FALSE, check.names =TRUE, stringsAsFactors =default.stringsAsFactors())# de todos os argumentos os mais importantes são:# ... #que pode ser vetores ou tag = vetor (os dados da tabela)# stringsAsFactors #que especifica se queremos os textos como vetores ou fatores
# exemplo 1 -# Primeiro criamos alguns dados# um vetor numericov1 <-1:10# um vetor de letras do mesmo comprimento usando a constante LETTERSv2 <- LETTERS[1:10]# um vetor de palavras de mesmo comprimentov3 <-rep(c("fulano", "jose", "joaquim", "martin"), length.out =length(v1))# Juntamos num data.frame com fatoresdd <-data.frame(v1, v2, v3, stringsAsFactors = T)class(dd) # é um data frame
## [1] "data.frame"
dim(dd) # dimensoes, linhas e colunas
## [1] 10 3
ncol(dd) # numero de colunas
## [1] 3
nrow(dd) # numero de linhas
## [1] 10
str(dd) # estrutura do objeto (veja as classes das colunas)
# juntamos com nome de colunas (tag = vetor)dd2 <-data.frame(RegistorID = v1, CodigoZ = v2, Pessoa = v3, stringsAsFactors =FALSE)dd2
RegistorID
CodigoZ
Pessoa
1
A
fulano
2
B
jose
3
C
joaquim
4
D
martin
5
E
fulano
6
F
jose
7
G
joaquim
8
H
martin
9
I
fulano
10
J
jose
# agora vamos usar o cbind que vimos acimadz <-cbind(v1, v2, v3)# ou entao usando tag=vetor para ter nomes das colunas de acordodz <-cbind(RegistorID = v1, CodigoZ = v2, Pessoa = v3)class(dz) # isso cria uma matriz
## [1] "matrix" "array"
str(dz) # todos os dados são da mesma classe (texto)
dz <-as.data.frame(as.matrix(dz), stringsAsFactors =FALSE) # convertemos num data.frame sem fatoresstr(dz) # converte numeros para numerico e texto para character
3.1.3 Funções importantes na manipulação de matrizes e data.frames
As funções head() e tail() mostram o cabeçalho e rodapé tanto para matrizes como para data.frames, respectivamente.
Vejam o ? dessas duas funções:
?head?tail
# Primeiro criamos alguns dados# um vetor numericov1 <-1:10# um vetor de letras do mesmo comprimento usando a constante LETTERSv2 <- LETTERS[1:10]# um vetor de palavras de mesmo comprimentov3 <-rep(c("fulano", "jose", "joaquim", "martin"), length.out =length(v1))# juntamos com nome de colunas (tag = vetor) e comdd2 <-data.frame(RegistorID = v1, CodigoZ = v2, Pessoa = v3, stringsAsFactors =TRUE)# cabeçalhohead(dd2) # primeiras 6 linhas
RegistorID
CodigoZ
Pessoa
1
A
fulano
2
B
jose
3
C
joaquim
4
D
martin
5
E
fulano
6
F
jose
head(dd2, 3) # três primeiras linhas
RegistorID
CodigoZ
Pessoa
1
A
fulano
2
B
jose
3
C
joaquim
# rodapétail(dd2) # seis últimas linhas
RegistorID
CodigoZ
Pessoa
5
5
E
fulano
6
6
F
jose
7
7
G
joaquim
8
8
H
martin
9
9
I
fulano
10
10
J
jose
tail(dd2, 3) # três últimas linhas
RegistorID
CodigoZ
Pessoa
8
8
H
martin
9
9
I
fulano
10
10
J
jose
As funções dim(), nrow() e ncol() informam as dimensões de matrizes e data.frames, número de linhas, e número de colunas, respectivamente.
dim(dd2) # vetor com dois valores, número de linhas e número de colunas
## [1] 10 3
nrow(dd2) # número de linhas do data.frame ou matrix
## [1] 10
ncol(dd2) # número de colunas do data.frame ou matrix
## [1] 3
nrow(as.matrix(dd2))
## [1] 10
ncol(as.matrix(dd2))
## [1] 3
As funções str() e summary() informam a estrutura dos data.frames e o resumo dos dados, respectivamente.
str(dd2) # mostra a estrutura do objeto, quais colunas, classes de colunas e total de valores
summary(dd2) # mostra para cada coluna a variação encontrada: estatística descritiva de variáveis numéricas, contagem por categoria de fatores, etc. Veremos isso adiante.
RegistorID
CodigoZ
Pessoa
Min. : 1.00
A :1
fulano :3
1st Qu.: 3.25
B :1
joaquim:2
Median : 5.50
C :1
jose :3
Mean : 5.50
D :1
martin :2
3rd Qu.: 7.75
E :1
NA
Max. :10.00
F :1
NA
NA
(Other):4
NA
As funções colnames() e rownames() permitem VER e ATRIBUIR valores de nomes de linhas e colunas em data.frames e matrizes.
Em um data.frame, os nomes de linhas DEVEM SER ÚNICOS e não podem ter duas linhas com o mesmo nome.
São códigos que identificam registros únicos.
Isso é muito importante para o entendimento dos identificadores dos seus dados.
# vamos criar uma matriz com nomes de linhas e colunasmm <-matrix(1:9, nrow =3, ncol =3, dimnames =list(paste("linha", 1:3, sep =""), paste("coluna", 1:3, sep ="")))# e converter essa matrix para um data.framedd <-as.data.frame(mm)# vamos também criar outra matriz SEM nomes de linhas e colunasmm2 <-matrix(1:9, nrow =3, ncol =3)# e converter essa matrix para um data.framedd2 <-as.data.frame(mm2)dd2
V1
V2
V3
1
4
7
2
5
8
3
6
9
# para os objetos com nomes podemos ver os nomesrownames(mm)
## [1] "linha1" "linha2" "linha3"
rownames(dd)
## [1] "linha1" "linha2" "linha3"
colnames(mm)
## [1] "coluna1" "coluna2" "coluna3"
colnames(dd)
## [1] "coluna1" "coluna2" "coluna3"
# para os objetos sem nomesrownames(mm2) # nulo, não tem nome
## NULL
rownames(dd2) # números em formato de texto
## [1] "1" "2" "3"
colnames(mm2) # nulo, não tem nome
## NULL
colnames(dd2) # V1 a Vncol(dd) - ele cria nomes das colunas
## [1] "V1" "V2" "V3"
# note que no caso do data.frame dd2, apesar de não ter nome de linha e coluna, o R criou uma para ele. DATA.FRAMES SEMPRE TEM NOME DE LINHAS E COLUNAS. Note que o nome das linhas apesar de números correspondentes aos índices, são de fato TEXTO
# essas funções permitem VER mas também permitem ATRIBUIR (modificar) nomes# modificando quem já tem nome (matriz, mas funciona igual para dd)colnames(mm) # nomes atuais
## [1] "coluna1" "coluna2" "coluna3"
colnames(mm) <-c("novonome1", "novonome2", "novonome3")mm # veja como o nome das colunas mudou
novonome1
novonome2
novonome3
linha1
1
4
7
linha2
2
5
8
linha3
3
6
9
# mudando apenas o nome da coluna2colnames(mm)[2] <-"colunaDOIS"colnames(mm) # nomes atuais
## [1] "novonome1" "colunaDOIS" "novonome3"
# atribuindo quando não tem nomecolnames(mm2) # está vazio ou não existe (NULL)
## NULL
colnames(mm2) <-paste("banana", 1:ncol(mm2), sep ="-")mm2 # agora tem nome de coluna
banana-1
banana-2
banana-3
1
4
7
2
5
8
3
6
9
rownames(mm2) # nomes de linhas também está vazio
## NULL
rownames(mm2) <-paste("chuchu", 1:nrow(mm2), sep =".")mm2 # agora tem nomes de linha e coluna
banana-1
banana-2
banana-3
chuchu.1
1
4
7
chuchu.2
2
5
8
chuchu.3
3
6
9
Vamos tentar atribuir um mesmo nome de linha teste1 a duas linhas de nossa matriz mm2 e ver o que acontece:
rownames(mm2)[1:2] <-"teste1"# coloque o nome teste1 para as linhas 1 e 2 FUNCIONA PARA MATRIX
Reparem que um mesmo nome de linha pode ser utilizado em mais de uma linha de uma matriz. Será que isso pode ser feito em um data.frame? Vejamos:
rownames(dd)[1:2] <-"teste1"# nao funciona, porque ele não aceita nomes repetidos de linhas em DATA.FRAMES