Wie verwende ich Listen in R richtig?


320

Kurzer Hintergrund: Viele (die meisten?) Zeitgenössische Programmiersprachen, die weit verbreitet sind, haben mindestens eine Handvoll ADTs (abstrakte Datentypen) gemeinsam, insbesondere

  • Zeichenfolge (eine Folge von Zeichen)

  • Liste (eine geordnete Sammlung von Werten) und

  • Kartenbasierter Typ (ein ungeordnetes Array, das Schlüssel Werten zuordnet)

In der Programmiersprache R sind die ersten beiden als characterund implementiertvector .

Als ich anfing, R zu lernen, waren fast von Anfang an zwei Dinge offensichtlich: listist der wichtigste Datentyp in R (weil es die übergeordnete Klasse für das R istdata.frame ), und zweitens konnte ich zumindest nicht verstehen, wie sie funktionierten nicht gut genug, um sie in meinem Code richtig zu verwenden.

Zum einen schien mir der listDatentyp von R eine einfache Implementierung der Map ADT zu sein ( dictionaryin Python, NSMutableDictionaryin Objective C, hashin Perl und Ruby,object literal in Javascript usw.).

Sie erstellen sie beispielsweise wie ein Python-Wörterbuch, indem Sie Schlüssel-Wert-Paare an einen Konstruktor übergeben (was in Python dictnicht der Fall ist list):

x = list("ev1"=10, "ev2"=15, "rv"="Group 1")

Und Sie greifen auf die Elemente einer R-Liste zu, genau wie auf die eines Python-Wörterbuchs, z x['ev1']. Ebenso können Sie nur die 'Schlüssel' oder nur die 'Werte' abrufen , indem Sie:

names(x)    # fetch just the 'keys' of an R list
# [1] "ev1" "ev2" "rv"

unlist(x)   # fetch just the 'values' of an R list
#   ev1       ev2        rv 
#  "10"      "15" "Group 1" 

x = list("a"=6, "b"=9, "c"=3)  

sum(unlist(x))
# [1] 18

Aber R lists sind auch anders als andere ADTs vom Kartentyp (unter den Sprachen, die ich sowieso gelernt habe). Ich vermute, dass dies eine Folge der ursprünglichen Spezifikation für S ist, dh die Absicht, eine Daten- / Statistik-DSL [domänenspezifische Sprache] von Grund auf zu entwerfen.

Drei signifikante Unterschiede zwischen listRs und Mapping-Typen in anderen weit verbreiteten Sprachen (z. B. Python, Perl, JavaScript):

Erstens sind lists in R eine geordnete Sammlung, genau wie Vektoren, obwohl die Werte verschlüsselt sind (dh die Schlüssel können beliebige Hash-Werte sein, nicht nur sequentielle Ganzzahlen). Fast immer ist der Mapping-Datentyp in anderen Sprachen ungeordnet .

zweite , listkann s von Funktionen zurückgegeben werden , obwohl Sie nie in einem übergeben , listwenn Sie die Funktion aufgerufen, und auch wenn die Funktion , die zurückgegeben die listkeinen (expliziten) enthalten listKonstruktor (Natürlich können Sie mit diesem in der Praxis beschäftigen , indem Umschließen des zurückgegebenen Ergebnisses in einen Aufruf von unlist):

x = strsplit(LETTERS[1:10], "")     # passing in an object of type 'character'

class(x)                            # returns 'list', not a vector of length 2
# [1] list

Eine dritte Besonderheit von listRs: Es scheint nicht, dass sie Mitglieder eines anderen ADT sein können, und wenn Sie dies versuchen, wird der primäre Container zu a gezwungen list. Z.B,

x = c(0.5, 0.8, 0.23, list(0.5, 0.2, 0.9), recursive=TRUE)

class(x)
# [1] list

Ich habe hier nicht die Absicht, die Sprache oder deren Dokumentation zu kritisieren. Ebenso schlage ich nicht vor, dass irgendetwas mit dem nicht stimmtlist Datenstruktur oder ihrem Verhalten . Ich muss nur korrigieren, wie sie funktionieren, damit ich sie in meinem Code richtig verwenden kann.

