Observe as diferenças nos resultados das funções plot e summary abaixo:
a) plot:
plot(rivers)
plot(iris[, -5],
col=c('red', 'green', 'blue')[unclass(iris$Species)],
pch=19)
plot(Titanic)
b) summary:
summary(rivers)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 135.0 310.0 425.0 591.2 680.0 3710.0
summary(iris)
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## Min. :4.300 Min. :2.000 Min. :1.000 Min. :0.100 setosa :50
## 1st Qu.:5.100 1st Qu.:2.800 1st Qu.:1.600 1st Qu.:0.300 versicolor:50
## Median :5.800 Median :3.000 Median :4.350 Median :1.300 virginica :50
## Mean :5.843 Mean :3.057 Mean :3.758 Mean :1.199
## 3rd Qu.:6.400 3rd Qu.:3.300 3rd Qu.:5.100 3rd Qu.:1.800
## Max. :7.900 Max. :4.400 Max. :6.900 Max. :2.500
summary(Titanic)
## Number of cases in table: 2201
## Number of factors: 4
## Test for independence of all factors:
## Chisq = 1637.4, df = 25, p-value = 0
## Chi-squared approximation may be incorrect
Os resultados são bem diferentes, não?
Se não consegue entender o motivo dessas diferenças, estude o que está abaixo. Isso deverá ajudar a entender alguns dos detalhes “técnicos” mais importantes do R (e de profunda influência em seu uso).
O uso eficiente (acima do básico) do R pressupõe conhecimentos (básicos) de Orientação a Objetos (OO)!
OO é um paradigma da Ciência da Computação (não uma exclusividade do R) para a resolução de problemas computacionais. Na realidade, quase todas as linguagens de programação modernas (o R é uma delas) adotaram OO. Ex: C++, C#, Object Pascal, Python, Ruby, etc.
OO é fundamentado na análise, projeto e programação de sistemas de software baseado na composição e interação entre as diversas unidades de software chamadas de objetos.
Na OO, um problema real complexo qualquer é abstraido (ou seja, simplificado) em suas partes mais elementares e importantes na resolução de um problema. Abstrair, significa uma simplificação da realidade complexa em seus elementos mínimos relevantes.
Surgem então os conceitos de CLASSE, INSTÂNCIA DA CLASSE e OBJETO (além de HERANÇA, ENCAPSULAMENTO e POLIMORFISMO DE MÉTODO).
Na realidade o R é um grande conjunto de objetos. Tudo no R é objeto! Adicionalmente, esses objetos estão organizados numa estrutura hierárquica de classes.
Mas o que são classes? As classes, são os projetos, as definições formais dessas partes simples (objetos) que irão fazer parte da resolução de um problema computacional!
Cada classe define, para cada objeto, minimamente:
Na OO, resolver um problema computacional qualquer significa essencialmente fazer uma modelagem de classes.
Uma classe não existe, ela não é nada mais que uma definição formal de algo que virá a existir. A classe passa a existir quando for instanciada, em outras palavras, quando uma instância da classe for efetivamente criada (o objeto real da abstração).
Uma vez criadas essas instâncias (objetos) elas irão atuar na resolução do problema para o qual foram pensadas (isso é feito na modelagem de classes).
class(rivers)
## [1] "numeric"
class(iris)
## [1] "data.frame"
class(Titanic)
## [1] "table"
A resposta simples para as diferenças encontradas nas funções genéricas plot e summary no início desse tópico é: OS OBJETOS PERTENCEM A CLASSES DISTINTAS. Portanto, possuem PROPRIEDADES E MÉTODOS DISTINTOS.
Vejamos um problema real que consiste em armazenar dados (de diferentes naturezas) de n indivíduos observados em p variáveis em escalas distintas.
A estrutura de dados (objeto) adequada para isso é um data.frame:
n <- 10
p <- 5
set.seed(13)
dad <- data.frame(Y1=floor(runif(n, 1, 10)), # Renda (s. mínimo)
Y2=rnorm(n, 1.7, .2), # Altura
Y3=rnorm(n, 60, .3), # Peso
Y4=rnorm(n, 30, .4), # Idade
Y5=sample(c('M', 'F'), n, rep=T)) # Sexo
rownames(dad) <- paste('id',
1:nrow(dad),
sep='-')
dad
## Y1 Y2 Y3 Y4 Y5
## id-1 7 1.783105 59.94182 30.05974 M
## id-2 3 1.945901 60.41893 29.41627 M
## id-3 4 1.747336 60.03020 29.18918 F
## id-4 1 1.626923 59.96567 29.57722 M
## id-5 9 1.921029 60.21067 29.70874 F
## id-6 1 1.481281 60.07876 29.99672 M
## id-7 6 1.792374 60.55085 30.33912 M
## id-8 7 1.427803 60.10722 29.84660 M
## id-9 8 1.328795 59.68638 29.78940 F
## id-10 1 1.612029 60.18606 29.89071 F
Vamos verificar as propriedades (atributos) do objeto dad:
attributes(dad)
## $names
## [1] "Y1" "Y2" "Y3" "Y4" "Y5"
##
## $class
## [1] "data.frame"
##
## $row.names
## [1] "id-1" "id-2" "id-3" "id-4" "id-5" "id-6" "id-7" "id-8" "id-9" "id-10"
E os métodos associados à instância da classe, ou seja, do objeto dad: onde estão?
No caso do R, diferentemente da maioria das outras linguagens, os objetos de armazenamento de dados (vetores, matrizes, arrays, data.frames, listas, tabelas, etc) não possuem métodos.
O que existem são funções genéricas (print, summary, plot, mean, etc) que provêem métodos para os objetos que armazenam dados:
methods(summary)
## [1] summary.Abacaxi summary.aov summary.aovlist* summary.aspell*
## [5] summary.check_packages_in_dir* summary.connection summary.data.frame summary.Date
## [9] summary.default summary.ecdf* summary.factor summary.Frutas
## [13] summary.glm summary.infl* summary.jcfaria summary.lm
## [17] summary.loess* summary.manova summary.matrix summary.mlm*
## [21] summary.nls* summary.packageStatus* summary.POSIXct summary.POSIXlt
## [25] summary.ppr* summary.prcomp* summary.princomp* summary.proc_time
## [29] summary.sockclientconn* summary.srcfile summary.srcref summary.stepfun
## [33] summary.stl* summary.table summary.teste summary.tukeysmooth*
## [37] summary.warnings
## see '?methods' for accessing help and source code
methods(plot)
## [1] plot.Abacaxi plot.acf* plot.data.frame* plot.decomposed.ts* plot.default plot.dendrogram*
## [7] plot.density* plot.ecdf plot.factor* plot.formula* plot.Frutas plot.function
## [13] plot.hclust* plot.histogram* plot.HoltWinters* plot.isoreg* plot.jcfaria plot.lm*
## [19] plot.medpolish* plot.mlm* plot.ppr* plot.prcomp* plot.princomp* plot.profile.nls*
## [25] plot.raster* plot.spec* plot.stepfun plot.stl* plot.table* plot.ts
## [31] plot.tskernel* plot.TukeyHSD*
## see '?methods' for accessing help and source code
methods(mean)
## [1] mean.Date mean.default mean.difftime mean.POSIXct mean.POSIXlt
## see '?methods' for accessing help and source code
summary(dad)
## Y1 Y2 Y3 Y4 Y5
## Min. :1.0 Min. :1.329 Min. :59.69 Min. :29.19 Length:10
## 1st Qu.:1.5 1st Qu.:1.514 1st Qu.:59.98 1st Qu.:29.61 Class :character
## Median :5.0 Median :1.687 Median :60.09 Median :29.82 Mode :character
## Mean :4.7 Mean :1.667 Mean :60.12 Mean :29.78
## 3rd Qu.:7.0 3rd Qu.:1.790 3rd Qu.:60.20 3rd Qu.:29.97
## Max. :9.0 Max. :1.946 Max. :60.55 Max. :30.34
plot(dad[-5],
col='red',
pch=19)
Cada um desses métodos (genéricos) necessita saber a que classe o objeto passado como argumento para a função genérica pertence para usar um método apropriado (segundo as propriedades do objeto) na intenção de apresentar as informações (numéricas no caso de summary e gráficas no caso de plot) contidas nos objetos que armazenam dados. Esse mecanismo no R é denominado dispatch (despachar, expedir).
Todos os métodos genéricos possuem necessariamente um método padrão (default).
str(summary.default)
## function (object, ..., digits, quantile.type = 7)
str(plot.default)
## function (x, y = NULL, type = "p", xlim = NULL, ylim = NULL, log = "", main = NULL, sub = NULL, xlab = NULL, ylab = NULL, ann = par("ann"),
## axes = TRUE, frame.plot = axes, panel.first = NULL, panel.last = NULL, asp = NA, xgap.axis = NA, ygap.axis = NA, ...)
str(mean.default)
## function (x, trim = 0, na.rm = FALSE, ...)
Todos os métodos do R são genéricos? Não! Existem métodos específicos para determinados tipos de objetos. Os métodos genéricos são apenas para as ações mais corriqueiras, comuns e usuais a vários objetos.
Os métodos default sempre tentam retirar o máximo possível de informação de um objeto, INDEPENDENTE DE SUA CLASSE. NA AUSÊNCIA DE UM MÉTODO ESPECÍFICO PARA DETERMINADO TIPO DE OBJETO (CLASSE) É SEMPRE O MÉTODO SELECIONADO/EXECUTADO.
Exemplificando. Quando digitamos:
summary(dad)
Acontece o seguinte:
class(dad)
## [1] "data.frame"
grep('data.frame',
methods(summary),
value=TRUE)
## [1] "summary.data.frame"
summary(dad)
## Y1 Y2 Y3 Y4 Y5
## Min. :1.0 Min. :1.329 Min. :59.69 Min. :29.19 Length:10
## 1st Qu.:1.5 1st Qu.:1.514 1st Qu.:59.98 1st Qu.:29.61 Class :character
## Median :5.0 Median :1.687 Median :60.09 Median :29.82 Mode :character
## Mean :4.7 Mean :1.667 Mean :60.12 Mean :29.78
## 3rd Qu.:7.0 3rd Qu.:1.790 3rd Qu.:60.20 3rd Qu.:29.97
## Max. :9.0 Max. :1.946 Max. :60.55 Max. :30.34
A classe de um objeto é uma informação que o próprio objeto armazena, como um atributo:
attributes(dad)
## $names
## [1] "Y1" "Y2" "Y3" "Y4" "Y5"
##
## $class
## [1] "data.frame"
##
## $row.names
## [1] "id-1" "id-2" "id-3" "id-4" "id-5" "id-6" "id-7" "id-8" "id-9" "id-10"
Esse atributo pode ser livremente alterado pelo usuário
old.class <- class(dad) # Armazenando a classe original
class(dad) <- 'test' # Atribuindo uma nova classe
attributes(dad)
## $names
## [1] "Y1" "Y2" "Y3" "Y4" "Y5"
##
## $class
## [1] "test"
##
## $row.names
## [1] "id-1" "id-2" "id-3" "id-4" "id-5" "id-6" "id-7" "id-8" "id-9" "id-10"
summary(dad) # Observar a diferença em relação ao 'summary' anterior
## Length Class Mode
## Y1 10 -none- numeric
## Y2 10 -none- numeric
## Y3 10 -none- numeric
## Y4 10 -none- numeric
## Y5 10 -none- character
grep('^summary.test',
methods(summary),
value=TRUE) # Observar que não existe o método 'summary.test'.
## [1] "summary.teste"
Qual método foi aplicado?
summary.default
Que embora tente, não retira todas as informações de interesse do objeto dad, pois não é específico para essa finalidade.
Retornando a classe original do objeto dad:
class(dad) <- old.class
class(dad)
## [1] "data.frame"
summary(dad) # Novamente foi executado o método 'summary.data.frame'
## Y1 Y2 Y3 Y4 Y5
## Min. :1.0 Min. :1.329 Min. :59.69 Min. :29.19 Length:10
## 1st Qu.:1.5 1st Qu.:1.514 1st Qu.:59.98 1st Qu.:29.61 Class :character
## Median :5.0 Median :1.687 Median :60.09 Median :29.82 Mode :character
## Mean :4.7 Mean :1.667 Mean :60.12 Mean :29.78
## 3rd Qu.:7.0 3rd Qu.:1.790 3rd Qu.:60.20 3rd Qu.:29.97
## Max. :9.0 Max. :1.946 Max. :60.55 Max. :30.34
Nesse ponto as coisas (e o poder da OO) devem estar começando a ficar um pouco mais claras para você. Adicionalmente, este mecanismo dispatch (despachar, expedir) do R escolher um método específico de acordo com a classe do objeto pode ser considerado POLIMORFISMO DE CLASSE.
class(dad) <- c('test',
'jcfaria',
'data.frame')
attributes(dad)
## $names
## [1] "Y1" "Y2" "Y3" "Y4" "Y5"
##
## $class
## [1] "test" "jcfaria" "data.frame"
##
## $row.names
## [1] "id-1" "id-2" "id-3" "id-4" "id-5" "id-6" "id-7" "id-8" "id-9" "id-10"
OPA…, o objeto pertence a mais de uma classe? Sim, um objeto no R (segundo a implementação OO S3) pode pertencer a mais de uma classe!
Como assim S3? É que S3 foi a primeira implementação de OO no R, depois (o mundo não para mesmo) os desenvolvedores acharam que poderia ser melhor e criaram (estão criando) a S4.
Mas relaxe, S3 e S4 convivem em harmonia! Estima-se que aproximadamente 80-85% do R está em S3 e 15-20% em S4. Detalhes de diferenciação entre S3 e S4 estão fora do escopo dessa introdução.
Tá bom…, um objeto pode pertencer a mais de uma classe! (Isso se relaciona com HERANÇA, como será visto um pouco mais adiante)
Nesses casos, como o R seleciona o método adequado via mecanismo dispatch?
O retorno da função class, como visto, é um vetor de caracteres. O R SEMPRE VERIFICA ESSE VETOR DA ESQUERDA PARA A DIREITA. SEMPRE! Tente guardar (e não esquecer) isso em alguma parte de sua mente. Ou seja, no sentido do mais novo para o mais velho (HERANÇA). A primeira ocorrência encontrada é a que será executada (selecionada pelo mecanismo dispatch).
No nosso caso, summary(dad):
Se também não tivesse encontrado summary.data.frame o método summary.default seria eleito/selecionado.
Fazendo uma alusão, isso pode ser entendido assim:
summary.jcfaria <- function(object,
clm=1, ...) summary(object[, clm], ...)
methods(summary) # Observe a presença de 'summary.jcfaria'.
## [1] summary.Abacaxi summary.aov summary.aovlist* summary.aspell*
## [5] summary.check_packages_in_dir* summary.connection summary.data.frame summary.Date
## [9] summary.default summary.ecdf* summary.factor summary.Frutas
## [13] summary.glm summary.infl* summary.jcfaria summary.lm
## [17] summary.loess* summary.manova summary.matrix summary.mlm*
## [21] summary.nls* summary.packageStatus* summary.POSIXct summary.POSIXlt
## [25] summary.ppr* summary.prcomp* summary.princomp* summary.proc_time
## [29] summary.sockclientconn* summary.srcfile summary.srcref summary.stepfun
## [33] summary.stl* summary.table summary.teste summary.tukeysmooth*
## [37] summary.warnings
## see '?methods' for accessing help and source code
grep('summary.jcf', # (se acha difícil localizar a função 'grep' pode ajudar)
methods(summary),
value=TRUE)
## [1] "summary.jcfaria"
summary(dad)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 1.0 1.5 5.0 4.7 7.0 9.0
summary(dad,
clm=2)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 1.329 1.514 1.687 1.667 1.790 1.946
summary(dad,
clm=3,
digits=2)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 60 60 60 60 60 61
Observe que na última chamada foi adicionado um argumento digits=2 que não consta na declaração do método summary.jcfaria. Esse é o significado de '…' na função summary.jcfaria. Ou seja, pode-se passar qualquer argumento (no caso digits) para outras funções internas da função (método) summary.jcfaria sem ter que se preocupar em declará-los ou tratá-los.
plot.jcfaria <- function(x, ...) boxplot(x, ...)
methods(plot) # Observe a presença de 'plot.jcfaria'
## [1] plot.Abacaxi plot.acf* plot.data.frame* plot.decomposed.ts* plot.default plot.dendrogram*
## [7] plot.density* plot.ecdf plot.factor* plot.formula* plot.Frutas plot.function
## [13] plot.hclust* plot.histogram* plot.HoltWinters* plot.isoreg* plot.jcfaria plot.lm*
## [19] plot.medpolish* plot.mlm* plot.ppr* plot.prcomp* plot.princomp* plot.profile.nls*
## [25] plot.raster* plot.spec* plot.stepfun plot.stl* plot.table* plot.ts
## [31] plot.tskernel* plot.TukeyHSD*
## see '?methods' for accessing help and source code
grep('plot.jcf',
methods(plot),
value=TRUE)
## [1] "plot.jcfaria"
plot(dad[3])
plot(dad[3],
ylim=c(59.5, 60.6),
xlab='Peso',
col='red',
main='plot.jcfaria')
Bom, as coisas relativas a OO no R devem estar um pouco mais claras. Adicionalmente, foi percebida e importância disso no uso, não?
Vimos que o R tem várias funções genéricas (summary, plot, etc) e que elas realizam tarefas diferentes de acordo com a classe do objeto que é passado como argumento: summary(objeto).
Iremos a seguir criar uma função genérica denominada fruta.
fruta <- function(x, ...)
UseMethod('fruta')
fruta.default <- function(x, ...) print('Não sei qual fruta!')
fruta.Abacaxi <- function(x, ...) print('Abacaxi!')
fruta.Carambola <- function(x, ...) print('Carambola!')
fruta.Pitanga <- function(x, ...) print(paste(x,
'-',
'Pitanga!'))
O objeto '…' você já sabe para que serve, não? Se não, veja acima em: Brincando (um pouco mais) com OO
Podemos criar métodos adicionais para as genéricas já existentes no R:
summary.Frutas <- function(object, ...)
paste('Você gosta de ',
tolower(class(object)),
'?',
sep='', ...)
summary.Abacaxi <- function(object, ...)
paste(class(object),
' deve ser servido em rodelas!',
sep='', ...)
plot.Frutas <- function(x, ...)
{
plot(1,
type='n', ...)
text(x=1,
y=1,
paste(class(x),
'não são para se plotar, \n mas para comer!',
sep=' ', ...),
col='red', ...)
}
plot.Abacaxi <- function(x, ...)
{
plot(1,
type='n', ...)
text(x=1,
y=1,
paste(class(x),
'não é para se plotar, \n mas para comer',
'\n (servido em rodelas)!',
sep=' ', ...),
col='red', ...)
}
a <- 1:3
class(a)
## [1] "integer"
fruta(a) # 'fruta.default'
## [1] "Não sei qual fruta!"
class(a) <- 'Carambola'
a
## [1] 1 2 3
## attr(,"class")
## [1] "Carambola"
fruta(a) # 'a' pertence a classe 'Carambola'!
## [1] "Carambola!"
class(a) <- c('Jaboticaba',
'Maçã',
'Abacaxi') # 'a' irá pertencer a mais de uma classe!
a
## [1] 1 2 3
## attr(,"class")
## [1] "Jaboticaba" "Maçã" "Abacaxi"
fruta(a) # Busca no vetor classe para dispatch -> 'Abacaxi'
## [1] "Abacaxi!"
class(a) <- c('Mamão',
'Pitanga',
'Abacaxi')
a
## [1] 1 2 3
## attr(,"class")
## [1] "Mamão" "Pitanga" "Abacaxi"
fruta(a) # Busca no vetor classe para dispatch -> 'Pitanga'
## [1] "1 - Pitanga!" "2 - Pitanga!" "3 - Pitanga!"
class(a) <- 'Framboesa'
fruta(a) # Irá usar o método fruta.default
## [1] "Não sei qual fruta!"
summary(a) # Usa o método 'summary.default'
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 1.0 1.5 2.0 2.0 2.5 3.0
plot(a,
pch=19,
cex=2)
class(a) <- 'Frutas'
summary(a) # Usa o método 'summary.Frutas'
## [1] "Você gosta de frutas?"
plot(a) # Idem
class(a) <- 'Abacaxi'
summary(a) # Usa o método 'summary.Abacaxi'
## [1] "Abacaxi deve ser servido em rodelas!"
plot(a) # Idem
a <- unclass(a)
attributes(a)
## NULL
summary(a) # Usa o método 'summary.default'
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 1.0 1.5 2.0 2.0 2.5 3.0
plot(a) # Usa o método 'plot.default'
vogais <- letters[c(1, 5, 9, 15, 21)]
b <- paste('a',
vogais[1:4],
sep='')
b
## [1] "aa" "ae" "ai" "ao"
class(b)
## [1] "character"
Note que o atributo dim pode alterar a classe de um objeto (conversão de classe)!
attr(b, 'dim') <- c(2, 2)
b
## [,1] [,2]
## [1,] "aa" "ai"
## [2,] "ae" "ao"
class(b)
## [1] "matrix" "array"
attributes(b)
## $dim
## [1] 2 2
fruta(b)
## [1] "Não sei qual fruta!"
Pode-se acrescentar novos atributos aos objetos!
Isso deve ser feito para acrescentar alguma informação adicional útil ao objeto. Seu principal uso é na contrução de métodos.
attr(b,
'JCFaria') <- 'Professor da UESC/Ilhéus/Bahia'
attributes(b)
## $dim
## [1] 2 2
##
## $JCFaria
## [1] "Professor da UESC/Ilhéus/Bahia"
attributes(b)$JCFaria
## [1] "Professor da UESC/Ilhéus/Bahia"
fruta(b) # Usa o método 'fruta.default'
## [1] "Não sei qual fruta!"
summary(b) # Usa o método 'summary.matrix'
## V1 V2
## Length:2 Length:2
## Class :character Class :character
## Mode :character Mode :character
class(b) <- 'teste'
b
## [,1] [,2]
## [1,] "aa" "ai"
## [2,] "ae" "ao"
## attr(,"JCFaria")
## [1] "Professor da UESC/Ilhéus/Bahia"
## attr(,"class")
## [1] "teste"
rownames(b) <- paste('l',
1:2,
sep='')
colnames(b) <- paste('c',
1:2,
sep='')
Adicionando um novo método a função genérica summary:
summary.teste <- function(object, ...)
{
print(object[,])
cat('\n')
cat(attributes(object)$JCFaria)
cat('\n')
}
summary(b)
## c1 c2
## l1 "aa" "ai"
## l2 "ae" "ao"
##
## Professor da UESC/Ilhéus/Bahia
Encapsulamento é uma opção dos desenvolvedores de um determinado objeto, via de regra funções. Basicamente consiste em ocultar detalhes da implementação do objeto para o usuário final.
Como exemplo peguemos um motor. Não é necessário saber o funcionamento dele, apenas temos que saber que o método ligar da nossa classe motor irá fazer com que o nosso motor entre em funcionamento.
Ou seja, do ponto de vista do criador do objeto motor, não é necessário o usuário saber quais componentes o método irá acessar, modificar ou criar para que o motor entre em funcionamento.
O que o método ligar faz, não diz respeito a quem usa, apenas se usa e sabe-se que irá funcionar.
No conceito de orientação a objetos pode-se proteger aquilo que não se quer que sofra intervenção externa: métodos e atributos.
Os objetos protegidos só podem ser alterados a partir dos métodos em que foram declarados ou dentro do objeto a que eles pertencem.
methods(summary)
## [1] summary.Abacaxi summary.aov summary.aovlist* summary.aspell*
## [5] summary.check_packages_in_dir* summary.connection summary.data.frame summary.Date
## [9] summary.default summary.ecdf* summary.factor summary.Frutas
## [13] summary.glm summary.infl* summary.jcfaria summary.lm
## [17] summary.loess* summary.manova summary.matrix summary.mlm*
## [21] summary.nls* summary.packageStatus* summary.POSIXct summary.POSIXlt
## [25] summary.ppr* summary.prcomp* summary.princomp* summary.proc_time
## [29] summary.sockclientconn* summary.srcfile summary.srcref summary.stepfun
## [33] summary.stl* summary.table summary.teste summary.tukeysmooth*
## [37] summary.warnings
## see '?methods' for accessing help and source code
methods(plot)
## [1] plot.Abacaxi plot.acf* plot.data.frame* plot.decomposed.ts* plot.default plot.dendrogram*
## [7] plot.density* plot.ecdf plot.factor* plot.formula* plot.Frutas plot.function
## [13] plot.hclust* plot.histogram* plot.HoltWinters* plot.isoreg* plot.jcfaria plot.lm*
## [19] plot.medpolish* plot.mlm* plot.ppr* plot.prcomp* plot.princomp* plot.profile.nls*
## [25] plot.raster* plot.spec* plot.stepfun plot.stl* plot.table* plot.ts
## [31] plot.tskernel* plot.TukeyHSD*
## see '?methods' for accessing help and source code
Observe que vários métodos das funções genéricas (summary, plot) aparecem com um asterisco (*
).
Se você digitar o nome de um desses objetos (no caso funções) encapsuladas
(ou mais tecnicamente do ponto de vista do R - não exportadas), por exemplo:
summary.aovlist # Pacote 'stats'
## Error in eval(expr, envir, enclos): objeto 'summary.aovlist' não encontrado
summary.prcomp # Pacote 'stats'
## Error in eval(expr, envir, enclos): objeto 'summary.prcomp' não encontrado
## ou
plot.data.frame # Pacote 'graphics'
## Error in eval(expr, envir, enclos): objeto 'plot.data.frame' não encontrado
plot.prcomp # Pacote 'stats'
## Error in eval(expr, envir, enclos): objeto 'plot.prcomp' não encontrado
não terá acesso diretamente ao código fonte do objeto da classe função, como é comum no R.
Do ponto de vista dos desenvolvedores desses objetos (funções) o usuário não tem motivos para ter acesso ao código, dai optou por os encapsular, não por maldade! Eles fazem o que fazem e ponto final. :(
Particularmente, não vejo muito sentido em encapsular objetos num ambiente tão aberto e democrático quanto o R.
Contudo, não fique triste. Não será necessário pegar o código fonte do R para ter acesso ao código fonte dos objetos encapsulados. Existe uma alternativa: pacote:::objeto-encapsulado
stats:::summary.prcomp # Pacote 'stats'
## function (object, ...)
## {
## chkDots(...)
## vars <- object$sdev^2
## vars <- vars/sum(vars)
## importance <- rbind(`Standard deviation` = object$sdev, `Proportion of Variance` = round(vars,
## 5), `Cumulative Proportion` = round(cumsum(vars), 5))
## k <- ncol(object$rotation)
## colnames(importance) <- c(colnames(object$rotation), rep("",
## length(vars) - k))
## object$importance <- importance
## class(object) <- "summary.prcomp"
## object
## }
## <bytecode: 0x000002181c4b4f60>
## <environment: namespace:stats>
graphics:::plot.data.frame # Pacote 'graphics'
## function (x, ...)
## {
## plot2 <- function(x, xlab = names(x)[1L], ylab = names(x)[2L],
## ...) plot(x[[1L]], x[[2L]], xlab = xlab, ylab = ylab,
## ...)
## if (!is.data.frame(x))
## stop("'plot.data.frame' applied to non data frame")
## if (ncol(x) == 1) {
## x1 <- x[[1L]]
## if (class(x1)[1L] %in% c("integer", "numeric"))
## stripchart(x1, ...)
## else plot(x1, ...)
## }
## else if (ncol(x) == 2) {
## plot2(x, ...)
## }
## else {
## pairs(data.matrix(x), ...)
## }
## }
## <bytecode: 0x00000218199e3b90>
## <environment: namespace:graphics>
stats:::plot.prcomp # Pacote 'stats'
## function (x, main = deparse1(substitute(x)), ...)
## screeplot.default(x, main = main, ...)
## <bytecode: 0x000002181c581718>
## <environment: namespace:stats>
Ou seja, o objeto da classe operador :::
é a chave da capsula!
Considere ainda a existência de algumas funções que facilitam a vida nessas situações de métodos encapsulados ou não exportados:
argsAnywhere(plot.prcomp)
## function (x, main = deparse1(substitute(x)), ...)
## NULL
getAnywhere(summary.prcomp)
## A single object matching 'summary.prcomp' was found
## It was found in the following places
## registered S3 method for summary from namespace stats
## namespace:stats
## with value
##
## function (object, ...)
## {
## chkDots(...)
## vars <- object$sdev^2
## vars <- vars/sum(vars)
## importance <- rbind(`Standard deviation` = object$sdev, `Proportion of Variance` = round(vars,
## 5), `Cumulative Proportion` = round(cumsum(vars), 5))
## k <- ncol(object$rotation)
## colnames(importance) <- c(colnames(object$rotation), rep("",
## length(vars) - k))
## object$importance <- importance
## class(object) <- "summary.prcomp"
## object
## }
## <bytecode: 0x000002181c4b4f60>
## <environment: namespace:stats>
Bom, espero que seu uso do R seja mais eficiente de agora em diante!
Repasse esse script sempre que tiver dúvidas, talvez você não entenda tudo da primeira vez.
Querendo contribuir com sua abrangência e qualidade: