Preparando dados
O script abaixo faz várias coisas:
- Pega os dados brutos e calcula a média dos valores
- Calcula novas variáveis para forma de folha e forma de estames (neste exemplo são úteis)
- Você explicita conjuntos de variáveis (colunas vegetativos, reprodutivos, qualitativos) e com isso:
- checa o número de amostras que pode comparar com cada variável e elimina variáveis que permitem poucas comparações
- checa as correlações entre variáveis de cada conjunto e a distribuição dos valores de cada variável
- identifica variáveis muito correlacionadas e decide se quer eliminar elas dos dados por dizerem a mesma coisa e minimizar efeito de dar muito peso a variáveis muito correlacionadas (e.g. tamanho de partes).
- Calcula a matriz de distância morfológica incluindo valores ausentes (e normatizando valores entre 0 e 1 - Gower)
- Gera um conjunto de dados a partir dessa matriz de distância (dadosMORFOnmds.csv)
Dados e funções usados
- dadosmorfobrutos.csv - dado usado para construir os scripts abaixo
- funcoesnecessarias.r - várias funções utilizadas nestes tutoriais
Código 01 - Dados médias e checa correlações
Você deverá adequar aos seus dados para que funcione adequadamente (especificamente os nomes das colunas para os conjuntos de dados)
#apaga todos os objetos rm(list=ls()) #carrega pacotes e funcoes necessarias source("funcoesNecessarias.R") #define caminho e arquivos #para ler dados.brutos = 'dadosParaAnalises/dadosMorfoBrutos.csv' #para salvar #caminhos para salvar as figuras, tabelas e dados gerados pelo script #ira repor arquivos com o mesmo nome se ja gerados #ira criar essa pasta se não houve no diretorio atual de trabalho (getwd()) pathparafiguras= "figuras" pathparatabelas= "tabelas" pathparadados = "dadosParaAnalises" #le os dados brutos, com variaveis ordinais e nominais codificadas como numeros ou 0 e 1 dad.morfo.bruto = read.table(file=dados.brutos,sep='\t',na.strings=c("NA",""),row.names = 1,as.is=T,header=T) #obtendo os valores médios de cada amostra dados.media = aplicamedia(dad.morfo.bruto) #Qual o número de variáveis para cada amostra? #para cada amostra qual o número mínimo de amostras com quem pode comparar? #classifique MANUALMENTE suas variáveis #pode adicionar novas classes além dos exemplos abaixo #nome das colunas das variaveis vegetativas quantitativas veg.quant = c("FOL_COMDOPEC", "FOL_ESPDOPEC", "FOL_COMDALAMFOL", "FOL_LARDALAM", "FOL_ALTDAMAXLAR") #nome das colunas das variaveis vegetativas categoricas #ou seja, todas as variaveis que originalmente eram categoricas veg.quali = c("IND_GEMAPIDEN", "IND_GEMAPITIP_aracnoide", "IND_GEMAPITIP_simplesereto", "IND_LAMABADEN", "IND_LAMABATIP") #nome das variaveis reprodutivas quantitativas flor.quant= c("FLO_COMDOPED", "FLO_DIADOPED", "FLO_COMMAXDAFLO", "FLO_DIADAFLO", "AND_PREDEGLANOSESTDOVERIII", "AND_COMESTVERI", "FLO_LARESTVERI", "AND_COMESTVERII", "AND_LARESTVERII", "COR_COMDOSESTDOVERIII", "AND_LARDOSESTVERIII","FLO_DIAMAXDOOVA", "GIN_COMDOPIS") #nome das colunas das variaveis vegetativas categoricas #ou seja, todas as variaveis que originalmente eram categoricas flor.quali = c( "IND_TEPNAFACEXTDEN", "IND_TEPNAFACEXTTIP_aracnoide", "IND_TEPNAFACEXTTIP_simpleadpresso", "IND_TEPNAFACEXTTIP_simpleeretos", "IND_TUBFLOINTDEN", "IND_TUBFLOINTTIP_aracnoide", "IND_TUBFLOINTTIP_simpleadpresso", "IND_TUBFLOINTTIP_simpleeretos") #se quiser eliminar algumas colunas que entraram por engano #informe aqui eliminadas = c("FOL_LARDALAMNAMET", "COL_ALT", "COL_DAP") #para cada conjunto de variaveis, conta para cada variavel o número de amostras que ela permite comparar contaramostraporvar <- function(y,dd) { yy = as.numeric(as.vector(dd[,y])) sum(!is.na(yy)) } pd.veg.quant = sapply(veg.quant,contaramostraporvar,dd=dados.media) pd.veg.ind = sapply(veg.quali,contaramostraporvar,dd=dados.media) pd.flor.quant = sapply(flor.quant,contaramostraporvar,dd=dados.media) pd.flor.ind = sapply(flor.quali,contaramostraporvar,dd=dados.media) #junta tudo mm1 = data.frame(CATEG="Vegetativos Quantitativos",NAMOSTRAS=pd.veg.quant) mm2 = data.frame(CATEG="Vegetativos Qualitativos",NAMOSTRAS=pd.veg.ind) mm3 = data.frame(CATEG="Flor Quantitativo",NAMOSTRAS=pd.flor.quant) mm4 = data.frame(CATEG="Flor Qualitativos",NAMOSTRAS=pd.flor.ind) mm = rbind(mm1,mm2,mm3,mm4) tbb = table(mm$NAMOSTRAS) tbb = as.data.frame(tbb) row.names(tbb)= tbb[,1] categs = levels(as.factor(mm$CATEG)) for(l in 1:length(categs)){ vl = as.factor(mm$CATEG)==categs[l] tbb1 = table(mm$NAMOSTRAS[vl]) tbb[,categs[l]] = NA tbb[names(tbb1),categs[l]] = tbb1 } tbb = tbb[,-1] tbb = as.matrix(tbb[,-1]) tbb = t(tbb) dir.create(pathparafiguras) dir.create(pathparatabelas) dir.create(pathparadados) pdf(paste(pathparafiguras,"/01_amostrasPorvariaveis.pdf",sep=""),width=8.5,height=10) par(las=1,mar=c(4,12,3,2)) barplot(tbb,beside=T,col=c("green","red","blue","yellow"),horiz=T,ylab="Número de amostras",xlab="Número de variáveis") legend(x=2,y=30,legend=row.names(tbb),pch=22,pt.bg=c("green","red","blue","yellow"),ncol=1,cex=0.8) dev.off() #tem variaveis que permitem comparar poucas amostras? #qual o mínimo aceitável para inclusão na análise #ou seja, quais variaveis devem ser eliminadas porque tem #muitos valores ausentes na coluna #melhor eliminar essas variaveis dos dados #pois terão pouco efeito de qualquer forma nas comparacoes #Qual o numero mínimo de amostras para incluir a variavel? n.minimo = 5 vl = mm$NAMOSTRAS<=n.minimo #então quais elimina? quais.vars = rownames(mm[vl,]) #elimina essas colunas dos dados.media #e das listas de categorias rn = colnames(dados.media) rn = rn[!rn%in%quais.vars] dados.media = dados.media[,rn] veg.quant = veg.quant[!veg.quant%in%quais.vars] veg.quali= veg.quali[!veg.quali%in%quais.vars] flor.quant= flor.quant[!flor.quant%in%quais.vars] flor.quali= flor.quali[!flor.quali%in%quais.vars] #definindo similaridades: #1) qual importancia das variáveis medidas #2) elas expressam de fato o que eu considero informativo no meu grupo? ####FORMA DE FOLHAS #por exemplo. Eu quero definir minhas variaveis #de acordo com o que eu percebo que é importante. #Eu medi folhas mas acho que a forma da folha expressa pelas #seguintes variáveis melhor descreve os padrões que eu percebo #nas minhas amostras: #a) As folhas variam na proporcao entre largura e comprimento da lamina (há folhas mais obovadas, outras mais elípticas e outras mais redondas) #isso pode ser codificado em duas razoes numéricas: #a.1) máxima largura dividida pelo comprimento da lamina (forma da lâmina) - FORMA01 #salva figuras das variaveis criadas num arquivo pdf(paste(pathparafiguras,"/02_formaFolhas.pdf",sep=""),width=8.5,height=10) FORMA01 = dados.media$FOL_LARDALAM/dados.media$FOL_COMDALAMFOL par(mfrow=c(3,1),las=1,mar=c(5,4,3,3),mgp=c(2.5,0.5,0),cex.axis=0.8,tck=-0.01) h = hist(FORMA01,breaks =30,col='blue',xlim=c(0,max(FORMA01,na.rm = T)+min(FORMA01,na.rm=T)),ylab ="Número amostras",xlab="Forma01 = (máxima largura/comprimento) da Lâmina Foliar",main="") text(h$mids[1],h$counts[1]+0.5,labels="Folhas + estreitas",srt=90,adj=c(0,0.5),cex=0.8) text(h$mids[length(h$mids)],h$counts[length(h$counts)]+0.5,labels="Folhas + arredondadas",srt=90,adj=c(0,0.5),cex=0.8) #b) outra medida que mostra se lâmina é mais obovada, elíptica ou ovada, é a razao entre a altura da máxima largura e comprimento total FORMA02 = dados.media$FOL_ALTDAMAXLAR/dados.media$FOL_COMDALAMFOL par(las=1,mar=c(5,4,3,2),mgp=c(2.5,0.5,0),cex.axis=0.8,tck=-0.01) h <- hist(FORMA02,breaks =30,col='red',xlim=range(FORMA02,na.rm=T)+c(-0.1,+0.1),ylab ="Número amostras",xlab="Forma02 = (altura da máxima largura/comprimento) da Lâmina Foliar",main="") text(h$mids[1],h$counts[1]+0.5,labels="Folhas + elípticas",srt=90,adj=c(0,0.5),cex=0.8) text(h$mids[length(h$mids)],h$counts[length(h$counts)]+0.5,labels="Folhas + obovadas",srt=90,adj=c(0,0.5),cex=0.8) #c)uma última variável de forma, é a proporçao da folha que é peciolo, ou seja do comprimento total da folha, quanto é peciolo. Isso mostra porporcionalmente se o peciolo é muito pequeno ou se a folha é peciolada FORMA03 = dados.media$FOL_COMDOPEC/(dados.media$FOL_COMDOPEC+dados.media$FOL_COMDALAMFOL) par(las=1,mar=c(5,4,3,2),mgp=c(2.5,0.5,0),cex.axis=0.8,tck=-0.01) h <- hist(FORMA03,breaks =30,col='green',xlim=range(FORMA03,na.rm=T)+c(-0.04,+0.04),ylab ="Número amostras",xlab="Forma03 = (comprimento peciolo/comprimento da folha)",main="") text(h$mids[1],h$counts[1]+0.5,labels="Folhas sésseis",srt=90,adj=c(0,0.5),cex=0.8) text(h$mids[length(h$mids)],h$counts[length(h$counts)]+0.5,labels="Folhas + pecioladas",srt=90,adj=c(0,0.5),cex=0.8) dev.off() #adiciona essas variaveis aos vetores e dados veg.quant= c(veg.quant,c("FORMA01","FORMA02","FORMA03")) dados.media = data.frame(dados.media,FORMA01,FORMA02,FORMA03,stringsAsFactors = F) #####FORMA DOS ESTAMES #no caso deste exemplo #algumas formas dos estames fazem sentido pdf(paste(pathparafiguras,"/05_formaEstames.pdf",sep=""),width=8.5,height=10) FORMA.ESTAME.I = dados.media$AND_LARESTVERI/dados.media$AND_COMESTVERI par(mfrow=c(3,1),las=1,mar=c(5,4,3,3),mgp=c(2.5,0.5,0),cex.axis=0.8,tck=-0.01) h = hist(FORMA.ESTAME.I,breaks =30,col='blue',xlim=range(FORMA.ESTAME.I,na.rm=T)+c(-0.04,+0.04),ylab ="Número amostras",xlab="FormaEstameI = (largura estame/comprimento estame",main="") text(h$mids[1],h$counts[1]+0.5,labels="Estames I + estreitos",srt=90,adj=c(0,0.5),cex=0.8) text(h$mids[length(h$mids)],h$counts[length(h$counts)]+0.5,labels="Estames I + largos",srt=90,adj=c(0,0.5),cex=0.8) #agora vamos juntar os dados apenas com as variaveis FORMA.ESTAME.II = dados.media$AND_LARESTVERII/dados.media$AND_COMESTVERII par(las=1,mar=c(5,4,3,2),mgp=c(2.5,0.5,0),cex.axis=0.8,tck=-0.01) h = hist(FORMA.ESTAME.II,breaks =30,col='green',xlim=range(FORMA.ESTAME.II,na.rm=T)+c(-0.04,+0.04),ylab ="Número amostras",xlab="FormaEstameII = (largura estame/comprimento estame",main="") text(h$mids[1],h$counts[1]+0.5,labels="Estames II + estreitos",srt=90,adj=c(0,0.5),cex=0.8) text(h$mids[length(h$mids)],h$counts[length(h$counts)]+0.5,labels="Estames II + largos",srt=90,adj=c(0,0.5),cex=0.8) #agora vamos juntar os dados apenas com as variaveis FORMA.ESTAME.III = dados.media$AND_LARDOSESTVERIII/dados.media$COR_COMDOSESTDOVERIII par(las=1,mar=c(5,4,3,2),mgp=c(2.5,0.5,0),cex.axis=0.8,tck=-0.01) hist(FORMA.ESTAME.III,breaks =30,col='blue',xlim=range(FORMA.ESTAME.III,na.rm=T)+c(-0.04,+0.04),ylab ="Número amostras",xlab="FormaEstameIII = (largura estame/comprimento estame",main="") text(h$mids[1],h$counts[1]+0.5,labels="Estames III + estreitos",srt=90,adj=c(0,0.5),cex=0.8) text(h$mids[length(h$mids)],h$counts[length(h$counts)]+0.5,labels="Estames III + largos",srt=90,adj=c(0,0.5),cex=0.8) dev.off() #adiciona essas variaveis aos vetores e dados flor.quant = c(flor.quant,c("FORMA.ESTAME.I","FORMA.ESTAME.II","FORMA.ESTAME.III")) dados.media = data.frame(dados.media,FORMA.ESTAME.I,FORMA.ESTAME.II,FORMA.ESTAME.III,stringsAsFactors = F) ####CHECA AS CORRELACOES ENTRE VARIAVEIS ###MOSTRA AS DISTRIBUICOES UNIVARIADAS osdados = list(veg.quant=veg.quant,flor.quant=flor.quant,qualitativos=c(veg.quali,flor.quali)) #note que juntei os dois grupos de dados #qualitativos #por quero ver a correlacao entre eles #pois se referem neste caso à indumento #para cada conjunto de variaveis #checa as correlacoes entre variaveis #e gera uma figura para cada dado (num pdf unico) #e uma tabela mostrando as correlacoes (significativas) entre todos os pares de variaveis arqn = paste(pathparafiguras,"/06_CorrelacoesEntreVariaveis.pdf",sep="") pdf(arqn,width=10,height=8.5) for(d in 1:length(osdados)) { colunas = osdados[[d]] nomedado = names(osdados)[d] #pega esses dados dv = dados.media[,colunas] #salva num arquivo pairs(dv, lower.panel = panel.smooth, upper.panel = panel.cor, diag.panel = panel.hist) mtext(side=3,line=2.5,text = toupper(nomedado),cex=1,adj=0, font=2) #testa correlacoes ascors = fazascor(dv) #mostra apenas as significativas vl = ascors$PV<0.05 par(mar=c(5,5,3,3)) plotatable(ascors[vl,]) mtext(side=2,line=2,text = paste("Correlações significativas para",toupper(nomedado)),cex=1,adj=1, font=2) fn = paste(pathparatabelas,"/",nomedado,".csv",sep="") write.table(ascors,fn,sep="\t",na="",row.names = T,quote=T) } dev.off() ####ELIMINANDO VARIAVEIS CORRELACIONADAS### ####EXPLICITANDO O QUE VOCE ACHA IMPORTANTE### #na figura gerada acima #algumas variáveis estão fortemente correlacionadas. Elas expressam apenas 1 coisa: tamanho das parte vegetativas e isso pode estar representado na análise por apenas 1 dessas variáveis, indicando tamanho. Note que as variáveis de forma não estão correlacionadas com as variáveis brutas medidas, expressando outro tipo de informação veg.quant.excluidas = c("FOL_ESPDOPEC","FOL_LARDALAM", "FOL_ALTDAMAXLAR") gp = which(veg.quant%in%veg.quant.excluidas) veg.quant = veg.quant[-gp] #agora as variaveis de indumento o.indumento = c(veg.quali,flor.quali) #duas variaveis estao correlacionadas expressando a mesma coisa (face externa, quanto tem muito pelo é aracnoide, entao nao precisa usar as duas, vamos usar apenas densidade) o.indumento=o.indumento[!o.indumento=="IND_TEPNAFACEXTTIP_aracnoide"] #diametro da flor, comprimento da flor e comprimento do pedicelo estao fortemente correlacionados (r>0.8). Todos eles expressam tamanho da flor em geral. Portanto, vamos ficar apenas com comprimento da flor expressando isso #comprimento e largura dos estames do verticilo I e II também, portanto apenas 1 basta de cada #a forma dos estames do verticilo I e II também. Deixando apenas vert I e vert III flor.quant.excluidas = c("FLO_DIADAFLO","FLO_COMDOPED","AND_COMESTVERII","FORMA.ESTAME.II","FLO_LARESTVERI","AND_LARESTVERII") #outras??? depende de como você quer definir similaridade flor.quant = flor.quant[!flor.quant%in%flor.quant.excluidas] #junta todas as variaveis num objeto medias cls = c(veg.quant,o.indumento,flor.quant) dados.media2 = dados.media[,cls] #todo registro precisa pelo menos ter dados vegetativos #elimina linhas que não tem vl = is.na(dados.media2$FOL_COMDALAMFOL) dados.media2 = dados.media2[!vl,] vl = is.na(dados.media$FOL_COMDALAMFOL) dados.media = dados.media[!vl,] #ultima checada contanas <- function(x) { sum(is.na(x))/length(x) } nas1 = apply(dados.media,1,contanas) nas2 = apply(dados.media2,1,contanas) hist(nas1,main='NAs em dados.media',breaks=20,col="red") hist(nas2,main='NAs em dados.media2',breaks=20,col="red") #salva esse arquivo fn = paste(pathparadados,"/dados_medias_varsel.csv",sep="") write.table(dados.media2,file=fn,sep="\t",row.names = T,na="",quote=T) #salva o arquivo com todas as variaveis fn = paste(pathparadados,"/dados_medias_todasvar.csv",sep="") write.table(dados.media,file=fn,sep="\t",row.names = T,na="",quote=T) #gera um arquivo com histogramas para cada variavel odado = dados.media fn = paste(pathparafiguras,"/07_dadoMediasHistogramas_todas.pdf",sep="") pdf(fn,width=8.5,height=10) par(mfrow=c(3,2),mar=c(5,4,3,3),mgp=c(2.5,0.5,0),tck=-0.01,cex.axis=0.8) for(cl in 1:ncol(odado)) { cln = colnames(odado)[cl] var = odado[,cl] hist(var,xlab=cln,col='red',breaks =30,main="") } dev.off()
Código 02 - Matriz de distancia e NMDS
rm(list=ls()) source("funcoesNecessarias.R") #calcula a distancia morfológica e o dado NMDS resultante #CALCULA A DISTANCIA MORFOLÓGICA USANDO GOWER #le os dados arq1 = "dadosParaAnalises/dados_medias_todasvar.csv" dados.media = read.table(file=arq1,sep="\t",row.names = 1,na.strings =c("NA","")) #elimina umas colunas desses dados eliminadas = c("FOL_LARDALAMNAMET", "COL_ALT", "COL_DAP") cls = colnames(dados.media) cls = cls[!cls%in%eliminadas] dados.media = dados.media[,cls] #dados com variaveis selecionadas arq2 ="dadosParaAnalises/dados_medias_varsel.csv" dados.media2 = read.table(file=arq2,sep="\t",row.names = 1,na.strings =c("NA","")) #qual desses dados vai rodar? abaixo faz todos qualdados = list(varsel=dados.media2,todasvar=dados.media) #define caminho para salvar figuras e objetos pathparadados = "dadosParaAnalises" pathparafiguras = "figuras" pathparatabelas = "tabelas" dir.create(pathparadados) dir.create(pathparafiguras) dir.create(pathparatabelas) #calcula a distancia morfológica de gower #veja detalhes no help da funcao daise para entender o que ele faz com NAs (pode ter dados faltantes) #para cada dado parasalvar = NULL for(d in 1:length(qualdados)) { odado = qualdados[[d]] nomedado = names(qualdados)[d] md = daisy(odado, metric = "gower", stand = F,warnBin = F) #pega parte inferior da matriz, excluindo a diagonal tt = md[lower.tri(md,diag = F)] #plota essas distancias numa figura fn = paste(pathparafiguras,"/Histograma_morfoGowerDist_",nomedado,".pdf",sep="") pdf(fn,width=6,height=5) hist(tt,breaks=40,col='red',xlab="Distância morfológica de gower",main="") dev.off() #se for NA, então a dissimilaridade é 0 (No help: "If all weights w_k delta(ij;k) are zero, the dissimilarity is set to NA") #vamos tratar tudo como 0 de dissimilaridade para esses pares de amostra md[is.na(md)] = 0 #NMDS nao funciona se tem amostras com distancia 0. Entao, coloca uma dissimilaridade muito pequena para esses casos md[md==0] = table(round(md,3))[2]/100000 #guarda objetos de distancia numa lista para um Rdata parasalvar[[nomedado]] = list(morfodist=md,dado=odado) } #salva distancias de gower num Rdata para uso fn = paste(pathparadados,"/morfoDistGower.Rdata",sep="") save(parasalvar,file=fn) #QUAL O NÚMERO DE EIXOS MINIMOS (K) QUE DEVO REDUZIR MEUS DADOS SEM PERDER INFORMACAO #qual o número de eixos que minimiza o valor de stress no NMDS? #testa de k=2 a k=número de variáveis originais fn = paste(pathparafiguras,"/EixosMinimosParaNMDSbruto_",nomedado,".pdf",sep="") pdf(fn,width=8.5,height=10) par(mfrow=c(2,1),mar=c(5,4,3,2),cex.axis=0.8) for(d in 1:length(parasalvar)) { odado = parasalvar[[d]][['dado']] nomedado = names(parasalvar)[d] md = parasalvar[[d]][['morfodist']] qualk = NULL #para tantas variaveis quanto em odado for(k in 2:ncol(odado)) { print(paste(k,"de",ncol(odado))) m.nmds = isoMDS(md,k=k) rr = data.frame(K=k,STRESS=m.nmds$stress) qualk = rbind(qualk,rr) } K = qualk$K STRESS = qualk$STRESS plot(K,STRESS,type='l',lwd=2,lty='solid',main=nomedado,col='red') points(K,STRESS,pch=21,cex=2,bg='red') } dev.off() #TRANSFORMANDO OS DADOS #qual o K mínimo após o qual o valor de stress estabiliza? #ve a correlacao entre matrizes #md1 =parasalvar[[1]][['morfodist']] #md2 =parasalvar[[2]][['morfodist']] #plot(md1,md2) #um vetor com um valor de K #para cada dado em parasalvar um.bom.k = c(30,30) #gerar o NMDS e salvar os dados for(d in 1:length(parasalvar)) { odado = parasalvar[[d]][['dado']] nomedado = names(parasalvar)[d] md = parasalvar[[d]][['morfodist']] m.nmds = isoMDS(md,k=um.bom.k[d]) dado.nmds = m.nmds$points colnames(dado.nmds) = paste("NMDS",1:ncol(dado.nmds),sep='') fn = paste(pathparadados,"/dadosMORFOnmds",nomedado,".csv",sep="") write.table(dado.nmds,file=fn,sep="\t",na="",row.names=T,quote=T) } #pronto dadosMorfoNMDS gerados para análises