8 votes

Problème avec l'itération sur une série temporelle en Clojure

J'ai le problème suivant : J'ai une série temporelle avec plus de 10000 entrées et je veux effectuer quelques calculs avec chacune d'entre elles. Cela ne serait pas un problème en soi, mais j'ai besoin d'obtenir la dernière valeur calculée afin d'obtenir la suivante. Une forme très simple de ce dont j'ai besoin ressemblerait à ceci :

Val(n) = Val(n-1) + (entrée de la série temporelle / 2) (ou quelque chose comme ça !)

Je n'ai aucune idée de comment gérer cela. Simplement en faisant quelque chose comme ceci :

(defn calc-val
  [série temporelle élément]
  (seq (cons (générer-élément-de-val série temporelle élément)
             (calc-val série temporelle (inc élément)))))

ne fonctionnerait pas car je ne peux pas (ou du moins je ne sais pas comment !) obtenir la dernière valeur calculée. Ensuite, je me suis dit : OK, utilisons Loop-Recur. Cela me donnerait la valeur correspondant à l'entrée de la série temporelle MAIS pour la suivante, je devrais refaire tous les calculs. Iterate serait la bonne chose, mais cela n'a pas fonctionné car la fonction a des effets secondaires.

Donc je suis bloqué sur celui-ci. Ce serait génial si quelqu'un pouvait me donner un indice.

7voto

Michał Marczyk Points 54179

Si vous vous souciez uniquement du résultat final, utilisez reduce; si vous avez besoin d'obtenir une séquence de résultats de transformation de chaque valeur à tour de rôle (où chaque transformation dépend des précédentes), utilisez reductions (trouvé dans clojure.contrib.seq-utils en 1.1 et dans clojure.core en 1.2).

ci-dessous, transform-first-entry fait ce que vous voulez faire au premier élément (si vous n'avez pas besoin de le transformer de quelque manière que ce soit, vous pouvez simplement laisser de côté le premier argument de reduce / reductions et utiliser entries plutôt que (rest entries comme argument final); transform-entry est la fonction qui prend le résultat de la transformation de l'entrée précédente et l'entrée actuelle (dans cet ordre) et produit le résultat de transformation pour l'entrée actuelle.

;;; se soucier uniquement du résultat final
(reduce transform-entry
        (transform-first-entry (first series))
        (rest entries))

;;; besoin d'obtenir une séquence de résultats intermédiaires
(reductions ...arguments comme ci-dessus...)

Remarquez que reductions est paresseux.

En supposant que vous vouliez laisser le premier élément inchangé et appliquer votre transformation d'exemple à partir du texte de la question aux entrées suivantes, vous pourriez utiliser

(defn transform-entry [prev-transformed current]
  (+ prev-transformed
     (/ current 2)))

comme fonction de réduction dans

(reduce transform-entry series) ; ...ou reductions

3voto

Isaac Points 6327

Si vous voulez juste un indice, regardez comment utiliser partition.

Pour un peu plus qu'un indice

(defn calc-val
  [time-series element]
  (let [p (partition 2 1 time-series)]
    (for [t p]
      (let [first-value (first t)
            second-value (second t)]
        (faire ce que vous devez ici)))))

Bien que cela n'ait pas été testé, cela devrait fonctionner ou être proche de la solution :)

Explication

(partition n i seq) sépare seq en parties qui sont des listes d'une longueur de n (2 dans ce cas) avec un chevauchement de i (1 dans ce cas), puis nous itérons sur celles-ci avec for et faisons ce que nous voulons avec les parties.

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