159 votes

Dois-je utiliser un data.frame ou une matrice ?

Quand doit-on utiliser un data.frame et quand est-il préférable d'utiliser un matrix ?

Les deux conservent les données dans un format rectangulaire, donc parfois ce n'est pas clair.

Existe-t-il des règles générales pour savoir quand utiliser tel ou tel type de données ?

0 votes

Souvent, une matrice peut être mieux adaptée à un type particulier de données, mais si le paquet que vous voulez utiliser pour analyser ladite matrice s'attend à un cadre de données, vous devrez toujours le convertir inutilement. Je pense qu'il n'y a aucun moyen d'éviter de se souvenir de quel paquet utilise quel paquet.

181voto

Michał Points 929

Une partie de la réponse est déjà contenue dans votre question : Vous utilisez des cadres de données si l'on peut s'attendre à ce que les colonnes (variables) soient de différents types (numérique/caractère/logique, etc.). Les matrices sont destinées aux données de même type.

Par conséquent, le choix matrice/data.frame n'est problématique que si vous disposez de données du même type.

La réponse dépend de ce que vous allez faire avec les données dans data.frame/matrix. Si elles sont destinées à être transmises à d'autres fonctions, le type attendu des arguments de ces fonctions détermine le choix.

Aussi :

Les matrices sont plus efficaces en termes de mémoire :

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

Les matrices sont indispensables si vous envisagez d'effectuer des opérations de type algèbre linéaire.

Les cadres de données sont plus pratiques si vous vous référez fréquemment à leurs colonnes par leur nom (via l'opérateur compact $).

Les cadres de données sont aussi, à mon avis, plus adaptés à la présentation (impression) d'informations tabulaires, car vous pouvez appliquer un formatage à chaque colonne séparément.

5 votes

Une chose que j'ajouterais à cette réponse est que si vous prévoyez d'utiliser le paquet ggplot2 pour faire des graphiques, ggplot2 ne fonctionne qu'avec des data.frames et non des matrices. Il s'agit d'une information à connaître !

78voto

Gavin Simpson Points 72349

Un point non mentionné par @Michal est que non seulement une matrice est plus petite que le cadre de données équivalent, mais l'utilisation de matrices peut rendre votre code beaucoup plus efficace que l'utilisation de cadres de données, souvent considérablement. C'est l'une des raisons pour lesquelles, en interne, de nombreuses fonctions R transforment en matrices des données qui se trouvent dans des cadres de données.

Les cadres de données sont souvent bien plus pratiques ; on ne dispose pas toujours de morceaux de données purement atomiques.

Notez que vous pouvez avoir une matrice de caractères ; il n'est pas nécessaire d'avoir des données numériques pour construire une matrice dans R.

Lors de la conversion d'un cadre de données en une matrice, notez qu'il y a une data.matrix() qui traite les facteurs de manière appropriée en les convertissant en valeurs numériques basées sur les niveaux internes. Contrainte via as.matrix() donnera une matrice de caractères si l'une des étiquettes de facteur est non numérique. Comparez :

> 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

J'utilise presque toujours un cadre de données pour mes tâches d'analyse de données, car j'ai souvent plus que des variables numériques. Lorsque je code des fonctions pour des paquets, je les transforme presque toujours en matrice, puis je reformate les résultats sous forme de cadre de données. C'est parce que les cadres de données sont pratiques.

0 votes

Je me suis également demandé quelle était la différence entre data.matrix() et as.matrix(). Merci de les clarifier et de donner vos conseils en programmation.

0 votes

Merci de partager @Gavin Simpson ! Pourriez-vous nous en dire un peu plus sur la façon de revenir de 1-6 à a-f ?

1 votes

@YZhang Il faudrait stocker les étiquettes de chaque facteur et un vecteur logique indiquant quelles colonnes de la matrice sont des facteurs. Il serait ensuite relativement simple de reconvertir les colonnes qui sont des facteurs en facteurs avec les étiquettes correctes. Les commentaires ne sont pas de bons endroits pour le code, alors regardez si la question a été posée et répondue auparavant et si non, posez une nouvelle question.

49voto

petrelharp Points 460

@Michal : Les matrices ne sont pas vraiment plus efficaces en termes de mémoire :

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

... sauf si vous avez un grand nombre de colonnes :

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

0 votes

L'argument de l'efficacité de la mémoire est en fait data.frames offrant plus de flexibilité sur les types de colonnes. data.frame(a = rnorm(1e6), b = sample(letters, 1e6, TRUE)) sera beaucoup plus petite (6x selon mon calcul rapide) en mémoire que la matrix à cause de la coercition de type.

10voto

user8341 Points 31

La matrice est en fait un vecteur avec des méthodes supplémentaires, tandis que data.frame est une liste. La différence se résume à vecteur vs liste. Pour l'efficacité du calcul, restez avec la matrice. Utilisez data.frame si vous devez le faire.

3 votes

Hmm, une matrice est un vecteur avec des dimensions, je ne vois pas où les méthodes entrent en jeu ?

1voto

Vadim Points 235

Je ne peux pas insister davantage sur la différence d'efficacité entre les deux ! S'il est vrai que les DF sont plus pratiques dans certains cas, en particulier pour l'analyse des données, qu'ils permettent également l'utilisation de données hétérogènes et que certaines bibliothèques les acceptent uniquement, tout cela est vraiment secondaire, sauf si vous écrivez un code unique pour une tâche spécifique.

Laissez-moi vous donner un exemple. Il y avait une fonction qui calculait le chemin 2D de la méthode MCMC. En gros, cela signifie que nous prenons un point initial (x,y), et que nous itérons un certain algorithme pour trouver un nouveau point (x,y) à chaque étape, en construisant de cette façon le chemin complet. L'algorithme implique le calcul d'une fonction assez complexe et la génération d'une certaine variable aléatoire à chaque itération, donc quand il a fonctionné pendant 12 secondes, j'ai pensé que c'était bien étant donné la quantité de choses qu'il fait à chaque étape. Ceci étant dit, la fonction a rassemblé tous les points du chemin construit ainsi que la valeur d'une fonction objective dans un data.frame à 3 colonnes. Ainsi, 3 colonnes n'est pas si grand, et le nombre d'étapes était également plus que raisonnable 10.000 (dans ce genre de problèmes les chemins de longueur 1.000.000 sont typiques, donc 10.000 n'est rien). J'ai donc pensé qu'un DF de 10 000x3 n'était absolument pas un problème. La raison pour laquelle un DF a été utilisé est simple. Après avoir appelé la fonction, ggplot() a été appelé pour dessiner le chemin (x,y) résultant. Et ggplot() n'accepte pas de matrice.

