web-dev-qa-db-fra.com

La différence entre crochet [] et double crochet [[]] pour accéder aux éléments d'une liste ou d'un cadre de données

R fournit deux méthodes différentes pour accéder aux éléments d’une liste ou de data.frame: les opérateurs [] et [[]].

Quelle est la différence entre les deux? Dans quelles situations devrais-je utiliser l'un par rapport à l'autre?

442
Sharpie

La définition du langage R est pratique pour répondre à ces types de questions:

R possède trois opérateurs d’indexation de base, la syntaxe étant illustrée par les exemples suivants

    x[i]
    x[i, j]
    x[[i]]
    x[[i, j]]
    x$a
    x$"a"

Pour les vecteurs et les matrices, les formes [[ sont rarement utilisées, bien qu’elles présentent de légères différences sémantiques par rapport à la forme [ (par exemple, elle supprime tout attribut name ou dimnames et une correspondance partielle est utilisée pour les index de caractère). Lors de l'indexation de structures multidimensionnelles avec un seul index, x[[i]] ou x[i] renvoie l'élément ith séquentiel de x.

Pour les listes, on utilise généralement [[ pour sélectionner un seul élément, alors que [ renvoie une liste des éléments sélectionnés.

La forme [[ ne permet de sélectionner qu'un seul élément à l'aide d'indices d'entiers ou de caractères, alors que [ permet l'indexation par des vecteurs. Notez que pour une liste, l'index peut être un vecteur et chaque élément du vecteur est appliqué à son tour à la liste, au composant sélectionné, au composant sélectionné de ce composant, etc. Le résultat est toujours un seul élément .

283
ars

Les différences significatives entre les deux méthodes sont la classe des objets qu’elles renvoient lorsqu’elles sont utilisées pour l’extraction et si elles acceptent une plage de valeurs ou une seule valeur lors de l’affectation.

Prenons le cas de l'extraction de données dans la liste suivante:

foo <- list( str='R', vec=c(1,2,3), bool=TRUE )

Supposons que nous souhaitons extraire la valeur stockée par bool à partir de foo et l’utiliser dans une instruction if(). Cela illustrera les différences entre les valeurs de retour de [] et [[]] lorsqu'elles sont utilisées pour l'extraction de données. La méthode [] renvoie les objets de la liste de classes (ou data.frame si foo était un data.frame), tandis que la méthode [[]] renvoie les objets dont la classe est déterminée par le type de leurs valeurs. 

Donc, en utilisant la méthode [], vous obtenez:

if( foo[ 'bool' ] ){ print("Hi!") }
Error in if (foo["bool"]) { : argument is not interpretable as logical

class( foo[ 'bool' ] )
[1] "list"

Cela est dû au fait que la méthode [] a renvoyé une liste et qu'une liste n'est pas un objet valide à transmettre directement à une instruction if(). Dans ce cas, nous devons utiliser [[]] car il retournera l'objet "nu" stocké dans 'bool' qui aura la classe appropriée:

if( foo[[ 'bool' ]] ){ print("Hi!") }
[1] "Hi!"

class( foo[[ 'bool' ]] )
[1] "logical"

La deuxième différence est que l'opérateur [] peut être utilisé pour accéder à un range d'emplacements dans une liste ou à des colonnes d'une trame de données alors que l'opérateur [[]] est limité à l'accès à un emplacement ou à une colonne single. Prenons le cas de l’affectation de valeur en utilisant une deuxième liste, bar():

bar <- list( mat=matrix(0,nrow=2,ncol=2), Rand=rnorm(1) )

Supposons que nous voulions écraser les deux derniers emplacements de foo avec les données contenues dans bar. Si nous essayons d'utiliser l'opérateur [[]], voici ce qui se produit:

foo[[ 2:3 ]] <- bar
Error in foo[[2:3]] <- bar : 
more elements supplied than there are to replace

En effet, [[]] est limité à l'accès à un seul élément. Nous devons utiliser []:

foo[ 2:3 ] <- bar
print( foo )

$str
[1] "R"

$vec
     [,1] [,2]
[1,]    0    0
[2,]    0    0

$bool
[1] -0.6291121

Notez que tant que l’affectation a abouti, les emplacements de foo ont conservé leur nom original.

156
Sharpie

Les doubles crochets donnent accès à une liste élément , alors qu'un seul crochet vous redonne une liste avec un seul élément.

lst <- list('one','two','three')

a <- lst[1]
class(a)
## returns "list"

a <- lst[[1]]
class(a)
## returns "character"
96
medriscoll

[] extrait une liste, [[]] extrait des éléments de la liste

alist <- list(c("a", "b", "c"), c(1,2,3,4), c(8e6, 5.2e9, -9.3e7))

str(alist[[1]])
 chr [1:3] "a" "b" "c"

str(alist[1])
List of 1
 $ : chr [1:3] "a" "b" "c"

str(alist[[1]][1])
 chr "a"
43
user143339

De Hadley Wickham:

 From Hadley Wickham

Ma modification (de mauvaise qualité) à afficher avec tidyverse/purrr

 enter image description here

33
jzadra

Pour aider les débutants à naviguer dans le brouillard manuel, il peut être utile de voir la notation [[ ... ]] sous la forme/ collapsing function - en d’autres termes, c’est lorsque vous voulez simplement «obtenir les données» d’un vecteur, d’une liste ou trame de données. Faites cela si vous souhaitez utiliser les données de ces objets pour les calculs. Ces exemples simples vont illustrer.

(x <- c(x=1, y=2)); x[1]; x[[1]]
(x <- list(x=1, y=2, z=3)); x[1]; x[[1]]
(x <- data.frame(x=1, y=2, z=3)); x[1]; x[[1]]

Donc du troisième exemple:

> 2 * x[1]
  x
1 2
> 2 * x[[1]]
[1] 2
12
Redfoot

Les deux d'entre eux sont des moyens de sous-définir . Le crochet unique renverra un sous-ensemble de la liste, qui en soi sera une liste. C'est-à-dire qu'il peut contenir ou non plus d'un élément . D'autre part, un double crochet ne renverra qu'un seul élément de la liste.

-Un support unique nous donnera une liste. Nous pouvons également utiliser un seul crochet si nous souhaitons renvoyer plusieurs éléments de la liste . Considérez la liste suivante: -

>r<-list(c(1:10),foo=1,far=2);

Notez maintenant la manière dont la liste est renvoyée lorsque je tente de l’afficher . Je tape r et appuie sur Entrée.

>r

#the result is:-

[[1]]

 [1]  1  2  3  4  5  6  7  8  9 10

$foo

[1] 1

$far

[1] 2

Maintenant, nous allons voir la magie du support unique: -

>r[c(1,2,3)]

#the above command will return a list with all three elements of the actual list r as below

[[1]]

 [1]  1  2  3  4  5  6  7  8  9 10

$foo

[1] 1


$far

[1] 2

ce qui est exactement la même chose que lorsque nous avons essayé d'afficher la valeur de r à l'écran, ce qui signifie que l'utilisation de parenthèses simples a renvoyé une liste, où à l'index 1 nous avons un vecteur de 10 éléments, puis nous avons deux autres éléments avec les noms foo et far . Nous pouvons également choisir de donner un seul index ou nom d’élément en tant qu’entrée à la parenthèse unique .

> r[1]

[[1]]

 [1]  1  2  3  4  5  6  7  8  9 10

Dans cet exemple, nous avons donné un index "1" et obtenu en retour une liste avec un élément (qui est un tableau de 10 nombres)

> r[2]

$foo

[1] 1

Dans l'exemple ci-dessus, nous avons donné un index "2" et obtenu en retour une liste avec un élément

> r["foo"];

$foo

[1] 1

Dans cet exemple, nous avons passé le nom d'un élément et en retour, une liste a été renvoyée avec un élément.

Vous pouvez également transmettre un vecteur de noms d'éléments comme: -

> x<-c("foo","far")

> r[x];

$foo

[1] 1

$far
[1] 2

Dans cet exemple, nous avons passé un vecteur avec deux noms d'élément "foo" et "far"

En retour, nous avons une liste avec deux éléments.

En bref, un crochet unique vous renverra toujours une autre liste avec un nombre d'éléments égal au nombre d'éléments ou au nombre d'index que vous passez dans le crochet unique.

En revanche, un double crochet ne renverra toujours qu’un seul élément . Avant de passer au double crochet, il ne faut pas oublier une note .NOTE:THE MAJOR DIFFERENCE BETWEEN THE TWO IS THAT SINGLE BRACKET RETURNS YOU A LIST WITH AS MANY ELEMENTS AS YOU WISH WHILE A DOUBLE BRACKET WILL NEVER RETURN A LIST. RATHER A DOUBLE BRACKET WILL RETURN ONLY A SINGLE ELEMENT FROM THE LIST.

Je vais localiser quelques exemples. Veuillez garder une note des mots en gras et y revenir après avoir terminé les exemples ci-dessous:

Le double crochet vous renverra la valeur réelle à l’index (PAS retournera une liste)

  > r[[1]]

     [1]  1  2  3  4  5  6  7  8  9 10


  >r[["foo"]]

    [1] 1

pour les doubles crochets, si nous essayons de voir plus d'un élément en passant un vecteur, il en résultera une erreur simplement parce qu'il n'a pas été construit pour répondre à ce besoin, mais pour renvoyer un seul élément.

Considérer ce qui suit

> r[[c(1:3)]]
Error in r[[c(1:3)]] : recursive indexing failed at level 2
> r[[c(1,2,3)]]
Error in r[[c(1, 2, 3)]] : recursive indexing failed at level 2
> r[[c("foo","far")]]
Error in r[[c("foo", "far")]] : subscript out of bounds
12
Jijo Mathew

Étant terminologique, l'opérateur [[ extrait l'élément d'une liste alors que l'opérateur [ prend sous-ensemble d'une liste.

8
submartingale

Pour un autre cas d'utilisation concret, utilisez des crochets doubles lorsque vous souhaitez sélectionner un bloc de données créé par la fonction split(). Si vous ne le savez pas, split() regroupe une liste/un bloc de données en sous-ensembles basés sur un champ clé. C'est utile si vous souhaitez utiliser plusieurs groupes, les tracer, etc.

> class(data)
[1] "data.frame"

> dsplit<-split(data, data$id)
> class(dsplit)
[1] "list"

> class(dsplit['ID-1'])
[1] "list"

> class(dsplit[['ID-1']])
[1] "data.frame"
7
Peter

En outre:

Suivant le L I N K du A N S W E R ici. 

Voici un petit exemple abordant le point suivant:

x[i, j] vs x[[i, j]]

df1   <- data.frame(a = 1:3)
df1$b <- list(4:5, 6:7, 8:9)

df1[[1,2]]
df1[1,2]

str(df1[[1,2]])
str(df1[1,2])
0
Andre Elrico