2014-09-15 1 views
5

두 클래스 클래스, SentenceWord을 정의하고자한다고 가정 해 보겠습니다. 각 단어 객체는 문자열과 음성의 일부 (pos)를 가지고 있습니다. 각 문장에는 몇 개의 단어가 들어 있으며 데이터를위한 추가 슬롯이 있습니다.R에 동일한 유형의 여러 객체를 슬롯에 채우게하려면 어떻게해야합니까?

Word 클래스는 정의하기 쉽습니다.

wordSlots <- list(word = "character", pos = "character") 
wordProto <- list(word = "", pos = "") 
setClass("Word", slots = wordSlots, prototype = wordProto)  
Word <- function(word, pos) new("Word", word=word, pos=pos) 

이제 좀 Word의 일부 숫자 데이터를 포함 할 수있는 Sentence 클래스를 만들고 싶어.

나는 그렇게으로 Sentence 클래스를 정의하는 경우 :

sentenceSlots <- list(words = "Word", stats = "numeric") 
sentenceProto <- list(words = Word(), stats = 0) 
setClass("Sentence", slots = sentenceSlots, prototype = sentenceProto) 

그런 다음 문장이 하나의 단어를 포함 할 수 있습니다. 나는 분명히 많은 슬롯들, 즉 각 단어에 대해 하나씩 정의 할 수 있지만 길이가 제한 될 것입니다. 나는이 같은 Sentence 클래스 정의하는 경우

그러나 : 내가 원하는대로

sentenceSlots <- list(words = "list", stats = "numeric") 
sentenceProto <- list(words = list(Word()), stats = 0) 
setClass("Sentence", slots = sentenceSlots, prototype = sentenceProto) 

이 많은 단어를 포함 할 수 있지만, 슬롯을 words 클래스 Word 아닌 개체를 포함 할 수 있습니다.

이 방법이 있습니까? 이것은 같은 유형의 객체 벡터를 가질 수있는 C++ 객체와 유사합니다.

+0

나는 이전에 제안한 (삭제 한) 것이 좋다고 생각합니다. 문장에서 단어 목록이 아닌 단어 벡터로 바꿉니다. R에서 많은 객체 지향 프로그래밍을 수행하지는 않지만 작동해야한다고 생각합니다. – DMT

+0

그것은 그것을 벡터가 아니라 목록으로 해석합니다. 'words = "vector"와'x <- new ("Sentence")','x @ words <- c (Word(), Word(), 3)'는 에러를 발생시키지 않고'x @ words' 목록. –

+0

이해할 권리? 단어 유형이 두 가지이고 숫자 유형이 하나이기 때문에? 설정이 이루어지기 전에 강요 될 것입니다. 3은 문장 개체의 통계에 해당합니까? – DMT

답변

6

는 첫 번째 단계는 하나가 IRanges에서 공식화 된 단어의 목록을 가지고 니콜라의 제안 @ 오히려 '워드'가 아닌 '단어'

## constructor, accessors, subset (also need [[, [<-, [[<- methods) 
.Words <- setClass("Words", 
    representation(words="character", parts="character")) 
words <- function(x) [email protected] 
parts <- function(x) [email protected] 
setMethod("length", "Words", function(x) length(words(x))) 
setMethod("[", c("Words", "ANY", "missing"), function(x, i, j, ...) { 
    initialize(x, words=words(x)[i], parts=parts(x)[i], ...) 
}) 

## validity 
setValidity("Words", function(object) { 
    if (length(words(object)) == length(parts(object))) 
     NULL 
    else 
     "'words()' and 'parts()' are not the same length" 
}) 

