* [[02_tutoriais:tutorial8:start|Tutorial]]
* [[01_curso_atual:exercicios9| Exercícios]]
* [[03_apostila:programar_ale| Apostila]]
====== 9. Noções de Programação ======
===== R: Um Ambiente Orientado a Objetos =====
==== Atributos ====
Até esse ponto do curso, foi visto que existem no R funções, variáveis e vetores. Todos esses ítens são chamados genericamente de **objetos**.
Veremos no decorrer do curso vários outros **objetos** do R. A importância do conceito de **objeto** num ambiente de trabalho de análise de dados é que os objetos possuem **atributos**, os quais podem variar em função do tipo de objeto.
Vejamos um exemplo.
> zoo
onça anta tatu guará
4 10 2 45
> class( zoo )
[1] "numeric"
> length( zoo )
[1] 4
> names( zoo )
[1] "onça" "anta" "tatu" "guará"
>
O vetor '''zoo''' é um vetor de classe '''numeric''', de comprimento ('''length''') 4 e com nomes ('''names'''): onça, anta, tatu e guará. Classe, comprimento e nomes são os atributos típicos de vetores.
Qualquer vetor sempre terá uma classe e um comprimento, mas o atributo '''names''' é opcional:
> b
[1] 1 2 3 4 5 6 7 8
> class( b )
[1] "integer"
> length( b )
[1] 8
> names( b )
NULL
>
A função '''attributes''' nos mostra os atributos de um objeto, mas é de uso limitado no caso de vetores:
> zoo
onça anta tatu guará
4 10 2 45
> attributes( zoo )
$names
[1] "onça" "anta" "tatu" "guará"
> b
[1] 1 2 3 4 5 6 7 8
> attributes( b )
NULL
>
==== Funções ====
As funções do R também são objetos, mas da classe '''function''':
> class( ls )
[1] "function"
> class( log )
[1] "function"
> class( sin )
[1] "function"
>
No caso das funções, podemos associar a elas os **argumentos** que elas necessitam para serem executadas:
> args( ls )
function (name, pos = -1, envir = as.environment(pos), all.names = FALSE,
pattern)
NULL
> args( log )
function (x, base = exp(1))
NULL
>
Algumas funções matemáticas, no entanto, tem sempre apenas um argumento e são consideradas **funções primitivas**:
> args( sin )
NULL
> sin
.Primitive("sin")
>
> args( exp )
NULL
> exp
.Primitive("exp")
>
==== Mundo dos Objetos ====
Um aspecto importante num ambiente orientado a objetos é que **tudo** o que o ambiente trabalha são objetos e o ambiente não pode trabalhar com nada que não seja um objeto conhecido. Inclui nessa categoria tudo aquilo que o R apresenta na tela, por isso toda saída do R pode ser guardada num objeto:
> length( zoo )
[1] 4
> zoo.comp = length( zoo )
> zoo.comp
[1] 4
> class( zoo )
[1] "numeric"
> zoo.class = class( zoo )
> zoo.class
[1] "numeric"
> class( zoo.class )
[1] "character"
> names( zoo )
[1] "onça" "anta" "tatu" "guará"
> class( names( zoo ) )
[1] "character"
> length( names( zoo ) )
[1] 4
>
Quando o R nos mostra, como resultado de uma operação, valores como '''NULL''' e '''integer(0)''' ele está dizendo que o resultado é **vazio**, isto é, não há resultado:
> b
[1] 1 2 3 4 5 6 7 8
> names( b )
NULL
> b[ b > 10 ]
integer(0)
>
Veja que o valor '''NULL''' é um valor válidos que podem ser utilizados.
> zoo2 = zoo
> zoo2
onça anta tatu guará
4 10 2 45
> names( zoo2 )
[1] "onça" "anta" "tatu" "guará"
> names( zoo2 ) = NULL
> zoo2
[1] 4 10 2 45
> names( zoo2 )
NULL
>
=== Exercícios ===
Considere o vetor com nome de espécies:
> sp
[1] "Myrcia sulfiflora" "Syagrus romanzoffianus" "Tabebuia cassinoides"
[4] "Myrcia sulfiflora"
>
Para obter a freqüência das espécies podemos usar a função '''table''':
> table( sp )
sp
Myrcia sulfiflora Syagrus romanzoffianus Tabebuia cassinoides
2 1 1
>
Qual a classe do objeto que a função '''table''' retorna? Quais são os seus attributos?
Qual a classe do objeto produzido pelo comando '''class( x )'''?
===== Construindo Funções Simples =====
==== A Estrutura Básica de uma Função ====
Toda manipulação de dados e análises gráficas e estatísticas no R são realizadas através de funções. Entretanto, você não precisa ser um programador experimentado para construir algumas funções simples para facilitar a atividade de manipulação de dados.
A estrutura básica de uma função é:
> minha.funcao <- function( argumento1, argumento2, argumento3, . . .)
{
comando 1
comando 2
comando 3
. . .
comando n
return("resultado")
}
Os elementos dessa expressão são:
* **minha.funcao** é o nome que a nova função receberá;
* **function** é a expressão no R que cria uma nova função;
* **entre as chaves "{}"** são listados os comandos da função, sempre com um comando por linha;
* **entre os parênteses "()"** são listados (separados por vírgula) os argumentos necessários a função;
* **comando return("resultado") ** retorna os resultados, caso falte, será apresentado o resultado do último comando (comando n).
Vejamos alguns exemplos simples:
##criar um vetor de dados com 20 valores aleatórios de uma distribuição Poisson
dados.dens<-rpois(20,lambda=6)
##funcão para calcular média
media.curso <-function(x,rmNA=TRUE)
{
soma=sum(x)
nobs=length(x)
media=soma/nobs
return(media)
}
##Vamos agora preparar uma função mais elaborada, considerando a
##presença e excluíndo NA por padrão, e lançando mensagem na tela
##sobre o número de NAs removidos. Note que é uma função com dois argumentos
##que permite ao usuário tomar a decisão de remover ou não NAs e avisando,
##diferente da função mean()
media.curso <-function(x,rmNA=TRUE)
{
if(rmNA==TRUE)
{
dados=(na.omit(x))
dif=length(x)-length(dados)
cat("\t", dif," valores NA excluídos\n")
}
else
{
dados=x
}
soma=sum(dados)
nobs=length(dados)
media=soma/(nobs)
return(media)
}
###calcular a média do objeto dados
media.curso(dados.dens)
##########################################
###função para calcular variância
var.curso<-function(x)
{
media=media.curso(x)
dados=na.omit(x)
disvquad=(dados-media)^2
variancia=sum(disvquad)/(length(dados)-1)
return(variancia)
}
###Calcular a variância de dados
var.curso(dados.dens)
###Tomando dados.dens como a contagem de uma espécie em uma amostra de 20 parcelas de 20x20m,
###podemos verificar o padrão de dispersão dessa espécie, utilizando o Índice de Dispersão (razão variância / média)
ID.curso<-function(x)
{
id=var.curso(x)/media.curso(x)
return(id)
}
##Calcular o coeficiente de dispersão
ID.curso(dados.dens)
## quando o valor é próximo a 1 a distribuição é considerada aleatória.
## podemos fazer um teste de significância pela aproximação com o valor Qui-Quadrado
para verificar a significância dos dados
test.ID <- function(x)
{
dados=na.omit(x)
med=media.curso(x)
dev.quad=(dados-med)^2
qui=sum(dev.quad)/med
critico.qui<-qchisq(c(0.025,0.975),df=(length(dados)-1))
if(critico.qui[1]<=qui & critico.qui[2]>=qui)
{ cat("\t distribuição aleatória para alfa=0.05\n")}
else{}
if(qui < critico.qui[1])
{ cat("\t","distribuição agregada, p<0.025 \n")}
else{}
if(qui>critico.qui[2])
{ cat("\t","distribuição regular, p>0.975 \n")}
resulta=c(qui,critico.qui)
names(resulta)<-c("qui-quadrado", "critico 0.025", "critico 0.975")
return(resulta)
}
############
=== Exercícios ===
Construa uma função que calcula automaticamente o valor de graus Celsius, sabendo-se a temperatura em Fahrenheit.
C° = 5/9 * (F°(temperatura dada) - 32)
Construa uma função que calcula o somatório dos primeiros //n// números naturais.
Por exemplo se //n=4// a função deve retornar o valor: //1+2+3+4//.
Existe uma série de índices de dispersão baseados em dados de contagem para verificar o padrão espacial de uma espécie.
Alguns deles são:
* **Razão Variância-Média**: ID = variância / média;
* **Coeficiente de Green**: IG = (ID-1)/(n-1);
* **Índice de Morisita**:
{{:03_apostila:indice_morisita.jpg|}}
onde:
n = tamanho da amostra; xi= número de indivíduos na i -ésima unidade amostral
Construa uma função para cada um desses índices, assumindo como argumento os valores de xi.
Aplique aos dados de caixetais, verificando a dispersão da árvores de caixeta em cada caixetal.
==== Definindo Argumentos ====
Todos argumentos de uma função tem seu respectivo nome. Ao evocar a função podemos fazê-lo de duas formas:
* utilizando o **nome** dos argumentos **em qualquer ordem**;
* utilizando a **ordem** dos argumentos, mas **omitindo** os nomes.
> plot( col="red", pch=2, y=egr$ht, x=egr$dap )
> plot( egr$dap, egr$ht )
Para qualquer argumento podemos definir um **valor default** apresentando esse valor junto com argumento na definição da função:
> myplot <- function(..., col="red") { plot(..., col="red") }
> myplot( cax$dap, cax$h )
> myplot( ht ~ dap, data=egr )
O exemplo acima também mostra a função do argumento **". . ."**. Esse argumento representa **qualquer argumento adicional** que desconhecemos, mas que desejamos que seja passado para as funções dentro da função que estamos construindo.
=== Exercícios ===
Faça uma função para construir o gráfico de diversidade de espécies de Whittaker: logaritmo da abundância contra a ordem (descrescente) da abundância das espécies. Construa essa função de forma que qualquer parâmetro gráfico possa ser alterado.
===== Trabalhando com Funções mais Complexas =====
==== Um Aspecto Prático ====
Para saber qual é o editor padrão do R use o comando:
> getOption("editor")
[1] "vi"
>
Para alterar o editor padrâo use o comando:
> options( editor= "gedit" ) # Faz o editor "gedit" ser o editor padrão do R
No caso de editar sua função num editor externo ao R (p.ex., no arquivo '''minhas-funcoes.R'''), você traz o código para dentro do R utilizando o comando **"source"**:
> source( "minhas-funcoes.R" )
É importante que o arquivo editado externamente ('''minhas-funcoes.R''') seja um arquivo **ASCII** sem qualquer símbolo especial.
=== Exercícios ===
Experimente definir um editor com o qual você consiga trabalhar ('''gedit'''?) e refaça os exercícios anteriores salvando todos os códigos num arquivo externo.
Construa funções para computar os seguintes índices de diversidade de espécies:
* Índice de Shannon: ''H = - ∑ (p//i// * ln( p//i// ))''
* Índice de Simpson: ''D = ∑(p//i//^2)''
onde p//i// é a proporção da espécie //i//
Considere que o argumento de sua função será uma matriz com a abundância das espécies sendo as
parcelas amostradas nas colunas. Considere a possibilidade de haver NA nessa matrix e a remoção dele.
==== Realizando "Loops" ====
Em linguagem de programação um **loop** é quando você força um programa a executar uma série de comandos repedidas vêzes.
A estrutura de loop no R é:
for( "variável" in "vetor de valores")
{
comando 1
comando 2
comando 3
. . .
comando n
}
A palavra **for** é o chamado do loop. Dentro dos parênteses se define uma variável seguida da palavra **in** e um vetor de valores que a variável deverá assumir. Dentro das chaves se lista os comandos que devem ser repeditos a cada passo do loop.
Vejamos um exemplo: //Convergência da distribuição t de Student para distribuição Normal Padronizada//:
> #
> # Convergência da distribuição t de Student para distribuição Normal Padronizada
> #
> curve(dnorm(x), from=-4, to=4, col="red", lwd=6)
> for(gl in 1:200)
+ {
+ curve(dt(x, gl), -4, 4, add=TRUE, col="green")
+ }
>
No exemplo acima temos:
* '''gl''' é a variável definida para o loop;
* '''1:200''' é o vetor de valores que a variável assumirá, logo, o loop será repetido 200 vêzes.
=== Exercícios ===
Construa uma função para demonstrar o Teorema Central do Limite.
==== Solução Vetorial x Loop ====
Sendo um **ambiente vetorial**, os //loops// não são uma opção muito eficiente para computação dentro do R. Em geral, o R é mais eficiente se encontrarmos uma **solução vetorial** para problemas de computação que aparentemente exigem um loop. A solução vetorial, entretanto, costuma ser mais exigente em termos do tamanho de memória RAM do computador.
Considere o problema o seguinte problema: temos a localização espacial de plantas num plano cartesiano com coordenadas **(x,y)**. Por exemplo:
> x = runif(100)
> y = runif(100)
> plot(x,y)
O objetivo é obter as **distâncias** entre as plantas duas-a-duas. Primeiro consideremos uma solução através de loop:
inter.edist = function(x, y)
{
n = length(x)
dist <- c()
for(i in 1:(n-1))
{
for(j in (i+1):n)
{
dist <- c(dist, sqrt( (x[i] - x[j])^2 + (y[i] - y[j])^2 ))
}
}
dist
}
Consideremos agora uma solução vetorial:
inter.edist.v = function(x, y)
{
xd <- outer( x, x, "-" )
yd <- outer( y, y, "-" )
z <- sqrt( xd^2 + yd^2 )
dist <- z[ row(z) > col(z) ]
dist
}
Qual dessas soluções é mais eficiente em termos do uso do tempo?
> x = runif(100)
> y = runif(100)
>
> system.time( inter.edist( x, y ) )
[1] 0.140 0.008 0.149 0.000 0.000
>
> system.time( inter.edist.v( x, y ) )
[1] 0.008 0.000 0.009 0.000 0.000
**Não tente rodar o exemplo acima com 1000 ou mais observações**, pois o tempo fica **realmente longo** para versão em loop.
**CONCLUSÃO:** use apenas **pequenos loops** no R!!!
=== Exercícios ===
Construa uma função que gera uma tabela de fitossociologia. Utilize os dados de caixeta ([[dados:dados-caixeta]]) como teste.
==== APÊNDICE: Tabela de Operadores do R ====
Outro aspecto formal importante da linguagem R é a ordem de prioridade de seus operadores. Além das regras de precedência usuais para as operações matemáticas, é essencial conhecer a prioridade dos outros operadores:
=================================================================
OPERADOR DESCRIÇÃO PRIORIDADE
=================================================================
$ seleção de componentes ALTA
[ [[ indexação |
^ potência |
- menos unitário |
: operador de seqüência |
%nome% operadores especiais |
* / multiplicação, divisão |
< > <= >= == != comparação |
! não |
& && | || e, ou |
~ fórmula estatística \/
<<- <- -> = atribuição Baixa
=================================================================