Quel est le moyen idiomatique de collecter des résultats dans une boucle dans R si le nombre de résultats finaux n'est pas connu à l'avance? Voici un exemple de jouet:
results = list() i=1L while (i < bigBigBIGNumber) { if (someCondition(i)) results = list(results, i) i = i+1 } unlist(results)
4 Réponses :
plus proche du second que vous avez énuméré: Notez que aussi, vous pouvez utiliser i code> n'a pas besoin d'être un
entier code>, pourrait être un
caractère code>, etc. p>
résultats [[longueur (résultats)]] <- ... code> si nécessaire, mais si vous Avoir déjà un itérateur, probablement ne serait probablement pas. p> p>
Cela résoudra-t-il les deux problèmes que j'ai posés sur, à savoir 1. B> pré-générer toutes les valeurs à itérer (je ne veux pas les garder toutes en mémoire) et 2 . B> est-il ajouté à la complexité quadratique, c'est-à-dire que l'ajout comme des résultats [[i]] <- ... code> provoque la réaffectation de l'ensemble de la liste?
Un peu de benchmarking montre qu'il échoue sur les deux points 1. I> et pointez 2. I> de mon commentaire. Cependant, il montre également que cette façon d'ajouter à une liste est plus rapide que l'approche de la liste liée que j'ai essayée jusqu'à une très grande longueur (plus que 100000 code>), ainsi que cette boucle dans
R code> De cette façon est si lent que je vais généralement "manquer de temps" avant de pouvoir manquer de mémoire lorsque vous utilisez
pour code>.
Si l'efficacité est d'une extrême préoccupation, vous voulez probablement regarder en dehors de la base r code>.
RCPP code> vous vient à l'esprit. cran.r-project.org/web/packages/rcpp/index. HTML
Toute affectation aura une "complexité quadratique" dans R. Il y a toujours au moins une copie temporaire, parfois plus, faite avant la fin de la tâche. Le conseil donné est d'avoir au moins 3 fois la RAM devait contenir le plus grand objet de votre espace de travail. (Consommé à un taux d'environ 10 octets par «double».)
@Dwin voulez-vous dire que même x = 1: 10; x [[3]] <- 10 CODE> réaffecte le tableau complet i>? Cela ne fera sûrement pas cela, car vous avez suggéré de pré-allocation vous-même dans votre autre commentaire. La complexité quadratique n'est pas de l'affectation, mais de l'ajout répété
n code> fois. (Cela prendra
O (n ^ 2) code> temps.)
@Szabolcs, pourquoi indexez-vous un vecteur avec [[]] code> au lieu de
[] code>?
@Dwin, je ne comprends pas si vous dites que la solution de Ricardo est efficace ou non ... Pourriez-vous s'il vous plaît clarifier? La liste est pas i> préallocated. Cela serait également inefficace que je suppose que je suppose.
@Arun suppose juste [ code> si vous l'aimez mieux et si cela ne fait aucune différence.
@Szabolcs tant que vous n'accédez pas à une liste, [[ code> et
[ code> ne fait pas une différence, oui.
Je dis que l'inefficacité ne peut être éliminée. Copier sur la mission en r est juste m = pas évitable sans stratégies de codage spéciales qui ne sont sans doute en dehors de la portée de la langue appropriée. Si vous voulez une efficacité, je vous suggère de regarder dans le paquet de données.Table ou de la RCPP. Il y a plusieurs exemples de données de données.
Si vous ne pouvez pas calculer (Ce code n'est pas testé. ) p> Si vous pouvez calculer Je suppose que vous souhaitez appeler une fonction, et non simplement sur les indices eux-mêmes. Quelque chose comme ça peut être plus proche de ce que vous voulez: p> 1: bigbignumber code>, comptez les entrées, créez le vecteur, puis remplissez-le.
1: bigbigbignumber code>, cela fonctionnera également: p>
+1 pour indiquer la valeur potentielle de vectorisation dans les valeurs [Somécontion (valeurs)] code>
Le problème étant, bien sûr, que somécontion (i) code> est calculé deux fois i>. S'il s'agit d'un calcul complexe, alors cela peut le faire deux fois peut manger des gains de performance. J'ai une question dans ces lignes , toutes les pensées seraient appréciées.
Voici un algorithme qui double la taille de la liste de sortie tel qu'il remplit, obtenant des temps de calcul quelque peu linéaires, comme indiquez les tests de référence:
test <- function(bigBigBIGNumber = 1000) { n <- 10L results <- vector("list", n) m <- 0L i <- 1L while (i < bigBigBIGNumber) { if (runif(1) > 0.5) { m <- m + 1L results[[m]] <- i if (m == n) { results <- c(results, vector("list", n)) n <- n * 2L } } i = i + 1L } unlist(results) } system.time(test(1000)) # user system elapsed # 0.008 0.000 0.008 system.time(test(10000)) # user system elapsed # 0.090 0.002 0.093 system.time(test(100000)) # user system elapsed # 0.885 0.051 0.936 system.time(test(1000000)) # user system elapsed # 9.428 0.339 9.776
Merci, c'est très pratique, alors je l'accepterai, mais les autres réponses / commentaires ont également contribué à comprendre ce que les gens considèrent idiomatique dans R.
Je suppose que la linéarité est vraiment en tête dans la boucle (générant des nombres aléatoires, attribuant des résultats, etc.); Le temps de croissance est égal à juste (par exemple, pour 2 ^ 20 éléments) system.time ({x = entier (1); pour (i in 1:19) x <- C (x, entier (2 ^ i))}) code> (une fraction d'une seconde).
Il y a probablement une taille maximale que vous êtes prêt à tolérer; Pré-allouer et remplir ce niveau, puis couper si nécessaire. Cela évite le risque de ne pas pouvoir satisfaire la demande de double taille, même lorsque seule une petite quantité supplémentaire de mémoire pourrait être nécessaire; Il échoue tôt et implique une seule réaffectation plutôt que de log (n). Voici une fonction qui prend une taille maximale, une fonction génératrice et un jeton que la fonction génératrice retourne quand il n'y a plus rien à générer. Nous obtenons jusqu'à n résultats avant de retourner voici un générateur p> et en action p> Nous pouvons comparer les frais généraux, approximativement, en comparant quelque chose qui sait à l'avance combien d'espace est requis p> ici, nous vérifions le calendrier et la valeur d'un résultat unique p> lequel pour cet exemple est bien sûr éclipsé par la simple solution vectorielle p>
La fonction
C code> est utilisée pour étendre les vecteurs ou les listes. Si vous pouvez estimer la taille, alloué avec
vecteur ("entier", taille) code> aidera à réduire le coût de l'extension.
@DWIN existe-t-il des outils existants qui étendent la matrice de manière intelligente, à la demande? (E.G. Double la taille de la matrice préallocée une fois sa capacité atteinte et éviter la complexité quadratique)
@Szabolcs, pourquoi pensez-vous remplacer
C code> avec la liste
code> aiderait ici? À moins que vous préveniez une liste, le même problème persiste, n'est-ce pas?
@Arun Notez que
C code> concaténés (qui déclenche une réaffectation du vecteur) lors de la liste code> code> Je construit une structure comme
Liste (liste (liste (1 ), 2), 3) code>, une liste liée. Lorsqu'il est mis en boucle, ce dernier a une complexité linéaire, le premier a un quadratique. Vous pouvez facilement vérifier cela par un petit repère: doubler le nombre d'éléments à ajouter doublez le temps avec la liste
code> et presque quadruples avec
C code>. Cela signifie que pour un résultat «assez large», la liste code> code> sera toujours plus rapide. Ce que je n'ai pas réalisé quand j'ai écrit la question est que dans ce cas "assez grand" ...
@Arun ... n'est pas impraticement grand. Pour les listes de taille pratique,
C code> sera toujours plus rapide.
@Szabolcs, exécutant votre liste de liste-de -... sur 1E5 Éléments déjà abouti à une erreur
Erreur: Protect () Pile de protection Overflow code>. Pas tout à fait sûr de quelle est la gamme de votre BigBignumber ..
@Arun oui, je viens de le courir aussi et je me suis rendu compte que la complexité n'est pas linéaire. Je ne sais pas pourquoi. Je serais intéressé par la manière de mettre correctement implémenter une liste liée dans R, si possible du tout.
Malheureusement, une liste de liste ici est une liste imbriquée. Il ne semble pas correspondre au paradigme de la liste liée ...
@Arun Pouvez-vous expliquer pourquoi? L'idée est venue de Mathematica (un autre système fonctionnel qui préfère des structures immuables), où le mécanisme de stockage sous-jacent d'une liste imbriquée est également directement correspondant à une liste liée. Une liste Mathematica est stockée comme une gamme de pointeurs à d'autres expressions Mathematica, qui peuvent être répertoriées. Il semble donc que ce soit différent dans R. Pouvez-vous expliquer comment les listes sont stockées dans R (je suis juste curieux, mais cela n'est pas aussi pertinent), et s'il est possible de mettre en œuvre une liste liée du tout (un peu plus pertinente). ?
Pour l'instant, j'espère Cette réponse pourrait aider partiellement à aider, dans ces listes R, sont comme des structures de données de carte de hachage ..
Avez-vous lu l'inferno? Burns-stat.com/pages/Tutor/r_inferno.pdf
@ Romanluštrik je l'ai regardé. C'est l'un des documents que je regarde de temps en temps tout en apprenant. C'est bien. Merci de le pointer.