2013-01-02 94 views
1

R我想將從stats::spectrum(類'spec')返回的對象轉換(脅迫?)爲新的S4類。在S3級「規範」本質上是一種混合格式的各種信息的列表(我評論的屏幕輸出):將'spec'S3類轉換爲新的S4類

psd3 <- spectrum(rnorm(1e3), plot=FALSE) 
summary(psd3) 
#   Length Class Mode  
# freq  500 -none- numeric 
# spec  500 -none- numeric 
# coh   0 -none- NULL  
# phase  0 -none- NULL  
# kernel  0 -none- NULL  
# df   1 -none- numeric 
# bandwidth 1 -none- numeric 
# n.used  1 -none- numeric 
# orig.n  1 -none- numeric 
# series  1 -none- character 
# snames  0 -none- NULL  
# method  1 -none- character 
# taper  1 -none- numeric 
# pad   1 -none- numeric 
# detrend  1 -none- logical 
# demean  1 -none- logical 

class(unclass(psd3)) 
# [1] "list" 

is.object(psd3) & !isS4(psd3) 
# [1] TRUE 

現在,讓我們說,我們定義一個新的,S4生成一個名爲「specS4」級,其中所述狹槽的名字是在「規範」對象的名稱

specS4 <- setClass("specS4", 
    representation = representation(freq="numeric", spec="numeric", coh="numeric", phase="numeric", kernel="numeric", df="numeric", bandwidth="numeric", n.used="numeric", orig.n="numeric", series="character", snames="character", method="character", taper="numeric", pad="numeric", detrend="logical", demean="logical"), 
    prototype = prototype(coh=numeric(0), phase=numeric(0), kernel=numeric(0), df=Inf, snames="", detrend=FALSE, demean=FALSE) 
) 

,並生成從它一個新的對象:

psd4 <- specS4() 

validObject(psd4) 
# [1] TRUE 

什麼會是分配的各成分的最佳方式到其對應的插槽psd4併發症是spectrum可能會返回NULL幾個(已知)字段;分配這些值將在checkSlotAssignment(給出的表示)中引發錯誤。

一個很痛苦的解決方案,我擁有的是:

nonull.spec <- function(psd){ 
    stopifnot(inherits(psd, 'spec', FALSE)) 
    # as.numeric(NULL) --> numeric(0) 
    # spec.pgram/.ar both may return NULL for these: 
    psd$coh <- as.numeric(psd$coh) 
    psd$phase <- as.numeric(psd$phase) 
    psd$kernel <- as.numeric(psd$kernel) 
    psd$snames <- as.character(psd$snames) 
    return(psd) 
} 

as.specS4 <- function(psd) UseMethod("as.specS4") 
as.specS4.spec <- function(psd){ 
    stopifnot(inherits(psd, 'spec', FALSE)) 
    ## deal with possible NULLs 
    psd <- nonull.spec(psd) 
    ## generate specS4 class 
    S4spec <- specS4() 
    ## (re)assign from 'spec' list 
    [email protected] <- psd$freq 
    [email protected] <- psd$spec 
    [email protected] <- psd$coh 
    [email protected] <- psd$phase 
    [email protected] <- psd$kernel 
    [email protected] <- psd$snames 
    # [more to assign, obviously] 
    # 
    # [run a validity check...] 
    # 
    return(S4spec) 
} 

其中一期工程,即使as.specS4.spec是故意不完整的。

psd4c <- as.specS4(psd3) 

validObject(psd4c) 
# [1] TRUE 

有沒有更好的方式來實現什麼as.specS4.spec呢?這個解決方案似乎不穩定。

+0

因爲它是如此的妄作,這裏是哈德利對S4系統的描述:https://github.com/hadley/devtools/wiki/S4 –

+0

我的理解是,你需要定義'新'和'如'S4方法。構建一個S4類不僅僅是定義一個結構並創建一個'as.name'函數。目前我認爲你沒有S4'as'方法。你需要'setMethod'來創建一個S4方法。 –

+0

你是對的,但'as'和'setAs'是S4類的。所以這個工作:'setClass('spec',prototype = specS4()); setAs(「spec」,「specS4」,函數(from,to){ new(to, freq = from $ freq, spec = from $ spec, coh = as.numeric(from $ coh), 階段= as.numeric(from $ phase), kernel = as.numeric(from $ kernel), snames = as.character(from $ snames)) });作爲(psd3,'specS4')',但你可能會注意到我仍然需要手動分配插槽。除非我錯過了一些東西,這並不能真正爲我節省任何努力。 –

回答

1

我剛剛意識到這實際上有多簡單。 Doh!

比賽slotNames在「規範」的對象與names的「specS4」對象,然後用slot分配(假設的問題代碼已運行):

as.specS4.spec <- function(psd){ 
    stopifnot(inherits(psd, 'spec', FALSE)) 
    psd <- nonull.spec(psd) 
    S4spec <- specS4() 
    spec_slots <- slotNames(S4spec) 
    spec_slots <- spec_slots[match(names(psd), spec_slots)] 
    for (what in spec_slots){ 
    slot(S4spec, what) <- as.vector(unlist(psd[what])) 
    } 
    return(S4spec) 
} 

psd4c2 <- as.specS4(psd3) 

validObject(psd4c2) 
# [1] TRUE 
> all.equal([email protected], [email protected], psd3$freq) 
# [1] TRUE