Hier sind die Dinge, die ich besser verstehen möchte:

  • Welche Regeln bestimmen, wann ein Funktionsaufruf ein list(z. B. den strsplitoben angegebenen Ausdruck) zurückgibt?

  • Wenn ich a list(z. B. list(10,20,30,40)) nicht explizit Namen zuweise, sind die Standardnamen nur sequentielle Ganzzahlen, die mit 1 beginnen? (Ich nehme an, aber ich bin weit davon entfernt, sicher zu sein, dass die Antwort ja lautet, sonst könnten wir diese Art von nicht listzu einem Vektor mit einem Aufruf von zwingen unlist.)

  • Warum geben diese beiden unterschiedlichen Operatoren []und [[]]das gleiche Ergebnis zurück?

    x = list(1, 2, 3, 4)

    beide Ausdrücke geben "1" zurück:

    x[1]

    x[[1]]

  • Warum geben diese beiden Ausdrücke nicht dasselbe Ergebnis zurück?

    x = list(1, 2, 3, 4)

    x2 = list(1:4)

Bitte verweisen Sie mich nicht auf die R-Dokumentation ( ?list, R-intro) - ich habe sie sorgfältig gelesen und sie hilft mir nicht bei der Beantwortung der oben genannten Fragen.

(Zuletzt habe ich kürzlich von einem R-Paket (verfügbar auf CRAN) erfahren, hashdas herkömmliches Verhalten vom Kartentyp über eine S4-Klasse implementiert . Ich kann dieses Paket auf jeden Fall empfehlen.)


3
Mit geben x = list(1, 2, 3, 4)beide NICHT das gleiche Ergebnis zurück:, x[1]und x[[1]]. Der erste gibt eine Liste zurück und der zweite gibt einen numerischen Vektor zurück. Wenn ich unten scrolle, scheint mir Dirk der einzige Befragte zu sein, der diese Frage richtig beantwortet hat.
IRTFM

2
Ich habe nicht bemerkt, dass jemand Ihre Liste der Möglichkeiten erweitert hat, die listin R nicht wie ein Hash sind. Ich habe noch eine, die ich für bemerkenswert halte. listin R können zwei Mitglieder mit demselben Referenznamen sein. Betrachten Sie dies obj <- c(list(a=1),list(a=2))als gültig und geben Sie eine Liste mit zwei benannten Werten von 'a' zurück. In diesem Fall gibt ein Aufruf von obj["a"]nur das erste übereinstimmende Listenelement zurück. Sie können ein ähnliches (möglicherweise identisches) Verhalten wie ein Hash mit nur einem Element pro referenziertem Namen in Umgebungen in R x <- new.env(); x[["a"]] <- 1; x[["a"]] <- 2; x[["a"]]
erzielen,

1
Ich habe diesen Beitrag mit den Antworten in den letzten 6 Monaten dreimal erneut gelesen und jedes Mal mehr Erleuchtung gefunden. Tolle Frage und ein paar tolle Antworten. Vielen Dank.
Rich Lysakowski PhD

Antworten:


150

Nur um den letzten Teil Ihrer Frage anzusprechen, da dies wirklich den Unterschied zwischen a listund vectorin R aufzeigt:

Warum geben diese beiden Ausdrücke nicht dasselbe Ergebnis zurück?

x = Liste (1, 2, 3, 4); x2 = Liste (1: 4)

Eine Liste kann als jedes Element eine andere Klasse enthalten. Sie können also eine Liste erstellen, in der das erste Element ein Zeichenvektor, das zweite ein Datenrahmen usw. ist. In diesem Fall haben Sie zwei verschiedene Listen erstellt. xhat vier Vektoren mit jeweils der Länge 1. x2hat 1 Vektor der Länge 4:

> length(x[[1]])
[1] 1
> length(x2[[1]])
[1] 4

Das sind also völlig andere Listen.

R-Listen ähneln stark einer Hash-Map- Datenstruktur, da jeder Indexwert jedem Objekt zugeordnet werden kann. Hier ist ein einfaches Beispiel für eine Liste, die 3 verschiedene Klassen enthält (einschließlich einer Funktion):

