Lavorare con dizionari / elenchi in R


89

Ho una domanda banale: non sono riuscito a trovare una struttura dati del dizionario in R, quindi ho usato invece list (come "word" -> number) Quindi, in questo momento ho problemi su come ottenere l'elenco delle chiavi. Qualcuno sa?

Risposte:


118

Sì, il listtipo è una buona approssimazione. Puoi usare names()sul tuo elenco per impostare e recuperare le "chiavi":

> foo <- vector(mode="list", length=3)
> names(foo) <- c("tic", "tac", "toe")
> foo[[1]] <- 12; foo[[2]] <- 22; foo[[3]] <- 33
> foo
$tic
[1] 12

$tac
[1] 22

$toe
[1] 33

> names(foo)
[1] "tic" "tac" "toe"
> 

18
+1 per rispondere alla domanda senza una parola sull'approccio inefficace dell'OP.
Marek

3
A seconda dell'uso previsto di un elenco come proxy per un dizionario, potrebbe essere prudente tenere presente che la ricerca "chiave" per gli elenchi è O (n) anziché O (1), che è ciò che ti aspetteresti per un dizionario (che esegue l'hashing delle chiavi).
egnha

4
Sì, il environmenttipo è usato per quello in R, ma è meno comune / meno noto.
Dirk Eddelbuettel

56

Non hai nemmeno bisogno di elenchi se i tuoi valori di "numero" sono tutti della stessa modalità. Se prendo l'esempio di Dirk Eddelbuettel:

> foo <- c(12, 22, 33)
> names(foo) <- c("tic", "tac", "toe")
> foo
tic tac toe
 12  22  33
> names(foo)
[1] "tic" "tac" "toe"

Gli elenchi sono necessari solo se i valori sono in modalità mista (ad esempio caratteri e numeri) o vettori.

Sia per gli elenchi che per i vettori, un singolo elemento può essere suddiviso in base al nome:

> foo["tac"]
tac 
 22 

O per un elenco:

> foo[["tac"]]
[1] 22

1
Come puoi ottenere l'elenco c(12,22,33)di questa struttura R in stile dizionario pippo? unlist(lapply(FUN=function(a){foo[[a]]},X = 1:length(foo)))è molto scomodo. Qualche funzione pronta per questo? La domanda è stata spostata qui
hhh

18

Per estendere un po 'la risposta di Calimo presento alcune altre cose che potresti trovare utili durante la creazione di questo quasi dizionari in R:

a) come restituire tutti i VALORI del dizionario:

>as.numeric(foo)
[1] 12 22 33

b) controlla se il dizionario CONTIENE LA CHIAVE:

>'tic' %in% names(foo)
[1] TRUE

c) come AGGIUNGERE NUOVA chiave, coppia di valori al dizionario:

c (foo, tic2 = 44)

risultati:

tic       tac       toe     tic2
12        22        33        44 

d) come soddisfare il requisito del DIZIONARIO REALE - che le chiavi NON POSSONO ripetersi (CHIAVI UNICHE)? È necessario combinare b) ec) e creare una funzione che convalidi se esiste tale chiave e fare ciò che si desidera: ad es. Non consentire l'inserimento, aggiornare il valore se il nuovo è diverso da quello vecchio o ricostruire in qualche modo la chiave (ad es. aggiunge un numero ad esso in modo che sia unico)

e) come CANCELLARE la coppia PER CHIAVE dal dizionario:

foo <-foo [which (foo! = foo [["tac"]])]


Posso aggiungere una chiave che contiene spazi, qualcosa come "chiave strana"?
user1700890

Inoltre qualcosa di simile non funziona c(foo, tic2=NULL). Qualche soluzione?
user1700890

15

Il motivo per utilizzare i dizionari in primo luogo è la prestazione. Sebbene sia corretto utilizzare vettori e elenchi con nome per l'attività, il problema è che stanno diventando piuttosto lenti e affamati di memoria con più dati.

Ciò che molte persone non sanno è che R ha effettivamente una struttura dati del dizionario incorporata: ambienti con l'opzionehash = TRUE

Vedi il seguente esempio per come farlo funzionare:

# vectorize assign, get and exists for convenience
assign_hash <- Vectorize(assign, vectorize.args = c("x", "value"))
get_hash <- Vectorize(get, vectorize.args = "x")
exists_hash <- Vectorize(exists, vectorize.args = "x")