Puis, à un moment donné, par curiosité, j'ai décidé de modifier la fonction pour rassembler le chemin dans une matrice. Heureusement la syntaxe des DFs et des matrices est similaire, tout ce que j'ai fait c'est de changer la ligne spécifiant df comme un data.frame par une ligne l'initialisant comme une matrice. Ici, je dois également mentionner que dans le code initial, le DF a été initialisé pour avoir la taille finale, de sorte que plus tard dans le code de la fonction, seules les nouvelles valeurs ont été enregistrées dans les espaces déjà alloués, et il n'y avait pas de frais généraux pour ajouter de nouvelles lignes au DF. Cela rend la comparaison encore plus équitable, et cela a également simplifié mon travail, car je n'ai pas eu besoin de réécrire quoi que ce soit d'autre dans la fonction. Une seule ligne a été modifiée pour passer de l'allocation initiale d'un data.frame de la taille requise à une matrice de la même taille. Pour adapter la nouvelle version de la fonction à ggplot(), j'ai converti la matrice maintenant retournée en un data.frame à utiliser dans ggplot().

Après avoir réexécuté le code, je ne pouvais pas croire le résultat. Le code a été exécuté en une fraction de seconde ! Au lieu d'environ 12 secondes. Et encore, la fonction pendant les 10.000 itérations n'a fait que lire et écrire des valeurs dans des espaces déjà alloués dans un DF (et maintenant dans une matrice). Et cette différence est aussi pour la taille raisonnable (ou plutôt petite) 10000x3.

Ainsi, si votre seule raison d'utiliser un DF est de le rendre compatible avec une fonction de bibliothèque telle que ggplot(), vous pouvez toujours le convertir en DF au dernier moment - et travailler avec des matrices aussi loin que vous le souhaitez. Si, d'un autre côté, vous avez une raison plus importante d'utiliser un DF, par exemple si vous utilisez un paquet d'analyse de données qui nécessiterait une transformation constante des matrices en DF et vice-versa, ou si vous ne faites pas de calculs intensifs vous-même et n'utilisez que des paquets standard (beaucoup d'entre eux transforment en interne un DF en matrice, font leur travail, puis retransforment le résultat - ils font donc tout le travail d'efficacité pour vous), ou si vous faites un travail unique pour ne pas vous soucier et vous sentir plus à l'aise avec les DF, alors vous ne devriez pas vous soucier de l'efficacité.

Ou une autre règle plus pratique : si vous avez une question comme dans l'OP, utilisez les matrices, alors vous n'utiliserez les DF que lorsque vous n'avez pas une telle question (parce que vous savez déjà que vous devez utiliser les DF, ou parce que vous ne vous en souciez pas vraiment puisque le code est unique, etc.)

Mais en général, gardez toujours à l'esprit ce point d'efficacité comme une priorité.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X