> complicated.list <- list("a"=1:4, "b"=1:3, "c"=matrix(1:4, nrow=2), "d"=search)
> lapply(complicated.list, class)
$a
[1] "integer"
$b
[1] "integer"
$c
[1] "matrix"
$d
[1] "function"

Da das letzte Element die Suchfunktion ist, kann ich es so nennen:

> complicated.list[["d"]]()
[1] ".GlobalEnv" ...

Als abschließender Kommentar dazu: Es sollte beachtet werden, dass a data.framewirklich eine Liste ist (aus der data.frameDokumentation):

Ein Datenrahmen ist eine Liste von Variablen mit der gleichen Anzahl von Zeilen mit eindeutigen Zeilennamen für die Klasse "data.frame".

Aus diesem Grund können Spalten in a data.frameunterschiedliche Datentypen haben, Spalten in einer Matrix jedoch nicht. Als Beispiel versuche ich hier eine Matrix mit Zahlen und Zeichen zu erstellen:

> a <- 1:4
> class(a)
[1] "integer"
> b <- c("a","b","c","d")
> d <- cbind(a, b)
> d
 a   b  
[1,] "1" "a"
[2,] "2" "b"
[3,] "3" "c"
[4,] "4" "d"
> class(d[,1])
[1] "character"

Beachten Sie, dass ich den Datentyp in der ersten Spalte nicht in numerisch ändern kann, da die zweite Spalte Zeichen enthält:

> d[,1] <- as.numeric(d[,1])
> class(d[,1])
[1] "character"

4
Das hilft, danke. (Übrigens ist Ihr Beispiel für eine 'komplizierte Liste', wie Sie vielleicht bereits wissen, die Standardmethode, um die 'switch'-Anweisung in C ++, Java usw. in Sprachen zu replizieren, die keine haben; wahrscheinlich eine gute Möglichkeit um dies in R zu tun, wenn ich muss). +1
Doug

8
Richtig, obwohl es switchin R eine nützliche Funktion gibt, die für diesen Zweck verwendet werden kann (siehe help(switch)).
Shane

63

Lassen Sie mich Ihre Fragen der Reihe nach beantworten und einige Beispiele nennen:

1 ) Eine Liste wird zurückgegeben, wenn die return-Anweisung eine hinzufügt. Erwägen

 R> retList <- function() return(list(1,2,3,4)); class(retList())
 [1] "list"
 R> notList <- function() return(c(1,2,3,4)); class(notList())
 [1] "numeric"
 R> 

2 ) Namen werden einfach nicht gesetzt:

R> retList <- function() return(list(1,2,3,4)); names(retList())
NULL
R> 

3 ) Sie geben nicht dasselbe zurück. Ihr Beispiel gibt

R> x <- list(1,2,3,4)
R> x[1]
[[1]]
[1] 1
R> x[[1]]
[1] 1

Dabei wird x[1]das erste Element von x- zurückgegeben, das dasselbe ist wie x. Jeder Skalar ist ein Vektor der Länge eins. Auf der anderen Seite wird x[[1]]das erste Element der Liste zurückgegeben.

4 ) Schließlich unterscheiden sich die beiden zwischen der Erstellung einer Liste mit vier Skalaren und einer Liste mit einem einzelnen Element (das zufällig ein Vektor aus vier Elementen ist).


1
Sehr hilfreich, danke. (Zu Punkt 1 in Ihrer Antwort - ich stimme zu, aber ich dachte an integrierte Funktionen wie "strsplit" und nicht an vom Benutzer erstellte Funktionen). Auf jeden Fall +1 von mir.
Doug

2
@doug Über Punkt 1 Ich denke, die einzige Möglichkeit besteht darin, die Hilfe auf bestimmte Funktionen im Abschnitt zu überprüfen Value. Wie in ?strsplit: "Eine Liste mit der gleichen Länge wie x". Sie sollten jedoch berücksichtigen, dass es eine Funktion geben kann, die abhängig von den Argumenten unterschiedliche Werte zurückgibt (z. B. sapply kann Liste oder Vektor zurückgeben).
Marek

34

Nur um einen Teil Ihrer Fragen zu beantworten:

