2010-07-13 3 views
8

У меня проблема: У меня есть временной ряд с более чем 10000 записей, и я хочу выполнить некоторые вычисления с каждым из них. Это само по себе не будет проблемой, но мне нужно получить последнее рассчитанное значение, чтобы получить следующий. Очень простая форма того, что я должен был бы выглядеть следующим образом:Проблема с итерацией по временному ряду в clojure

Val(n) = Val(n-1) + (time-series-entry/2) (! Или что-то вроде этого)

Я не имею ни малейшего представления, как управлять этим. Просто делать что-то вроде этого:

(defn calc-val 
    [time-series element] 
    (seq (cons (generate-val-element time-series element) 
      (calc-val time-series (inc element))))) 

не будет работать, потому что не может (по крайней мере, я не знаю, как!) Получить последнее вычисленное значение. Тогда я подумал: «Хорошо, давайте использовать Loop-Recur. Это дало бы мне значение, соответствующее записи временного ряда, но для следующего я должен был бы снова выполнить все вычисления. Iterate будет правильным, но это не сработало, потому что функция имеет побочные эффекты.

Так что я застрял здесь на этом. Было бы здорово, если бы кто-нибудь мог дать мне подсказку.

ответ

3

Если вам просто нужен намек; посмотрите на использование partition.

Для немного больше, чем намек ...

(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)] 
     (do whatever you need to here))))) 

Хотя это не был проверен, он должен работать или быть близко к работе :)

Пояснение

(partition n i seq) разделяет seq на части, которые содержат списки длины n (2 в этом случае) с перекрытием i (1 в этом случае), а затем мы перебираем их с помощью for и делаем то, что хотим с частями.

+0

Если я правильно понять вопрос, результат преобразования на каждом шаге зависит от результата преобразования на предыдущем шаге - а не от предыдущей нетрансформированной записи. Таким образом, косвенно это зависит от всего исходного фрагмента серии seq, предшествующего ему. (В надежде, что OP будет исправлена, если я ошибаюсь. :-)) –

+0

Если это так, абсолютно. Я понял это по-другому (поскольку его императивный пример сделал это иначе), но я счастлив, что ошибаюсь или прав! В любом случае, он в хороших руках;) – Isaac

+0

Кажется, мне тоже. Здесь мы надеемся, что он согласен. :-) –

7

Если вас интересует только конечный результат, используйте reduce; если вам нужно получить результаты преобразования каждого значения по очереди (где каждое преобразование зависит от предыдущих), используйте reductions (найдено в clojure.contrib.seq-utils в 1.1 и в clojure.core в 1.2).

Ниже transform-first-entry делает все, что вы хотите сделать первую запись (если вам не нужно, чтобы преобразовать его в любом случае, вы можете просто оставить свой первый аргумент reduce/reductions и использовать entries, а не (rest entries, как последний аргумент); transform-entry - это функция, которая принимает результат преобразования предыдущей записи и текущей записи (в этом порядке) и создает результат преобразования для текущей записи.

;;; only care about the final result 
(reduce transform-entry 
     (transform-first-entry (first series)) 
     (rest entries)) 

;;; need to get a seq of intermediate results 
(reductions ...arguments as above...) 

Отметьте, что reductions является ленивым.

Предполагая, что вы хотели, чтобы оставить первую запись без изменений и применить пример преобразования из текста вопроса на последующие записи, вы можете использовать

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

как функция восстановления в

(reduce transform-entry series) ; ...or reductions 
Смежные вопросы