# keys and values
key<- c("tic", "tac", "toe")
value <- c(1, 22, 333)

# initialize hash
hash = new.env(hash = TRUE, parent = emptyenv(), size = 100L)
# assign values to keys
assign_hash(key, value, hash)
## tic tac toe 
##   1  22 333
# get values for keys
get_hash(c("toe", "tic"), hash)
## toe tic 
## 333   1
# alternatively:
mget(c("toe", "tic"), hash)
## $toe
## [1] 333
## 
## $tic
## [1] 1
# show all keys
ls(hash)
## [1] "tac" "tic" "toe"
# show all keys with values
get_hash(ls(hash), hash)
## tac tic toe 
##  22   1 333
# remove key-value pairs
rm(list = c("toe", "tic"), envir = hash)
get_hash(ls(hash), hash)
## tac 
##  22
# check if keys are in hash
exists_hash(c("tac", "nothere"), hash)
##     tac nothere 
##    TRUE   FALSE
# for single keys this is also possible:
# show value for single key
hash[["tac"]]
## [1] 22
# create new key-value pair
hash[["test"]] <- 1234
get_hash(ls(hash), hash)
##  tac test 
##   22 1234
# update single value
hash[["test"]] <- 54321
get_hash(ls(hash), hash)
##   tac  test 
##    22 54321

Modifica : sulla base di questa risposta ho scritto un post sul blog con un po 'più di contesto: http://blog.ephorie.de/hash-me-if-you-can


Funziona per relazioni multivalore? Ad esempio tic = 1 e tic = 17
skan

@skan: Perché non lo provi?
vonjd

L'utilizzo di questo approccio al posto dell'utilizzo di elenchi con nomi ha ridotto il mio tempo di esecuzione da 6 minuti a 1 secondo! Capisco bene gli hash, ma qualcuno può confermare quando si cerca un nome in un elenco che tipo di algoritmo di ricerca viene utilizzato? Sta solo iterando l'elenco sotto le corrispondenze del nome? Vorrei capire esattamente perché gli elenchi sono così lenti e perché gli hash sono così veloci per un gran numero di chiavi?
Phil

@vonjd Sto cercando di usare il dizionario in R e ho trovato questa implementazione. Tuttavia, funziona anche quando ogni valore è associato a una coppia di chiavi? Grazie in anticipo.
salva il

@shana: potresti fare un esempio di cosa intendi esattamente?
vonjd

9

L' hash del pacchetto è ora disponibile: https://cran.r-project.org/web/packages/hash/hash.pdf

Esempi

h <- hash( keys=letters, values=1:26 )
h <- hash( letters, 1:26 )
h$a
# [1] 1
h$foo <- "bar"
h[ "foo" ]
# <hash> containing 1 key-value pair(s).
#   foo : bar
h[[ "foo" ]]
# [1] "bar"

Come puoi aggiungere più valori? Ho provato a ripetere la chiave ma memorizza solo l'ultimo valore. Ho anche provato ad assegnare elenchi ma non funziona
skan

I dizionari non memorizzano mai più valori per chiave. Puoi assegnare un elenco a una chiave, se lo desideri.
Ballpoint

7

Variazione più breve della risposta di Dirk:

# Create a Color Palette Dictionary 
> color <- c('navy.blue', 'gold', 'dark.gray')
> hex <- c('#336A91', '#F3C117', '#7F7F7F')

> # Create List
> color_palette <- as.list(hex)
> # Name List Items
> names(color_palette) <- color
> 
> color_palette
$navy.blue
[1] "#336A91"

$gold
[1] "#F3C117"

$dark.gray
[1] "#7F7F7F"

4

Mi limiterò a commentare che puoi ottenere un sacco di chilometri tablequando provi anche a "falsificare" un dizionario, ad es

> x <- c("a","a","b","b","b","c")
> (t <- table(x))
x
a b c 
2 3 1 
> names(t)
[1] "a" "b" "c"
> o <- order(as.numeric(t))
> names(t[o])
[1] "c" "a" "b"

eccetera.


Non credo as.numeric()sia necessario. La tabella è già numerica. Puoi ottenere lo stesso risultato connames(t[order(t)])
Rich Scriven
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.