Dieser Artikel zur Indizierung befasst sich mit der Frage nach dem Unterschied zwischen []und [[]].

Kurz gesagt, [[]] wählt ein einzelnes Element aus einer Liste aus und []gibt eine Liste der ausgewählten Elemente zurück. In Ihrem Beispiel ist x = list(1, 2, 3, 4)'Element 1 eine einzelne Ganzzahl, x[[1]]gibt jedoch eine einzelne 1 und x[1]eine Liste mit nur einem Wert zurück.

> x = list(1, 2, 3, 4)
> x[1]
[[1]]
[1] 1

> x[[1]]
[1] 1

Ist übrigens A = array( 11:16, c(2,3) ); A[5]15 in der flachen Anordnung ?!
Denis

13

Ein Grund, warum Listen so funktionieren (geordnet), besteht darin, die Notwendigkeit eines geordneten Containers zu adressieren, der an jedem Knoten einen beliebigen Typ enthalten kann, was Vektoren nicht tun. Listen werden in R für eine Vielzahl von Zwecken wiederverwendet, einschließlich der Bildung der Basis von adata.frame , einer Liste von Vektoren beliebigen Typs (aber gleicher Länge).

Warum geben diese beiden Ausdrücke nicht dasselbe Ergebnis zurück?

x = list(1, 2, 3, 4); x2 = list(1:4)

Wenn Sie das gleiche Ergebnis erzielen möchten, versuchen Sie Folgendes, um die Antwort von @ Shane zu ergänzen:

x3 = as.list(1:4)

Was den Vektor 1:4in eine Liste zwingt .


11

Nur um noch einen Punkt hinzuzufügen:

R hat eine Datenstruktur , in den Python zu dict gleichwertig dem hashPaket . Sie können darüber in diesem Blog-Beitrag aus der Open Data Group lesen . Hier ist ein einfaches Beispiel:

> library(hash)
> h <- hash( keys=c('foo','bar','baz'), values=1:3 )
> h[c('foo','bar')]
<hash> containing 2 key-value pairs.
  bar : 2
  foo : 1

In Bezug auf die Benutzerfreundlichkeit ist die hashKlasse einer Liste sehr ähnlich. Bei großen Datenmengen ist die Leistung jedoch besser.


1
Mir ist das Hash-Paket bekannt - es wird in meiner ursprünglichen Frage als geeigneter Proxy für den traditionellen Hash-Typ erwähnt.
Doug

Beachten Sie auch, dass die Verwendung von hash :: hash im Vergleich zu Hash-Umgebungen ( rpubs.com/rpierce/hashBenchmarks) von fragwürdigem Nutzen ist .
Russellpierce

9

Du sagst:

Zum anderen können Listen von Funktionen zurückgegeben werden, obwohl Sie beim Aufrufen der Funktion noch nie eine Liste übergeben haben und die Funktion keinen Listenkonstruktor enthält, z.

x = strsplit(LETTERS[1:10], "") # passing in an object of type 'character'
class(x)
# => 'list'

Und ich denke, Sie schlagen vor, dass dies ein Problem ist (?). Ich bin hier, um dir zu sagen, warum es kein Problem ist :-). Ihr Beispiel ist ein bisschen einfach: Wenn Sie den String-Split durchführen, haben Sie eine Liste mit Elementen, die 1 Element lang sind, sodass Sie wissen, dass dies x[[1]]dasselbe ist wie unlist(x)[1]. Was aber, wenn das Ergebnis der strsplitzurückgegebenen Ergebnisse in jedem Bin unterschiedlich lang ist? Das einfache Zurückgeben eines Vektors (im Vergleich zu einer Liste) reicht überhaupt nicht aus.

Zum Beispiel:

stuff <- c("You, me, and dupree",  "You me, and dupree",
           "He ran away, but not very far, and not very fast")
x <- strsplit(stuff, ",")
xx <- unlist(strsplit(stuff, ","))

Im ersten Fall ( x: der eine Liste zurückgibt) können Sie feststellen, was der 2. "Teil" der 3. Zeichenfolge war, z x[[3]][2]. Wie können Sie dasselbe tun, xxwenn die Ergebnisse "entwirrt" ( unlist-ed) sind?


