[[bot89:precurso:3matrizes:inicio]]

Filtrando e Ordenando Matrizes

  • Já vimos como fazer perguntas sobre vetores e obter vetores lógicos ou valores de índices que nos permitem extrair ou filtrar de vetores os dados que satisfazem às condições das perguntas feitas.
  • Aqui vamos extender isso para Matrizes e Data.Frames, porque é através de vetores lógicos ou de matrizes lógicas que podemos filtrar dados de objetos bidimensionais
?iris  #veja o help do R sobre Edgar Anderson's Iris Data que explica esses dados que vem com o R
class(iris)
str(iris)  #estrutura, veja as colunas
 
#vamos filtrar os dados de uma das especies
unique(iris$Species) #vemos os valores únicos
#ou, tendo em vista que é um fator
levels(iris$Species)
sp1 = levels(iris$Species)[1]
#quais linhas correspondem a essa especie
vl = iris$Species==sp1
sum(vl) #numero de linhas que satisfazem a pergunta
nrow(iris) #numero total de linhas no data.frame
#filtrando os dados eu simplesmente uso o vetor lógico como índice de linha. O novo objeto criado terá apenas as linhas em que vl é verdadeiro
iris.sp1 = iris[vl,]
nrow(iris.sp1)==sum(vl) #entao esta condição é verdadeira
 
#filtrar segundo duas colunas
vl = iris$Species==sp1 #seja da especie em sp1
sum(vl) #quantas sao?
vl2 = iris$Sepal.Length<=5 #tenha sepala menor ou igual a 5
sum(vl2) #quantas sao?
#combinando as duas perguntas
vll = vl & vl2
sum(vll) #quantas sao?
#filtrando
ff = iris[vll,] 
class(ff) #novo data.frame resultando do filtro realizado
nrow(ff)== sum(vll)  #isso deve ser verdadeiro
  • As funções is.na() e na.omit() vistas anteriormente permitem eliminar linhas e colunas que tenham valores ausentes, que muitas vezes impedem análises.
#vamos fazer uma cópia do objeto iris e modificar ele acrescentando alguns NAs
dd = iris
#tem algum NA originalmente?
sum(is.na(dd)) #não tem
 
#qual a dimensão?
dim(dd)
#pega 10 valores aletórios entre 1:150 (linhas)
v1 = sample(1:nrow(dd),size=10,replace=F)
#nessas linhas acrescenta NAs na coluna 2
dd[v1,2] = NA
#pega outros 10 valores aletórios entre 1:150 (linhas)
v1 = sample(1:nrow(dd),size=10,replace=F)
#nessas linhas acrescenta NAs na coluna 3
dd[v1,3] = NA
 
#pronto agora temos um data.frame com NAs
sum(is.na(dd)) #tem 20 NAs na tabela
 
#quais linhas tem NA
vl = is.na(dd[,2]) | is.na(dd[,3]) #ou é NA em 2 ou em 3 que foi onde mudei
dd[vl,]
 
#use na.omit() para eliminar todas as linhas que NA em alguma coluna
sum(is.na(dd)) #tem 20 valores
dd2 = na.omit(dd)
sum(is.na(dd2)) #nao tem mais nenhum

Para order matrizes e data.frames precisamos entender a diferença entre duas funções:

  • sort() - ordena um vetor e retorna os valores ordenados
  • order() - ordena um vetor e retorna os índices dos valores ordenados. Isso que você usa para ordenar matrizes e data.frames.
?sort
?order
#ordenação
str(iris)  
 
#funcao SORT()
o1 = sort(iris$Sepal.Length) #pega os valores ordenados da coluna comprimento de sépala
o1 #sao valores de sepalas do menor para o maior
#em ordem decrescente
o2 = sort(iris$Sepal.Length,decreasing=T)
o2 #sao valores de sepalas do maior para o menor
 
#FUNCAO order()
#qual o indice dos valores ordenados em ordem crescente?
o3 = order(iris$Sepal.Length)
o3 #esses valores correspondem aos INDICES dos valores ordenados
#entao para ver os valores ordenados
iris$Sepal.Length[o3]
#então isso deve ser totalmente verdadeiro: 
iris$Sepal.Length[o3]==sort(iris$Sepal.Length) #as comparações para a par são identicas
#então esta expressão também é verdadeira:
sum(iris$Sepal.Length[o3]==sort(iris$Sepal.Length))==nrow(iris)
 
#portanto a função sort ordena os valores e funcao order mostra apenas os indices dos valores ordenados. Assim, posso usar a funcao order() para ordenar data.frames, matrizes e vetores
idx = order(iris$Sepal.Length) #indice das linhas ordenadas segundo o comprimento das sepalas
#compara com o original:
sum(iris$Sepal.Length[idx]==iris$Sepal.Length)==nrow(iris) #é FALSO porque em iris as linhas não estão originalmente ordenadas segundo o comprimento. 
 
