Effiziente Möglichkeit, eine Klasse mit mehreren, optional leeren Slots in S4 von R zu definieren?

StackOverflow https://stackoverflow.com/questions/8334796

  •  26-10-2019
  •  | 
  •  

Frage

Ich erstelle ein Paket, um Daten zu verarbeiten, die mit bis zu 4 verschiedenen Typen eintreffen. Jeder dieser Typen ist eine legitime Klasse in Form einer Matrix, Daten.Frame oder Baum. Abhängig von der Art und Weise, wie die Daten verarbeitet werden, und andere experimentelle Faktoren, sind einige dieser Datenkomponenten möglicherweise fehlen Daten.

Ansatz 1:

Ich habe mit einer inkrementellen Vererbungsstruktur experimentiert, die wie ein verschachtelter Baum aussieht, wobei jede Kombination von Datentypen eine eigene Klasse ausdrücklich definiert hat. Dies scheint in Zukunft schwer für zusätzliche Datentypen zu erweitern, und ist auch für neue Entwickler eine Herausforderung, alle Klassennamen zu lernen, wie gut organisiert diese Namen jedoch sein könnten.

Ansatz 2:

Ein zweiter Ansatz besteht darin, eine einzelne "Master-Klasse" zu erstellen, die einen Slot für alle 4 Datentypen enthält. Um zuzulassen, dass die Slots für die Fälle fehlender Daten null sind, erscheint es erforderlich, zuerst eine virtuelle Klassenvereinigung zwischen dem zu definieren NULL Klasse und die neue Datentypklasse und verwenden Sie dann die virtuelle Klassengewerkschaft als erwartete Klasse für den relevanten Steckplatz in der Master-Klasse. Hier ist ein Beispiel (unter der Annahme, dass jede Datentypklasse bereits definiert ist):

################################################################################
# Use setClassUnion to define the unholy NULL-data union as a virtual class.
################################################################################    
setClassUnion("dataClass1OrNULL", c("dataClass1", "NULL"))
setClassUnion("dataClass2OrNULL", c("dataClass2", "NULL"))
setClassUnion("dataClass3OrNULL", c("dataClass3", "NULL"))
setClassUnion("dataClass4OrNULL", c("dataClass4", "NULL"))
################################################################################
# Now define the master class with all 4 slots, and 
# also the possibility of empty (NULL) slots and an explicity prototype for
# slots to be set to NULL if they are not provided at instantiation.
################################################################################
setClass(Class="theMasterClass", 
    representation=representation(
        slot1="dataClass1OrNULL",
        slot2="dataClass2OrNULL",
        slot3="dataClass3OrNULL",
        slot4="dataClass4OrNULL"),
    prototype=prototype(slot1=NULL, slot2=NULL, slot3=NULL, slot4=NULL)
)
################################################################################

Die Frage könnte also umformuliert werden als:

Gibt es effizientere und/oder flexiblere Alternativen zu diesen Ansätzen?

Dieses Beispiel wird von einer Antwort auf a geändert Fragen zum Festlegen des Standardwerts von Slot in NULL. Diese Frage unterscheidet sich darin, dass ich daran interessiert bin, die besten Optionen in R zu kennen, um Klassen mit Slots zu erstellen, die bei Bedarf leer werden können, obwohl in allen anderen nicht leeren Fällen eine bestimmte komplexe Klasse erforderlich ist.

War es hilfreich?

Lösung

Meiner Meinung nach...

Ansatz 2

Es wird den Zweck besiegt, ein formales Klassensystem zu übernehmen und dann eine Klasse zu erstellen, die schlecht definierte Slots ('a' oder null) enthält. Zumindest würde ich versuchen, DataClass1 zu machen, eine null-ähnliche Standardeinstellung zu haben. Als einfaches Beispiel ist die Standardeinstellung hier ein null-langen-numerischer Vektor.

setClass("DataClass1", representation=representation(x="numeric"))
DataClass1 <- function(x=numeric(), ...) {
    new("DataClass1", x=x, ...)
}

Dann

