Dovrei usare un data.frame o una matrice?


152

Quando si dovrebbe usare a data.frame, e quando è meglio usare a matrix?

Entrambi mantengono i dati in un formato rettangolare, quindi a volte non è chiaro.

Esistono regole generali per quando utilizzare quale tipo di dati?


Spesso una matrice può essere più adatta a un particolare tipo di dati, ma se il pacchetto che si desidera utilizzare per analizzare detta matrice prevede un frame di dati, sarà sempre necessario convertirlo inutilmente. Penso che non ci sia modo di evitare di ricordare quale pacchetto usa quale.
xApple

Risposte:


176

Parte della risposta è già contenuta nella domanda: si utilizzano frame di dati se si prevede che le colonne (variabili) siano di tipi diversi (numerico / carattere / logico ecc.). Le matrici sono per dati dello stesso tipo.

Di conseguenza, la matrice scelta / data.frame è problematica solo se si hanno dati dello stesso tipo.

La risposta dipende da cosa hai intenzione di fare con i dati in data.frame / matrix. Se verrà passato ad altre funzioni, il tipo atteso degli argomenti di queste funzioni determinerà la scelta.

Anche:

Le matrici sono più efficienti in termini di memoria:

m = matrix(1:4, 2, 2)
d = as.data.frame(m)
object.size(m)
# 216 bytes
object.size(d)
# 792 bytes

Le matrici sono una necessità se si prevede di eseguire qualsiasi tipo di operazione di algebra lineare.

