gpt4 book ai didi

recursion - 学习Clojure : recursion for Hidden Markov Model

转载 作者:行者123 更新时间:2023-12-05 00:21:47 27 4
gpt4 key购买 nike

我正在学习 Clojure 并从复制 Python 程序的功能开始,该程序将通过遵循(非常简单的)隐马尔可夫模型来创建基因组序列。

一开始,我坚持使用我已知的串行编程方式并大量使用 def 关键字,从而解决了具有大量副作用的问题,几乎将 Clojure 的每个概念都放在了屁股上。 (虽然它按预期工作)

然后我尝试将其转换为更实用的方式,使用循环、递归、原子等。现在,当我运行时,我得到了一个 ArityException,但我无法以一种方式读取错误消息,甚至无法显示哪个函数抛出它。

(defn create-model [name pA pC pG pT pSwitch]
; converts propabilities to cumulative prop's and returns a char
(with-meta
(fn []
(let [x (rand)]
(if (<= x pA)
\A
(if (<= x (+ pA pC))
\C
(if (<= x (+ pA pC pG))
\G
\T))))) ; the function object
{:p-switch pSwitch :name name})) ; the metadata, used to change model


(defn create-genome [n]
; adds random chars from a model to a string and switches models randomly
(let [models [(create-model "std" 0.25 0.25 0.25 0.25 0.02) ; standard model, equal props
(create-model "cpg" 0.1 0.4 0.4 0.1 0.04)] ; cpg model
islands (atom 0) ; island counter
m (atom 0)] ; model index
(loop [result (str)]
(let [model (nth models @m)]
(when (< (rand) (:p-switch (meta model))) ; random says "switch model!"
; (swap! m #(mod (inc @m) 2)) ; swap model used in next iteration
(swap! m #(mod (inc %) 2)) ; EDIT: correction
(if (= @m 1) ; on switch to model 1, increase island counter
; (swap! islands #(inc @islands)))) ; EDIT: my try, with error
(swap! islands inc)))) ; EDIT: correction
(if (< (count result) n) ; repeat until result reaches length n
(recur (format "%s%c" result (model)))
result)))))

运行它有效,但调用 (create-genome 1000) 会导致
ArityException Wrong number of args (1) passed to: user/create-genome/fn--772  clojure.lang.AFn.throwArity (AFn.java:429)

我的问题:
  • (显然)我做错了什么?
  • 我究竟该如何理解错误信息?

  • 我很乐意收到的信息
  • 如何改进代码(以 clojure-newb 可以理解的方式)?还有不同的范式 - 我很感激你的建议。
  • 为什么我需要在改变原子状态的形式之前加上井号#?我在一个例子中看到了这个,没有它这个函数不会评估,但我不明白:)
  • 最佳答案

    既然你问了改进的方法,这是我经常发现自己要去的一种方法:我可以抽象这个loop进入更高阶的模式?

    在这种情况下,您的循环随机选择字符 - 这可以建模为调用返回一个字符的无参数 fn - 然后将它们累加在一起,直到有足够的字符为止。这非常适合 repeatedly ,它采用这样的函数,并将其结果的惰性序列制作成您想要的任何长度。

    然后,因为您将整个字符序列放在一起,您可以将它们连接成一个字符串比重复 format 更有效一点。 s - clojure.string/join应该很合身,或者你可以 apply str超过它。

    这是我对这种代码形状的尝试 - 我还尝试使其完全由数据驱动,这可能导致它有点神秘,所以请耐心等待:

    (defn make-generator 
    "Takes a probability distribution, in the form of a map
    from values to the desired likelihood of that value appearing in the output.
    Normalizes the probabilities and returns a nullary producer fn with that distribution."
    [p-distribution]
    (let[sum-probs (reduce + (vals p-distribution))
    normalized (reduce #(update-in %1 [%2] / sum-probs) p-distribution (keys p-distribution) )]
    (fn [] (reduce
    #(if (< %1 (val %2)) (reduced (key %2)) (- %1 (val %2)))
    (rand)
    normalized))))

    (defn markov-chain
    "Takes a series of states, returns a producer fn.
    Each call, the process changes to the next state in the series with probability :p-switch,
    and produces a value from the :producer of the current state."
    [states]
    (let[cur-state (atom (first states))
    next-states (atom (cycle states))]
    (fn []
    (when (< (rand) (:p-switch @cur-state))
    (reset! cur-state (first @next-states))
    (swap! next-states rest))
    ((:producer @cur-state)))))


    (def my-states [{:p-switch 0.02 :producer (make-generator {\A 1 \C 1 \G 1 \T 1}) :name "std"}
    {:p-switch 0.04 :producer (make-generator {\A 1 \C 4 \G 4 \T 1}) :name "cpg"}])


    (defn create-genome [n]
    (->> my-states
    markov-chain
    (repeatedly n)
    clojure.string/join))

    希望能解释一些复杂性:
  • letmake-generator只是确保概率总和为 1。
  • make-generator大量使用另一种高阶循环模式,即 reduce .这本质上需要一个包含 2 个值的函数,并通过它线程化一个集合。 (reduce + [4 5 2 9])就像 (((4 + 5) + 2) + 9)。我主要用它来做与您嵌套的 if 类似的事情s 在 create-model ,但没有指明概率分布中有多少个值。
  • markov-chain形成两个原子,cur-state保持当前状态和 next-states ,它包含要切换到的下一个状态的无限序列(来自 cycle )。这就像您的 m 一样工作和 models ,但对于任意数量的状态。
  • 然后我使用 when检查随机状态切换是否应该发生,如果它确实执行了两个副作用,我需要保持状态原子是最新的。然后我只是不带参数地调用@cur-state 的 :producer 并返回它。

  • 现在很明显,您不必完全按照这种方式执行此操作,但是寻找这些模式肯定会帮助我。
    如果您想要更多功能,您还可以考虑转向一种设计,其中您的生成器采用一个状态(带有种子随机数生成器)并返回一个值加上一个新状态。这种“状态 monad”方法将使完全声明性成为可能,而本设计则不然。

    关于recursion - 学习Clojure : recursion for Hidden Markov Model,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31046044/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com