In R
Je souhaite convertir (coercer?) Un objet renvoyé de stats::spectrum
(classe 'spec') en une nouvelle classe S4. La « spécification » de la classe S3 est essentiellement une liste de différentes informations avec les formats mixtes (je l'ai commenté la sortie de l'écran):Conversion de la classe S3 'spec' en nouvelle classe 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
Maintenant, disons que nous définissons un nouveau générateur S4 pour une classe nommée « specS4 » , dans lequel les noms de sous sont les noms dans l'objet « spec »
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)
)
et générer un nouvel objet de celui-ci:
psd4 <- specS4()
validObject(psd4)
# [1] TRUE
Quelle serait la meilleure façon d'attribuer à chaque composante de psd3
à son emplacement correspondant dans psd4
? Une complication est que spectrum
peut renvoyer NULL
pour quelques champs (connus); l'affectation de ces valeurs entraînerait une erreur dans checkSlotAssignment
(pour la représentation donnée).
Une solution douloureuse que j'ai est:
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)
}
qui fonctionne, même si as.specS4.spec
est volontairement incomplète.
psd4c <- as.specS4(psd3)
validObject(psd4c)
# [1] TRUE
Y at-il une meilleure façon d'atteindre ce as.specS4.spec
fait? Cette solution semble précaire.
Parce qu'il était si utile pour moi , voici la description de Hadley du système S4: https://github.com/hadley/devtools/wiki/S4 –
Ma compréhension est que vous auriez besoin de définir «nouveau» et «comme» S4methods. Construire une classe S4 implique plus que de définir une structure et de créer une fonction 'as.name'. Pour le moment, je ne pense pas que vous ayez une méthode S4 'as'. Vous avez besoin de 'setMethod' pour créer une méthode S4. –
Vous avez raison, mais 'as' et' setAs' sont pour les classes S4. Donc cela fonctionne: 'setClass ('spec', prototype = specS4()); SETA ("spec", "specS4", la fonction (de, à) { nouveau (à, fréq = de fréq $, spec = de $ spec, coh = as.numeric (de coh de $), phase de = as.numérique (à partir de $ phase), kernel = as.numérique (à partir de $ kernel), snames = en tant que caractère (à partir de $ snames)) }); as (psd3, 'specS4') 'mais comme vous pouvez le remarquer, j'ai encore besoin d'assigner manuellement des slots. À moins que je ne manque quelque chose, cela ne me sauve vraiment rien. –