#vamos mudar isso
novo.iris = iris[idx,] #pego o vetor de indices dos valores ordenados e uso na indexacao para ordenar o objeto original segunda a coluna escolhida
idx2 = order(novo.iris$Sepal.Length) #indice das linhas ordenadas segundo o comprimento das sepalas
#note que agora essa expressão é verdadeira, porque o original já está ordenado segundo essa coluna
sum(novo.iris$Sepal.Length[idx2]==novo.iris$Sepal.Length)==nrow(novo.iris) #é FALSO 
 
 
#AGORA ORDENANDO POR MULTIPLAS COLUNAS
idx = order(iris$Species,iris$Sepal.Length, decreasing=TRUE) #por especie e por sepala em ordem decrescente
 
#ordena segundo essas duas colunas
novo.iris = iris[idx,]
novo.iris[,c("Species","Sepal.Length")]
 
#para cada especie esta ordenado por sepala:
novo.iris[novo.iris$Species=="versicolor",]$Sepal.Length  
novo.iris[novo.iris$Species=="virginica",]$Sepal.Length

É comum termos dados relacionados em tabelas diferentes, recurso que minimiza a entrada de redundância e portanto de erros nos nossos dados. Vamos ver isso em dados e metadados.

#vou criar aqui uma situação artificial com os dados iris, mas imagine uma situação mais complexa com muitos dados
 
#uma tabela com os nomes das especies
spp = unique(data.frame(GENUS="Iris",SPECIES=iris$Species,stringsAsFactors = F))
spp$fullname = paste(spp$GENUS,spp$SPECIES)
 
################################################################
#vou adicionar uns dados para esses nomes baixando da internet
###SO FUNCIONA COM INTERNET: pesquisa esses nomes na interne e traz algo
#tem varios jeitos de fazer isso, aqui apenas para produzir um dado
#pesquisa no TNRS o nome cientifico
library(taxize) #instale se nao tiver
sppinfo = sapply(spp$fullname,tp_search,type='exact')
#pega as colunas obtidas para todos os nomes
keys <- table(unlist(lapply(sppinfo, names)))
keys = names(keys[keys==length(sppinfo)])
#junta tudo num unico data.frame
sppinfo = as.data.frame(do.call(mapply, c(FUN=c, lapply(sppinfo, `[`, keys))),stringsAsFactors = F)
#tira osnomes illegits
sppinfo = sppinfo[-grep("illeg",sppinfo$nomenclaturestatusname,ignore.case = T),]
#cria um identificaor compartilhado entre tabelas
sppinfo$Species = gsub("Iris ","",sppinfo$scientificname)
#bagunca a ordem
sppinfo = sppinfo[sample(1:3),]
rownames(sppinfo) = sppinfo$Species
##NAO SE PREOCUPE EM DECIFRAR A BUSCA E ORGANIZACAO DESSA TABELA
################################################################
 
#agora temos dois conjuntos de dados, que em comum tem a coluna Species
#mas tem linhas diferentes
sppinfo
head(iris)
 
#suponha que voce queira adicionar à tabela iris uma coluna com informacao que esta na tabela sppinfo
 
#JEITO 1 DE FAZER ISSO (USANDO MATCH)
#pega as linhas da tabela sppinfo para cada linha da tabela iris
#para isso eu quero o INDICE da tabela sppinfo segundo o valor da coluna Species que a coluna comum às duas tabelas
idxinfo = match(iris$Species,sppinfo$Species)
#idxinfo é um vetor que tem o mesmo comprimento que o numero de linhas que iris e contem o numero das linhas (os indices) da tabela sppinfo
#assim, seguindo indexacao numerica eu posso pegar informacoes da tabela sppinfo e colocar na tabela iris
iris$speciesComAutor = sppinfo$scientificnamewithauthors[idxinfo]
head(iris)
#jutando as duas tabelas
novoiris = cbind(iris,sppinfo[idxinfo,])
head(novoiris)
 
 
#JEIO 2 DE FAZER ISSO (USANDO INDICES NOMINAIS)
#sppinfo contém nomes de linhas que correspondem aos valores que estao na coluna iris$Species
#portanto, para fazer a mesma coisa eu poderia simplesmente pegar atraves dos nomes das linhas da tabela sppinfo
iris$speciesComAutor = sppinfo[iris$Species,]$scientificnamewithauthors
#juntando as duas tabelas  completas
novoiris = cbind(iris,sppinfo[iris$Species,])
 
 
#e tem outros jeitos que voces irão descobrindo
  • bot89/precurso/3matrizes/inicio.txt
  • Última modificação: 08/07/2020 13:07
  • por labotam_admin