setClass("MasterClass1", representation=representation(dataClass1="DataClass1"))
MasterClass1 <- function(dataClass1=DataClass1(), ...) {
    new("MasterClass1", dataClass1=dataClass1, ...)
}

Ein Vorteil davon ist, dass Methoden nicht testen müssen, ob die Instanz im Steckplatz NULL oder 'DataClass1' ist.

setMethod(length, "DataClass1", function(x) length(x@x))
setMethod(length, "MasterClass1", function(x) length(x@dataClass1))

> length(MasterClass1())
[1] 0
> length(MasterClass1(DataClass1(1:5)))
[1] 5

Als Antwort auf Ihren Kommentar über die Warnung von Benutzern, wenn sie auf "leere" Slots zugreifen, und wenn Sie sich daran erinnern, dass Benutzer normalerweise Funktionen tun möchten, um etwas zu tun, anstatt ihnen zu sagen, dass sie etwas falsch machen, würde ich wahrscheinlich das leere Objekt zurückgeben DataClass1() was genau den Zustand des Objekts widerspiegelt. Vielleicht ein show Die Methode würde einen Überblick geben, der den Status des Steckplatzes verstärkt - DataClass1: Keine. Dies scheint besonders angemessen zu sein, wenn MasterClass1 eine Möglichkeit für die Koordinierung mehrerer verschiedener Analysen darstellt, von denen der Benutzer nur einige durchführen kann.

Eine Einschränkung dieses Ansatzes (oder Ihres Ansatzes 2) besteht DataClass1 Instanzen mit ungleich Null Länge und gezwungen sind, einen manuellen Versand zu machen (z. B. mit if oder switch). Dies mag für den Entwickler eine Einschränkung erscheinen, gilt aber auch für den Benutzer-der Benutzer erhält keinen Eindruck davon, welche Vorgänge für Instanzen von MasterClass1, die Datenversorgungsinstanzen mit ungleich Null Länge haben, einzigartig geeignet sind.

Ansatz 1

Wenn Sie sagen, dass die Namen der Klassen in der Hierarchie für Ihren Benutzer verwirrend sein werden, scheint dies vielleicht auf ein grundlegenderes Problem hinzuweisen - Sie bemühen sich zu sehr, eine umfassende Darstellung von Datentypen zu treffen. Ein Benutzer wird niemals in der Lage sein, die Klasse von ClasswithmatrixDataframeandTree zu verfolgen, da er nicht die Art und Weise darstellt, wie er die Daten anzeigt. Dies ist vielleicht eine Gelegenheit, Ihre Ambitionen zu skalieren, nur die bekanntesten Teile des Gebiets, den Sie untersuchen, wirklich in Angriff zu nehmen. Oder vielleicht eine Gelegenheit, die Daten zu überdenken, wie der Benutzer an die gesammelten Daten vorstellen und mit der Interaktion der Daten (was der Benutzer) von der Implementierung (wie Sie ausgewählt haben, um die Daten in darzustellen, zu verwenden Klassen) von Klassensystemen zur Verfügung gestellt, um effektiver zu verkapulieren, was der Benutzer wahrscheinlich tun wird.

Wenn Sie die Namensschreiber und die Anzahl der Klassen beiseite stellen, wenn Sie in Zukunft "schwer für zusätzliche Datentypen ausdehnen" sagen, frage ich mich, ob einige der Nuancen von S4 -Klassen Sie aufstolpten? Die kurze Lösung besteht darin, Ihr eigenes Schreiben zu vermeiden initialize Methoden und verlassen sich auf die Konstrukteure, um die knifflige Arbeit zu erledigen, nach wie vor

setClass("A", representation(x="numeric"))
setClass("B", representation(y="numeric"), contains="A")

A <- function(x = numeric(), ...) new("A", x=x, ...)
B <- function(a = A(), y = numeric(), ...) new("B", a, y=y, ...)

und dann

> B(A(1:5), 10)
An object of class "B"
Slot "y":
[1] 10

Slot "x":
[1] 1 2 3 4 5
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top