I frame di dati sono più convenienti se fai spesso riferimento alle sue colonne per nome (tramite l'operatore $ compatto).

I frame di dati sono anche IMHO migliori per riportare (stampare) informazioni tabulari in quanto è possibile applicare la formattazione a ciascuna colonna separatamente.


5
Una cosa che aggiungerei a questa risposta è che se hai intenzione di usare il pacchetto ggplot2 per creare grafici, ggplot2 funziona solo con data.frames e non con le matrici. Solo qualcosa di cui essere consapevoli!
Bajcz,

77

Qualcosa che non è menzionato da @Michal è che non solo una matrice è più piccola del frame di dati equivalente, l'uso di matrici può rendere il codice molto più efficiente rispetto all'utilizzo di frame di dati, spesso in modo considerevole. Questo è uno dei motivi per cui internamente, molte funzioni R costringeranno a matrici i dati che si trovano nei frame di dati.

I frame di dati sono spesso molto più convenienti; uno non ha sempre solo pezzi atomici di dati in giro.

Nota che puoi avere una matrice di caratteri; non devi solo avere dati numerici per costruire una matrice in R.

Nel convertire un frame di dati in una matrice, si noti che esiste una data.matrix()funzione che gestisce i fattori in modo appropriato convertendoli in valori numerici basati sui livelli interni. La coercizione via as.matrix()comporterà una matrice di caratteri se una delle etichette dei fattori non è numerica. Confrontare:

> head(as.matrix(data.frame(a = factor(letters), B = factor(LETTERS))))
     a   B  
[1,] "a" "A"
[2,] "b" "B"
[3,] "c" "C"
[4,] "d" "D"
[5,] "e" "E"
[6,] "f" "F"
> head(data.matrix(data.frame(a = factor(letters), B = factor(LETTERS))))
     a B
[1,] 1 1
[2,] 2 2
[3,] 3 3
[4,] 4 4
[5,] 5 5
[6,] 6 6

Uso quasi sempre un frame di dati per le mie attività di analisi dei dati poiché spesso ho più di semplici variabili numeriche. Quando codifico le funzioni per i pacchetti, forzo quasi sempre a matrice e quindi formatto i risultati come frame di dati. Questo perché i frame di dati sono convenienti.


Mi chiedevo anche la differenza tra data.matrix () e as.matrix (). Grazie per chiarire loro e i tuoi consigli in programmazione.
microbo

Grazie per aver condiviso @Gavin Simpson! Potresti introdurre un po 'di più su come tornare da 1-6 a af?
YJZ,

1
@YZhang Dovresti memorizzare le etichette per ciascun fattore e un vettore logico che indica quali colonne della matrice fossero fattori. Quindi sarebbe relativamente banale convertire solo quelle colonne che erano fattori in fattori con le etichette corrette. I commenti non sono un buon posto per il codice, quindi controlla se è stato chiesto e risposto prima alla Q e se non fai una nuova domanda.
Gavin Simpson,

47

@Michal: le matrici non sono molto più efficienti in termini di memoria:

m <- matrix(1:400000, 200000, 2)
d <- data.frame(m)
object.size(m)
# 1600200 bytes
object.size(d)
# 1600776 bytes

... a meno che tu non abbia un gran numero di colonne:

m <- matrix(1:400000, 2, 200000)
d <- data.frame(m)
object.size(m)
# 1600200 bytes
object.size(d)
# 22400568 bytes

l'argomento dell'efficienza della memoria riguarda in realtà l' data.framesofferta di maggiore flessibilità rispetto ai tipi di colonna. data.frame(a = rnorm(1e6), b = sample(letters, 1e6, TRUE))sarà molto più piccolo (6x dal mio rapido calcolo) in memoria rispetto alla matrixversione a causa della coercizione del tipo.
MichaelChirico,

9

La matrice è in realtà un vettore con metodi aggiuntivi. mentre data.frame è un elenco. La differenza sta nel vettore vs elenco. per efficienza di calcolo, attenersi alla matrice. Utilizzando data.frame se è necessario.


3
Hmm, una matrice è un vettore con dimensioni, non vedo dove entrano i metodi?
Gavin Simpson

0

Le matrici e i frame di dati sono array 2D rettangolari e possono essere eterogenei per righe e colonne . Condividono alcuni metodi e proprietà, ma non tutti.

Esempi:

M <- list(3.14,TRUE,5L,c(2,3,5),"dog",1i)  # a list
dim(M) <- c(2,3)                           # set dimensions
print(M)                                   # print result

#      [,1]  [,2]      [,3]
# [1,] 3.14  5         "dog"
# [2,] TRUE  Numeric,3 0+1i

DF <- data.frame(M)                   # a data frame
print(DF)                             # print result

#      X1      X2   X3
#  1 3.14       5  dog
#  2 TRUE 2, 3, 5 0+1i

M <- matrix(c(1,1,1,1,2,3,1,3,6),3)   # a numeric matrix
DF <- data.frame(M)                   # a all numeric data frame

solve(M)                              # obtains inverse matrix
solve(DF)                             # obtains inverse matrix
det(M)                                # obtains determinant
det(DF)                               # error

0

Non posso sottolineare più la differenza di efficienza tra i due! Sebbene sia vero che i DF sono più convenienti in alcuni casi di analisi dei dati in particolare, consentono anche dati eterogenei e alcune librerie li accettano solo, questi sono tutti secondari a meno che non si scriva un codice unico per un'attività specifica.

Lasciate che vi faccia un esempio. C'era una funzione che calcolava il percorso 2D del metodo MCMC. Fondamentalmente, questo significa che prendiamo un punto iniziale (x, y) e ripetiamo un certo algoritmo per trovare un nuovo punto (x, y) ad ogni passo, costruendo in questo modo l'intero percorso. L'algoritmo prevede il calcolo di una funzione abbastanza complessa e la generazione di alcune variabili casuali ad ogni iterazione, quindi quando viene eseguito per 12 secondi ho pensato che andasse bene dato quanto roba fa ad ogni passaggio. Detto questo, la funzione ha raccolto tutti i punti nel percorso costruito insieme al valore di una funzione obiettivo in un data.frame a 3 colonne. Quindi, 3 colonne non sono così grandi e anche il numero di passaggi era più che ragionevole di 10.000 (in questo tipo di problemi i percorsi di lunghezza 1.000.000 sono tipici, quindi 10.000 non è nulla). Quindi, ho pensato a un DF 10, 000x3 non è sicuramente un problema. Il motivo per cui è stato utilizzato un DF è semplice. Dopo aver chiamato la funzione, è stato chiamato ggplot () per disegnare il percorso (x, y) risultante. E ggplot () non accetta una matrice.

Poi, ad un certo punto per curiosità, ho deciso di cambiare la funzione per raccogliere il percorso in una matrice. Volentieri la sintassi di DF e matrici è simile, tutto ciò che ho fatto è stato cambiare la riga specificando df come data.frame in uno inizializzandolo come matrice. Qui devo anche menzionare che nel codice iniziale il DF è stato inizializzato per avere la dimensione finale, quindi più tardi nel codice della funzione sono stati registrati solo nuovi valori in spazi già allocati e non vi era alcun sovraccarico di aggiungere nuove righe al DF. Ciò rende il confronto ancora più equo, e ha anche semplificato il mio lavoro in quanto non avevo bisogno di riscrivere nulla di più nella funzione. Solo una riga cambia dall'allocazione iniziale di un data.frame della dimensione richiesta a una matrice della stessa dimensione. Per adattare la nuova versione della funzione a ggplot (), ho convertito la matrice ora restituita in dati.

Dopo aver rieseguito il codice non riuscivo a credere al risultato. Il codice viene eseguito in una frazione di secondo! Invece di circa 12 secondi. E ancora una volta, la funzione durante le 10.000 iterazioni legge e scrive solo valori su spazi già allocati in un DF (e ora in una matrice). E questa differenza è anche per la dimensione ragionevole (o piuttosto piccola) 10000x3.

Quindi, se la tua unica ragione per usare un DF è renderlo compatibile con una funzione di libreria come ggplot (), puoi sempre convertirlo in un DF all'ultimo momento - lavora con le matrici per quanto ti senti conveniente. Se d'altra parte c'è un motivo più sostanziale per usare un DF, come ad esempio usare un pacchetto di analisi dei dati che richiederebbe una trasformazione altrimenti costante da matrici a DF e viceversa, o se non si eseguono calcoli intensivi da soli e si usa solo standard pacchetti (molti di loro in realtà trasformano internamente un DF in una matrice, fanno il loro lavoro e poi trasformano il risultato indietro - quindi fanno tutto il lavoro di efficienza per te) o fanno un lavoro una tantum in modo da non preoccuparti e sentirti più a tuo agio con i DF, quindi non dovresti preoccuparti dell'efficienza.

O una diversa regola più pratica: se hai una domanda come nel PO, usa le matrici, quindi utilizzeresti DF solo quando non hai una domanda del genere (perché sai già che devi usare DF, o perché lo fai non importa davvero perché il codice è una tantum ecc.).

Ma in generale, tenere presente questo punto di efficienza sempre come priorità.

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.