Je voudrais construire un dataframe ligne par ligne dans R. J'ai fait quelques recherches, et tout ce que j'ai proposé est la suggestion de créer une liste vide, de garder un index de liste scalaire, puis à chaque fois d'ajouter à la liste une trame de données à une seule ligne et avance l'index de la liste d'une unité. Enfin, do.call(rbind,)
sur la liste.
Bien que cela fonctionne, cela semble très fastidieux. N'y a-t-il pas un moyen plus simple d'atteindre le même objectif?
Évidemment, je fais référence aux cas où je ne peux pas utiliser une apply
fonction et j'ai explicitement besoin de créer le dataframe ligne par ligne. Au moins, y a-t-il un moyen d'arriver à push
la fin d'une liste au lieu de garder explicitement une trace du dernier index utilisé?
append()
[qui devrait probablement être nommé insert] ouc()
pour ajouter des éléments à la fin d'une liste, mais cela ne vous aidera pas ici.lapply()
,Map()
et ainsi de suite, mais vous pouvez aussi jeter un oeil àaggregate()
,dapply() {heR.Misc}
etcast() {reshape}
pour voir si vos tâches ne peuvent pas être traitées par ces fonctions (toutes renvoient des trames de données).Réponses:
Vous pouvez les agrandir ligne par ligne en ajoutant ou en utilisant
rbind()
.Cela ne veut pas dire que vous devriez. La croissance dynamique des structures est l'un des moyens les moins efficaces de coder dans R.
Si vous le pouvez, allouez dès le départ l'intégralité de votre data.frame:
puis pendant vos opérations, insérez une ligne à la fois
Cela devrait fonctionner pour data.frame arbitraire et être beaucoup plus efficace. Si vous dépassez N, vous pouvez toujours réduire les lignes vides à la fin.
la source
data.table
semble être encore plus rapide que la pré-allocation utilisant data.frames. Test ici: stackoverflow.com/a/11486400/636656On peut ajouter des lignes à
NULL
:par exemple
la source
sapply
(ou vectoriser) et transposer.Ceci est un exemple idiot de la façon d'utiliser
do.call(rbind,)
sur la sortie deMap()
[qui est similaire àlapply()
]J'utilise cette construction assez souvent.
la source
La raison pour laquelle j'aime tant Rcpp est que je ne comprends pas toujours comment R Core pense, et avec Rcpp, le plus souvent, je n'ai pas à le faire.
Parlant philosophiquement, vous êtes dans un état de péché en ce qui concerne le paradigme fonctionnel, qui essaie de faire en sorte que chaque valeur semble indépendante de toute autre valeur; changer une valeur ne devrait jamais entraîner de changement visible dans une autre valeur, comme vous le faites avec les pointeurs partageant la représentation en C.
Les problèmes surviennent lorsque la programmation fonctionnelle signale au petit vaisseau de s'éloigner du chemin et que le petit vaisseau répond «Je suis un phare». Faire une longue série de petits changements à un gros objet que vous souhaitez traiter entre-temps vous place dans le territoire du phare.
Dans le C ++ STL,
push_back()
c'est un mode de vie. Il n'essaie pas d'être fonctionnel, mais il essaie de s'adapter efficacement aux idiomes de programmation courants .Avec une certaine intelligence dans les coulisses, vous pouvez parfois vous arranger pour avoir un pied dans chaque monde. Les systèmes de fichiers basés sur des instantanés en sont un bon exemple (qui a évolué à partir de concepts tels que les montages union, qui agissent également des deux côtés).
Si R Core voulait faire cela, le stockage vectoriel sous-jacent pourrait fonctionner comme un montage d'union. Une référence au stockage vectoriel peut être valide pour les indices
1:N
, tandis qu'une autre référence au même stockage est valide pour les indices1:(N+1)
. Il pourrait y avoir un stockage réservé pas encore valablement référencé par autre chose que pratique pour un rapidepush_back()
. Vous ne violez pas le concept fonctionnel lors de l'ajout en dehors de la plage que toute référence existante considère comme valide.Finalement, en ajoutant des lignes de manière incrémentielle, vous manquez de stockage réservé. Vous devrez créer de nouvelles copies de tout, avec le stockage multiplié par un certain incrément. Les implémentations STL que j'utilise ont tendance à multiplier le stockage par 2 lors de l'extension de l'allocation. Je pensais avoir lu dans R Internals qu'il existe une structure de mémoire où le stockage augmente de 20%. Dans tous les cas, les opérations de croissance se produisent avec une fréquence logarithmique par rapport au nombre total d'éléments ajoutés. Sur une base amortie, cela est généralement acceptable.
Alors que les astuces se déroulent dans les coulisses, j'ai vu pire. Chaque fois que vous
push_back()
insérez une nouvelle ligne dans la trame de données, une structure d'index de niveau supérieur doit être copiée. La nouvelle ligne pourrait s'ajouter à la représentation partagée sans affecter les anciennes valeurs fonctionnelles. Je ne pense même pas que cela compliquerait beaucoup le ramasse-miettes; puisque je ne propose pas quepush_front()
toutes les références soient des références de préfixe à l'avant du stockage vectoriel alloué.la source
La réponse de Dirk Eddelbuettel est la meilleure; Ici, je note simplement que vous pouvez vous en tirer sans pré-spécifier les dimensions ou les types de données du dataframe, ce qui est parfois utile si vous avez plusieurs types de données et beaucoup de colonnes:
la source
df<-rbind(df, row2)
?J'ai trouvé cette façon de créer des dataframe par raw sans matrice.
Avec nom de colonne automatique
Avec le nom de la colonne
la source
Si vous avez des vecteurs destinés à devenir des lignes, concaténez-les à l'aide de
c()
, transmettez-les à une matrice ligne par ligne et convertissez cette matrice en dataframe.Par exemple, les lignes
peut être converti en une trame de données ainsi:
Certes, je vois 2 limitations majeures: (1) cela ne fonctionne qu'avec des données monomodes, et (2) vous devez connaître vos # colonnes finales pour que cela fonctionne (c'est-à-dire que je suppose que vous ne travaillez pas avec un tableau irrégulier dont la plus grande longueur de ligne est inconnue a priori ).
Cette solution semble simple, mais d'après mon expérience avec les conversions de type dans R, je suis sûr que cela crée de nouveaux défis en aval. Quelqu'un peut-il commenter cela?
la source
Selon le format de votre nouvelle ligne, vous pouvez utiliser
tibble::add_row
si votre nouvelle ligne est simple et peut être spécifiée en "paires de valeurs". Ou vous pouvez utiliserdplyr::bind_rows
"une implémentation efficace du modèle commun de do.call (rbind, dfs)".la source