5
x = list(1, 2, 3, 4)
x2 = list(1:4)
all.equal(x,x2)

ist nicht dasselbe, weil 1: 4 dasselbe ist wie c (1,2,3,4). Wenn Sie möchten, dass sie gleich sind, dann:

x = list(c(1,2,3,4))
x2 = list(1:4)
all.equal(x,x2)

4

Dies ist eine sehr alte Frage, aber ich denke, dass eine neue Antwort einen Mehrwert bringen könnte, da meiner Meinung nach niemand einige der Bedenken im OP direkt angesprochen hat.

Ungeachtet dessen, was die akzeptierten Antworten nahelegen, sind listObjekte in R keine Hash-Maps. Wenn Sie eine Parallele zu Python machen möchten, listsind Sie eher wie Python lists (oder tupletatsächlich s).

Es ist besser zu beschreiben, wie die meisten R-Objekte intern gespeichert werden (der C-Typ eines R-Objekts ist SEXP). Sie bestehen im Wesentlichen aus drei Teilen:

  • einen Header, der den R-Typ des Objekts, die Länge und einige andere Metadaten deklariert;
  • der Datenteil, der ein Standard-C-Heap-zugewiesenes Array ist (zusammenhängender Speicherblock);
  • die Attribute, bei denen es sich um eine benannte verknüpfte Liste von Zeigern auf andere R-Objekte handelt (oder NULLwenn das Objekt keine Attribute hat).

Aus interner Sicht gibt es zum Beispiel kaum einen Unterschied zwischen a listund einem numericVektor. Die Werte, die sie speichern, sind einfach unterschiedlich. Lassen Sie uns zwei Objekte in das zuvor beschriebene Paradigma einteilen:

x <- runif(10)
y <- list(runif(10), runif(3))

Für x:

  • Der Header sagt, dass der Typ numeric( REALSXPauf der C-Seite) ist, die Länge 10 ist und andere Sachen.
  • Der Datenteil ist ein Array mit 10 doubleWerten.
  • Die Attribute sind NULL, da das Objekt keine hat.

Für y:

  • Der Header sagt, dass der Typ list( VECSXPauf der C-Seite) ist, die Länge 2 ist und andere Sachen.
  • Der Datenteil wird ein Array , das 2 Zeiger auf zwei sexp Typen sein, auf den Wert der Anpeilung erhalten runif(10)und runif(3)jeweils.
  • Die Attribute sind NULLwie für x.

Der einzige Unterschied zwischen einem numericVektor und a listbesteht also darin, dass der numericDatenteil aus doubleWerten besteht, während listder Datenteil ein Array von Zeigern auf andere R-Objekte ist.

Was passiert mit Namen? Namen sind nur einige der Attribute, die Sie einem Objekt zuweisen können. Sehen wir uns das folgende Objekt an:

z <- list(a=1:3, b=LETTERS)
  • Der Header sagt, dass der Typ list( VECSXPauf der C-Seite) ist, die Länge 2 ist und andere Sachen.
  • Der Datenteil wird ein Array , das 2 Zeiger auf zwei sexp Typen sein, auf den Wert der Anpeilung erhalten 1:3und LETTERSjeweils.
  • Die Attribute sind jetzt vorhanden und sind eine namesKomponente, die ein characterR-Objekt mit Wert ist c("a","b").

Auf der R-Ebene können Sie mit der attributesFunktion die Attribute eines Objekts abrufen .

Der für eine Hash-Map in R typische Schlüsselwert ist nur eine Illusion. Wenn du sagst:

z[["a"]]