생각하는 것입니다 패키지 (실제로, 'devel'/ 3의 S4Vectors.0 Branch of Bioconductor), 'SimpleList'는 목록의 모든 요소가 같은 클래스를 갖도록 요구하는 '순진한'방식을 취하는 반면 'CompressedList'는 비슷한 동작을하지만 실제로는 벡터와 같은 객체로 구현됩니다(), [[메소드]는 그룹으로 끝나거나 너비에 따라 '분할'됩니다.

library(IRanges) 
.Sentences = setClass("Sentences", 
    contains="CompressedList",  
    prototype=c(elementType="Words")) 

하나는 좀 더 사용자 친화적 인 생성자를 작성합니다,하지만 기본 기능은 작동 할 수 있기 때문에 몇 가지 일반적인 작업이 빠른 것을

> s3[[1]] 
An object of class "Words" 
Slot "word": 
[1] "a" "b" 

Slot "part": 
[1] "A" "B" 

> s3[[2]] 
An object of class "Words" 
Slot "word": 
character(0) 

Slot "part": 
character(0) 

> s3[[3]] 
An object of class "Words" 
Slot "word": 
[1] "c" "d" "e" 

Slot "part": 
[1] "C" "D" "E" 

주의로 이어지는

## 0 Sentences 
.Sentences() 
## 1 sentence of 0 words 
.Sentences(unlistData=.Words(), partitioning=PartitioningByEnd(0)) 
## 3 sentences of 2, 0, and 3 words 
s3 <- .Sentences(unlistData=.Words(words=letters[1:5], parts=LETTERS[1:5]), 
    partitioning=PartitioningByEnd(c(2, 2, 5))) 

입니다 예를 들어, 모든 '단어'를 대문자로 강요하는 것과 같이, S4 인스턴스를 생성하거나 파괴하지 않고 '비공개'요소에 적용

setMethod(toupper, "Words", function(x) { [email protected] <- toupper([email protected]); x }) 
setMethod(toupper, "Sentences", function(x) relist(toupper(unlist(x)), x)) 

unlist/relist가 실제로 '단어'의 단일 인스턴스 생성 및 슬롯 액세스에 있기 때문에 이것은 많은 문장 모음에 대해 '빠름'입니다. Scalable Genomics with R and Bioconductor은이 전략과 다른 전략에 대해 간략하게 설명합니다.

답장에서 @ R는 'R은 OO 프로그래밍 스타일에 완벽하게 적합하지 않습니다'라고 말하지만 R이 S4와 다른 점은 R의 S4 객체 지향 스타일이 C++ 및 Java와 다르다는 것을 깨닫는 것이 더 유용 할 것입니다. 특히 S4와 함께 작업 할 때 벡터의 관점에서 생각하는 것을 계속하는 것은 정말로 가치가 있습니다. 단어가 아닌 사람들, 사람보다는 사람 ...

+0

내가해야 할 모든 일을 다했고, 예상했던 것보다 더 쉽게 할 수 있었다. 매우 명확하고 유익한. 내 문제를 해결하는 데 많은 아이디어를 제공합니다! –

4

이 클래스의 문제에 대한 해결 방법을 제안합니다. R은 OO 프로그래밍 스타일에 완벽하게 적합하지 않으며 모든 솔루션은 Java 또는 C++와 같은 다른 언어의 견고 함을 거의 보여주지 않습니다. 그러나 words 슬롯을 목록으로 사용하여 Sentence 클래스를 선언 할 수 있습니다. 그런 다음과 같은 생성자를 정의

Sentence<-function(words,stats) { 
    #check for the components' class of words argument 
    if (!is.list(words) || !all(sapply(words,function(x) class(x)=="Word"))) stop("Not valid words argument") 
    #create the object 
     new("Sentence", words=words, stats=stats) 
    } 

같은 생성자의 예를 Polygons 클래스의 sp 패키지에서 찾을 수 있습니다. 당신은 그 기능의 몸을 볼 수 있습니다. 내가 마지막 단계가 필요하다고 생각하지 않는다

"@<-.Sentence"<-function(sentence,...) invisible(sentence) 

: 해당 사용자 설정을 잘못 words 슬롯을 피하려는 경우 @<- 운영자 등과 같은

, 당신은 다시 정의 할 수 있습니다. 무엇을 하든지 사용자는 언제나 물건을 망칠 수 있습니다. 예를 들어, 그는 생성자를 우회하여 new 함수를 직접 호출 할 수 있습니다. 또는 Word 클래스를 임의의 객체로 설정 한 다음 Sentence에 전달할 수 있습니다. 앞서 말했듯이, R은 이러한 프로그래밍 스타일에 완벽하지 않으므로 어떤 종류의 비 최적 솔루션을 채택해야합니다. R은 벡터에서 잘 작동 기억