LoginSignup
8

More than 5 years have passed since last update.

R言語S3クラスの実装

Posted at

概要

他の言語と比べるとRの(S3)クラス定義は特殊です(※個人の感想)。
これはR言語は統計処理言語なのが意識されて作られていることに由来しているからでしょう。

ただ、慣れるとオブジェクト指向っぽい書き方ができる気がする(完全にできるとは言ってはいない
今回のクラス定義はS3クラスについて雑にまとめました(他にはS4,R5,R6等々いろいろある)

参考出典

基本的に下記のリンクを参考にしてます

注意

忘備録的に書いているので、分かりにくいです。また、ソフトウェア工学しっかりとは学んでいないので、内容は保証しません。

クラス定義

RのS3クラス定義は簡単

x <- 1
class(x) <- "foo"
class(x)

これで、変数xfooクラスとして定義される。正直、なんじゃこりゃ。

総称関数

なんとなくの理解で総称関数を語る(=合っているとは保証しない)。詳しくは下記参照。

R言語で分析すると何気なく使っているprint関数。
文字列だろうが、data.frameクラスだろうが、lm関数の結果(lmクラス)だろうが、関係なくprintしてくれる。このように入力されるデータのクラスに関わらず、なんらかの出力を出してくれる便利な関数が「総称関数」です。

print("Hi")
print(iris)
print( lm(Sepal.Length~Petal.Length,iris) )

よって、上記は下記と一緒の出力結果を得る

print.default("Hi")
print.data.frame(iris)
# print.lm ( lm(Sepal.Length~Petal.Length,iris) )

つまり、Rの処理としては以下のことが行われている
スライド1.png

新しい総称関数を作りたい場合は、以下のようにUseMethod関数を使う。

UseMethod("GetFirst")

クラスの継承

RのS3クラス継承は少し分かりにくい。

class(x) <- c("hoo","foo")

これで、xはhoofooクラスを持つ。上の場合だとfooクラスが親で、hooクラスは子クラスとなる。つまり、要素番号が一番若いクラスが子クラスになる。実際に以下のスクリプトで確認できる。

 x <- list(x = 1,
           y = "hi")
 class(x)<-c("foo","hoo")
 greeting <- function(x){
   UseMethod("greeting",x)  
 }
 greeting.foo <- function(x){
   print(x$y)
 }
 greeting.hoo <- function(x){
   print(x$x)
 }
greeting(x)
> [1] "hi"

上ではgreeting関数を総称関数にして、変数xfooクラスとhooクラスを持たせた。それぞれのクラスについて関数を定義した結果、fooクラスの結果が返されている。

 x <- list(x = 1,
           y = "hi")
 class(x)<-c("foo","hoo")
 greeting <- function(x){
   UseMethod("greeting",x)  
 }
 greeting.hoo <- function(x){
   print(x$x)
 }
 greeting(x)
> [1] 1

二つ目はfooクラスにgreeting関数について何も定義していないと、親であるhooクラスの結果を返している。

クラス実装

もう少しオブジェクト指向っぽい実装を行いたい場合は以下のように実装する。

NorthAmerican <- function(eatsBreakfast=TRUE,myFavorite="cereal")
{

        me <- list(
                hasBreakfast = eatsBreakfast,
                favoriteBreakfast = myFavorite
       )

        ## Set the name for the class
        class(me) <- append(class(me),"NorthAmerican")
        return(me)
}

listの部分をフィールドとして定義。
class(me) <- append(class(me),"NorthAmerican")で継承関係を定義する。
以下のように、インスタンス生成っぽいアトモスフィア(雰囲気)が出てくる。

taro <- NorthAmerican(eatsBreakfast=TRUE,myFavorite="rice")

クラスにメソッドを追加するときは関数を総称関数にして、自ら定義したクラスの関数を記述する。

setHasBreakfast <- function(elObjeto, newValue)
        {
                print("Calling the base setHasBreakfast function")
                UseMethod("setHasBreakfast",elObjeto)
                print("Note this is not executed!")
        }

setHasBreakfast.default <- function(elObjeto, newValue)
        {
                print("You screwed up. I do not know how to handle this object.")
                return(elObjeto)
        }


setHasBreakfast.NorthAmerican <- function(elObjeto, newValue)
        {
                print("In setHasBreakfast.NorthAmerican and setting the value")
                elObjeto$hasBreakfast <- newValue
                return(elObjeto)
        }

参考にしたサイトでは上記の実装になっていたが、以下のような書き方でも可能

setHasBreakfast <- function(object , newValue)
        {
                print("Calling the base setHasBreakfast function")
                UseMethod("setHasBreakfast")
                print("Note this is not executed!")
        }

magrittrパッケージを使うと、メソッドの書き方が他の言語と見慣れた感じになる。

taro <- NorthAmerican(eatsBreakfast=TRUE,myFavorite="rice")

setHasBreakfast <- function(object, newValue)
{
  print("Calling the base setHasBreakfast function")
  UseMethod("setHasBreakfast")
  print("Note this is not executed!")
}

setHasBreakfast.default <- function(object,newValue)
{
  print("You screwed up. I do not know how to handle this object.")
  return(object)
}


setHasBreakfast.NorthAmerican <- function(object,newValue)
{
  print("In setHasBreakfast.NorthAmerican and setting the value")
  object$hasBreakfast <- newValue
  return(object)
}

require(magrittr)

taro %>% setHasBreakfast( newValue = FALSE)

詳しい説明は参考にしたサイトに譲るが、下記のようにメソッドを実装する方法もある。

bubba <- NorthAmericain(myFavorite="oatmeal")
bubba$getFavoriteBreakfast()
[1]"oatmeal"

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8