R OOP

2016/06/27

R에서 객체 지향 프로그래밍: S3 기초

R OOP

객체지향 S3, S4 관련 : http://adv-r.had.co.nz/S3.html

Object oriented, 객체 지향 → 프로그램 단순화, 코드 재사용 용이.

클래스(Class) ← 객체(멤버 변수), 메소드method(멤버 함수) - 클래스는 상속을 통해 계층 구조를 가짐.

객체지향 S3

method(함수명) : 함수명의 method함수를 조회. getS3method() : S3에서의 method 함수의 내용 조회..

객체지향 S4

Keywords

R S3 OOP 기초

클래스

S3에서는 클래스라고 해봐야 별 것 없다. 단지 class라는 속성(attribute)의 값에 따라 클래스가 결정될 뿐이다. 딱히 instance/class 구별이 큰 의미도 없다. 객체를 만드는 방법은 간단하다. class() 함수를 이용하여 class 속성을 지정할 수 있다. 다음처럼 사각형과 원을 만들어 보자.

a <- c(xleft=10, ybottom=7, xright=15, ytop=9)
class(a) <- "rectangle"

b <- list(center=c(10, 5), radius=5)
class(b) <- "circle"

어떤 객체가 어떤 내용을 담고 있는지 들여다 보는 데에 여러가지 함수들이 사용될 수 있다. 위처럼 사각형 a와 원 b를 만들었다면 class() 함수로 클래스를 확인해 볼 수 있다.

class(a) [1] “rectangle” class(b) [1] “circle” 객체에 대해 attributes(), str(), structure() 명령을 사용해서 어떤 내용이 출력되는지 살펴보라. 그러니까 str(a) Class ‘rectangle’ Named num [1:4] 10 7 15 9 ..- attr(*, “names”)= chr [1:4] “xleft” “ybottom” “xright” “ytop” 와 같은 식으로 명령을 내려 보라. attr() 함수를 이용하면 원하는 속성을 지정해서 살펴볼 수 있다. attr(a, “class”) [1] “rectangle” 아까 사용한 class() 함수는 단지 “class”라는 이름의 속성값에 접근하게 해주는 함수일 뿐이다. 메소드 넓이를 계산해 주는 메소드 area()를 만들어 보자. 사각형과 원은 넓이를 계산하는 방법이 다르다. 그러니까, 클래스마다 다른 메소드가 실행되어야 한다. 그런데 다음처럼 실행되게 하려고 한다.

area(a) [1] 10 area(b) [1] 78.53982 이것을 S3에서 구현하는 방법을 method dispatch라고 하는데 여기서 area() 함수를 generic function이라고 한다. 우선 필요하는 것은 generic function을 정의하는 것이다. 방법은 간단하다. 다음처럼 한다. area <- function(x, …) { UseMethod(“area”, x) } 이것으로 area()라는 generic function이 만들어졌다. 이것은 인자로 주어진 객체의 class를 체크해서 적절한 메소드를 dispatch해 준다. 각 클래스를 위한 method는 generic function의 이름 다음에 점을 찍고 클래스 이름을 붙여서 만든다. 말로 하는 것보다 한번 보는 것이 쉽다. area.rectangle <- function(x, …) { as.numeric((x[“xright”] - x[“xleft”]) * (x[“ytop”] - x[“ybottom”])) }

area.circle <- function(x, …) { pi * x$radius^2 } 이것으로 끝이다. 이제 generic function area()가 rectangle 객체를 받으면 area.rectangle() 메소드가 실행되고 circle 객체를 받으면 area.circle() 메소드가 실행된다. 한 generic function에 어떤 메소드들이 있는지 알고 싶다면 methods() 함수를 이용한다.

methods(“area”) [1] area.circle area.rectangle 한번 methods(plot) 명령을 내려보라. 여러가지 메소드들을 볼 수 있을 것이다. 만약 우리가 MyClass라는 새로운 클래스를 만들었고 plot()로 그것에 알맞은 그래프가 그려지게 하고 싶다면 plot.MyClass()라는 이름의 함수를 새로 정의하기만 하면 된다. plot()가 이미 generic function이므로 알아서 해준다. S3 generic function에서 주어진 클래스에 맞는 method를 얻는 것은 getS3method()로 가능하다. 즉 다음처럼 작동한다.

getS3method(“area”, “circle”) function(x, …) { pi * x$radius^2 } 생성자 S3에서는 생성자(constructor)를 형식적으로 지원하지 않는다. 프로그램 짜는 사람이 알아서 해야한다. 어쨌든 언제나 생성자는 만드는 습관을 들이는 것이 좋다. 생성자는 데이터를 받아서 대개는 리스트 형태로 만들고 class 속성값을 붙여주는 형태가 된다. 예를 들면:

new_circle <- function(x, y, r) {
  circle <- list(center=c(x,y), radius=r)
  class(circle) <- "circle"
  circle
}

2016.04.22

S3, S4 object -> 오브젝트 S3, S4 Reference Class -> 포인터

How to use S4 object in R?

Stackoverflow | Kyun

