Здесь полиморфизм организован по контейнерному принципу. Аналогом могут служить generic'и. Например, для объектов print и plot, как видно, основной и единственной является функция UseMethod("имя объекта").

полиморфизм S3 классов

Она получает доступ ко всем методам контейнера print и plot. Сами контейнеры содержат методы, которые определяются в разных объектах.

полиморфизм S3 классов
Звездочка возле названия обозначает, что метод находится не в ядре ({base}), а в другом пространстве. Здесь под ядром будем понимать Global Enviroment. Для выявления соответствующего Package'а, который надо подключить. Лучше всего воспользоваться методом getAnywere("метод"):
> getAnywhere(plot.lm)
A single object matching ‘plot.lm’ was found
It was found in the following places
registered S3 method for plot from namespace stats
namespace:stats

Трудно говорить об едином стиле, но использование контейнеров типа print, plot, summary и etc. Может облегчить жизнь программера, оформляя эти функции просто:
<имя контейнера>.имя_S3_класса.
print.aeTest <- function(ae){
cat("\n Skewness=",A,"\tKurtosis=",E,"\n")
cat("\n D(A)=",D.A,"\tD(E)=",D.E,"\n")
if(abs(A)<=3*sqrt(D.A) && abs(E)<=5*sqrt(D.E))
cat("\nYour sample is normal \n")
else
cat("\n This is non-parametric sample?\n")
}

print.aeTest <- function(ae){
cat("\n Skewness=",A,"\tKurtosis=",E,"\n")
cat("\n D(A)=",D.A,"\tD(E)=",D.E,"\n")
if(abs(A)<=3*sqrt(D.A) && abs(E)<=5*sqrt(D.E))
cat("\nYour sample is normal \n")
else
cat("\n This is non-parametric sample?\n")
}

Тогда вывод объекта на печать осуществляется просто:
> obj.ae <- aeTest(x,y)
> obj.ae

Skewness= -0.1131924 Kurtosis= 2.766801

D(A)= 0.09211553 D(E)= 0.33397

Your sample is normal

В вывод добавлена проверка на нормальность по асимметрии и эксцессу. Plot позволяет получить картинку распределения (красный пунктир - выборка, синяя сплошная - нормальное распределение с параметрами выборки).

>plot(obj.al)

Если сравнить вывод методов контейнера plot до и после загрузки класса, то видно, что появился plot.al, наш метод.

полиморфизм S3 классов

полиморфизм S3 классов

В следующей заметке будет рассмотрена небезопасность S3 классов, и неоходимость их замены S4 классами.

Название статьи
 

Анализ данных

1

Статистический анализ для бизнесаСтатистический анализ для бизнеса

2

Язык программирования R. Функция заменыФункция замены в R

3

Заметки об объектно-ориентированном программировании в R

S3-классы в RЗаметка 1. S3-классы в R

Заметка 2. Полиморфизм в S3 классах

 

Функция замены - это выражение вида:

f(x)<-y,

Оно эквивалентно:
x <- "f" <-(x, value = y),
при этом необходимо определить ранее f <- (). При определении следует помнить, что она всегда будет иметь именнованный параметр value&nbsp=.

Функция в R - это объект, состоящий из аргументов, тела и окружения (environment), т.е. формально она является замыканием (closure). Для работы с объектами окружения можно использовать функцию "<<-":

f <- function(u){
u<<- 2 * u
}

Если выполнить команду:

> u
Error object "u" not found
> f(5)
> u
[1] 10

Вообще-то, <<- используется для записи в переменную верхнего уровня, но, на самом деле, он запускает процесс восходящего вызова по иерархии окружения ("матрешка") и ищет первый уровень, на котором этот объект обнаружен:

f <- function(){
int <- function(){ x<<- x+1}
x <- 3
int()
return(x)
}

> f()
[1] 4
> x
Error object "u" not found

Кстати, в R много возможностей сделать одно и тоже действие несколькими способами:


x <<- x+1
эквивалентно:
assign("x", x+1, pos = .GlobalEnv)

классы в RS3-классы -самые старые в R, однако подавляющее большинство встроенных объектов написаны именно в этой логике. Попробуем рассмотреть на примере построение типичного класса S3. Возьмем произвольную выборку и выполним некоторые базовые компоненты.

При этом держим в уме три основные свойства ООП: инкапсуляцию, наследование, полиморфизм.

Итак, инкапсуляция.

Создать класс не сложно. Достаточно выполнить:


x<--c(1,2,3)
ff<--list(x=x, me=meam(x))
class(ff)<-"ff"

И (о,чудо!)мы можем проверить в консоли результат следующим набором команд:

> ff <- list(x = x,mean=mean(x))
> class(ff) <- "ff"
> ff$x
[1] 1 2 3
> ff$mean
[1] 2

зВроде все хорошо! И объект существует и даже считает среднее, но попробуем дальше поэксперементировать. Изменим вектор x (добавим еще чисел).

> ff$x <- c(ff$x,5,6,7)
> class(ff)
[1] "ff"
> ff$x
[1] 1 2 3 5 6 7
> ff$mean
[1] 2
> mean(ff$x)
[1] 4

Эффект, прямо скажем не радует! Попробуем просто присвоить:

> ff <- c(ff$x,5,6,7,8)
> class(ff)
[1] "numeric"

Все поломалось. Жаль, посмотрим, что же делать.

Приведем наш класс в привычную форму:#
# аналог ctor'а для класса fm
#
fm_create <- function(x){
fn <- list()# обязательно!!!!
fn$x <- x
fn$mean <<- mean(x)
fn$median <<- median(x)
fn$sd <<- sd(x)
class(fm_create) <- "fm"# обязательно!!!!
return(fm_create)# обязательно!!!!
}

Стало лучше, но ненамного. Перегрузим для начала операторы чтения и записи.

А, вообще-то, работает.

> n <- 60
> x <- (1:n)/n
> y <- rnorm(n,mean = mean(x),sd=sd(x))
> ff.obj <- fm_create(y)
> ff.obj$mean
[1] 0.5086667
> ff.obj$median
[1] 0.4787275
>
> ff.obj$median
[1] 0.4787275
>
> ff.obj$sd
[1] 0.2961263
>

Далее, все будет!