das ist, was passiert:

  • die [[Teilmengenfunktion wird aufgerufen;
  • Das Argument der Funktion ( "a") ist vom Typ character, daher wird die Methode angewiesen, diesen Wert anhand des namesAttributs (falls vorhanden) des Objekts zu suchen z.
  • Wenn das namesAttribut nicht vorhanden ist, NULLwird es zurückgegeben.
  • falls vorhanden, wird der "a"Wert darin gesucht. Wenn "a"es sich nicht um einen Namen des Objekts handelt, NULLwird dieser zurückgegeben.
  • falls vorhanden, wird die Position bestimmt (1 im Beispiel). Das erste Element der Liste wird also zurückgegeben, dh das Äquivalent von z[[1]].

Die Schlüsselwertsuche ist eher indirekt und immer positionell. Auch nützlich zu beachten:

  • In Hash-Maps muss ein Schlüssel nur begrenzt sein, dass er hashbar sein muss . namesin R müssen Strings ( characterVektoren) sein;
  • In Hash-Maps können Sie nicht zwei identische Schlüssel haben. In R können Sie nameseinem Objekt mit wiederholten Werten zuweisen . Zum Beispiel:

    names(y) <- c("same", "same")

    ist in R vollkommen gültig. Wenn Sie versuchen, wird y[["same"]]der erste Wert abgerufen. Sie sollten an dieser Stelle wissen, warum.

Zusammenfassend lässt sich sagen, dass die Möglichkeit, einem Objekt beliebige Attribute zuzuweisen, von außen etwas anderes erscheinen lässt. Aber listRs sind in keiner Weise Hash-Maps.


2

In Bezug auf Vektoren und das Hash / Array-Konzept aus anderen Sprachen:

  1. Vektoren sind die Atome von R. ZB rpois(1e4,5)(5 Zufallszahlen), numeric(55)(Länge-55-Nullvektor über Doppel) und character(12)(12 leere Zeichenfolgen) sind alle "grundlegend".

  2. Entweder Listen oder Vektoren können haben names.

    > n = numeric(10)
    > n
     [1] 0 0 0 0 0 0 0 0 0 0
    > names(n)
    NULL
    > names(n) = LETTERS[1:10]
    > n
    A B C D E F G H I J 
    0 0 0 0 0 0 0 0 0 0
  3. Vektoren erfordern, dass alles vom gleichen Datentyp ist. Schau dir das an:

    > i = integer(5)
    > v = c(n,i)
    > v
    A B C D E F G H I J           
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
    > class(v)
    [1] "numeric"
    > i = complex(5)
    > v = c(n,i)
    > class(v)
    [1] "complex"
    > v
       A    B    C    D    E    F    G    H    I    J                          
    0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i
  4. Listen können unterschiedliche Datentypen enthalten, wie aus anderen Antworten und der Frage des OP selbst hervorgeht.

Ich habe Sprachen (Ruby, Javascript) gesehen, in denen "Arrays" variable Datentypen enthalten können, aber in C ++ müssen "Arrays" beispielsweise alle denselben Datentyp haben. Ich glaube, das ist eine Sache mit Geschwindigkeit / Effizienz: Wenn Sie eine haben numeric(1e6), kennen Sie deren Größe und die Position jedes Elements a priori ; Wenn das Ding "Flying Purple People Eaters"in einem unbekannten Slice enthalten sein könnte , müssen Sie tatsächlich Dinge analysieren, um grundlegende Fakten darüber zu erfahren.

Bestimmte Standard-R-Operationen sind auch dann sinnvoller, wenn der Typ garantiert ist. Zum Beispiel cumsum(1:9)macht dies Sinn, während cumsum(list(1,2,3,4,5,'a',6,7,8,9))dies nicht der Fall ist, ohne dass der Typ garantiert doppelt ist.


Zu Ihrer zweiten Frage:

Listen können von Funktionen zurückgegeben werden, obwohl Sie beim Aufrufen der Funktion noch nie eine Liste übergeben haben

Funktionen geben andere Datentypen zurück, als sie ständig eingegeben werden. plotGibt einen Plot zurück, obwohl kein Plot als Eingabe verwendet wird. Arggibt a zurück numeric, obwohl es a akzeptiert hat complex. Usw.

(Und was strsplit: der Quellcode ist hier .)


2

Obwohl dies eine ziemlich alte Frage ist, muss ich sagen, dass sie genau das Wissen berührt, das mir bei meinen ersten Schritten in R gefehlt hat - dh wie man Daten in meiner Hand als Objekt in R ausdrückt oder wie man aus vorhandenen Objekten auswählt. Für einen R-Neuling ist es nicht einfach, von Anfang an "in einer R-Box" zu denken.

Also habe ich selbst angefangen, Krücken zu verwenden, was mir sehr geholfen hat, herauszufinden, welches Objekt für welche Daten verwendet werden soll, und mir im Grunde eine reale Verwendung vorzustellen.

Obwohl ich keine genauen Antworten auf die Frage gebe, könnte der kurze Text unten dem Leser helfen, der gerade mit R angefangen hat und ähnliche Fragen stellt.

  • Atomvektor ... Ich habe diese "Sequenz" für mich selbst genannt, keine Richtung, nur eine Sequenz derselben Art. [Teilmengen.
  • Vektor ... Sequenz mit einer Richtung aus 2D, [Teilmengen.
  • Matrix ... Bündel von Vektoren gleicher Länge, die Zeilen oder Spalten bilden, [Teilmengen nach Zeilen und Spalten oder nach Reihenfolge.
  • Arrays ... geschichtete Matrizen, die 3D bilden
  • Dataframe ... eine 2D-Tabelle wie in Excel, in der ich Zeilen oder Spalten sortieren, hinzufügen oder entfernen oder Arit erstellen kann. Operationen mit ihnen, erst nach einiger Zeit erkannte ich wirklich, dass Dataframe eine clevere Implementierung ist, listbei der ich mithilfe [von Zeilen und Spalten, aber sogar mithilfe von Teilmengen unterteilen kann [[.
  • Liste ... um mir selbst zu helfen Ich dachte über Liste nach, tree structurewo [i]ganze Zweige ausgewählt und zurückgegeben werden und [[i]]Artikel aus dem Zweig zurückgegeben werden. Und weil es so ist tree like structure, können Sie sogar ein verwenden index sequence, um jedes einzelne Blatt eines sehr komplexen listmit seinem zu adressieren [[index_vector]]. Listen können einfach oder sehr komplex sein und verschiedene Objekttypen zu einem zusammenfassen.

So haben listsSie am Ende mehr Möglichkeiten, wie Sie leafje nach Situation eine auswählen können, wie im folgenden Beispiel.

l <- list("aaa",5,list(1:3),LETTERS[1:4],matrix(1:9,3,3))
l[[c(5,4)]] # selects 4 from matrix using [[index_vector]] in list
l[[5]][4] # selects 4 from matrix using sequential index in matrix
l[[5]][1,2] # selects 4 from matrix using row and column in matrix

Diese Denkweise hat mir sehr geholfen.


1

Wenn es hilft, neige ich dazu, "Listen" in R als "Datensätze" in anderen Pre-OO-Sprachen zu verstehen:

  • Sie machen keine Annahmen über einen übergreifenden Typ (oder vielmehr ist der Typ aller möglichen Datensätze von Aritäten und Feldnamen verfügbar).
  • Ihre Felder können anonym sein (dann greifen Sie in strikter Definitionsreihenfolge darauf zu).

Der Name "Datensatz" würde mit der Standardbedeutung von "Datensätzen" (auch bekannt als Zeilen) in der Datenbanksprache kollidieren, und möglicherweise hat sich der Name deshalb selbst vorgeschlagen: als Listen (von Feldern).


1

Warum geben diese beiden unterschiedlichen Operatoren [ ]und [[ ]]das gleiche Ergebnis zurück?

x = list(1, 2, 3, 4)
  1. [ ]bietet Untereinstellungsbetrieb. Im Allgemeinen hat die Teilmenge eines Objekts denselben Typ wie das ursprüngliche Objekt. Daher x[1] stellt eine Liste. In ähnlicher Weise x[1:2]handelt es sich um eine Teilmenge der ursprünglichen Liste, daher handelt es sich um eine Liste. Ex.

    x[1:2]
    
    [[1]] [1] 1
    
    [[2]] [1] 2
  2. [[ ]]dient zum Extrahieren eines Elements aus der Liste. x[[1]]ist gültig und extrahiert das erste Element aus der Liste. x[[1:2]]ist nicht gültig, da [[ ]] keine Untereinstellung wie [ ].

     x[[2]] [1] 2 
    
    > x[[2:3]] Error in x[[2:3]] : subscript out of bounds
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.