Object와 함수가 분리되어 있다. setGeneric으로 함수 이름만 쓴다 setMethod 실제 book book1은 인스턴스이다

readLines writeLines | 소켓과 핸들은 필요없다.

===

R Object-oriented Programming Chapter 3. Saving Primitive input / output :

Software for data analysis - John M Chambers Amazon Kindle Book

C S R

Functional programming | Object-oriented programming

OOP caller , callee

c=a+b # call by value | 일반적인 프로그래밍

메모리 할당을 받아야 한다. scope.

S3, S4에 대한 것은 별로 없다. RC는 mutable

객체 지향 언어는 프로그래밍을 함에 있어서 데이터와 그 데이터를 처리할 메소드를 한데 묶어 객체를 만들고 객체들을 조립하는 것을 목표로 한 언어들을 말한다. 객체 지향 언어의 특징은 추상화, 캡슐화, 상속성, 다형성이 있다. 추상화는 외부 인터페이스만 제공하고 객체 내부를 숨겨서 어떻게 일을 하는지 몰라도 결과를 내보낸다[12]. 캡슐화는 객체 내부에 필요한 데이터등을 묶어서 한번에 관리 할 수 있게 해준다[13]. 상속은 모객체를 상속받아 추가 기능을 더 붙이거나 약간의 수정을 가한 객체를 만들 수 있다[14]. 다형성[15]은 메소드 이름은 같더라도 타입에 따라 다른 메소드가 실행될 수 있다는 것이다.[16]

Object = Class (object)|개념 + (instance) object|구체화

Encapsulation | Property and Method | object는 encap하고 일부만 노출됨

Inheritance

Polymorphism

Factor | Level = 색깔 | 노랑

break 하면 도수분포표를 나눌 수 있다. summary

===

attribute | name of vector 순서가 있다.

Picking a system - Advanced R

Three OO systems is a lot for one language, but for most R programming, S3 suffices. In R you usually create fairly simple objects and methods for pre-existing generic functions like print(), summary(), and plot(). S3 is well suited to this task, and the majority of OO code that I have written in R is S3. S3 is a little quirky, but it gets the job done with a minimum of code. If you are creating more complicated systems of interrelated objects, S4 may be more appropriate. A good example is the Matrix package by Douglas Bates and Martin Maechler. It is designed to efficiently store and compute with many different types of sparse matrices. As of version 1.1.3, it defines 102 classes and 20 generic functions. The package is well written and well commented, and the accompanying vignette (vignette(“Intro2Matrix”, package = “Matrix”)) gives a good overview of the structure of the package. S4 is also used extensively by Bioconductor packages, which need to model complicated interrelationships between biological objects. Bioconductor provides many good resources for learning S4. If you’ve mastered S3, S4 is relatively easy to pick up; the ideas are all the same, it is just more formal, more strict, and more verbose. If you’ve programmed in a mainstream OO language, RC will seem very natural. But because they can introduce side effects through mutable state, they are harder to understand. For example, when you usually call f(a, b) in R you can assume that a and b will not be modified. But if a and b are RC objects, they might be modified in the place. Generally, when using RC objects you want to minimise side effects as much as possible, and use them only where mutable states are absolutely required. The majority of functions should still be “functional”, and free of side effects. This makes code easier to reason about and easier for other R programmers to understand.

S4 기초

S4 클래스로 프로그래밍을 하기 위해서 기본적으로 다음 함수들을 시용해야 한다.

setClass() new() setGeneric() setMethod() 클래스 새로운 클래스는 다음처럼 setClass() 함수를 이용하여 정의한다.

setClass(“circle”, representation(x=“numeric”, y=“numeric”, r=“numeric”)) 이제 new()를 이용하여 인스턴스를 만들 수 있다. 객체의 속성을 S4에서늘 슬롯(slot)이라고 한다. 슬롯은 object@slot 형태로 접근할 수 있다. > a <- new(“circle”, x=5, y=10, r=4) > str(a) Formal class ‘circle’ [package “.GlobalEnv”] with 3 slots ..@ x: num 5 ..@ y: num 10 ..@ r: num 4 > a@x [1] 5 > a@y [1] 10 > a@r [1] 4 한 객체가 특정 클래스에 속하는지 체크할 때는 is()를 이용한다. > is(a, “circle”) [1] TRUE 메소드 메소드는 setMethod()를 이용하여 정의한다. 기존의 정의된 generic function이 없다면 우선 generic function부터 만들어야 하는데 이때에는 setGeneric()을 이용한다. 예를 들면 다음처럼 한다.

setGeneric(“area”, function(object) standardGeneric(“area”))

setMethod(“area”, “circle”, function(object) pi * object@r^2 ) 이제 메소드를 사용해 보면 > area(a) [1] 50.26548 > area(new(“circle”, x=3, y=4, r=3)) [1] 28.27433 한 generic function에 어떤 method들이 있는지 알고 싶을 때는 showMethods()를 이용한다.

showMethods(“area”) Function: area (package .GlobalEnv) object=“circle” 참조

참고