需要在Clojure中的函数末尾重新分配变量的值
我是Clojure世界和函数式编程的新手。我试图编写一个函数,计算给定一个词汇表(只是一个词汇表)和一组概率(每个单词出现的概率)的特定单词列表出现的概率。我使用一个简化的单词袋模型,假设每个结果都是独立的 例如,假设:需要在Clojure中的函数末尾重新分配变量的值,clojure,functional-programming,nlp,Clojure,Functional Programming,Nlp,我是Clojure世界和函数式编程的新手。我试图编写一个函数,计算给定一个词汇表(只是一个词汇表)和一组概率(每个单词出现的概率)的特定单词列表出现的概率。我使用一个简化的单词袋模型,假设每个结果都是独立的 例如,假设: 词汇(相关概率):睡眠(0.3),狗(0.09),a(0.2),牛(0.05),牛(0.17),船(0.04),一切(0.15) 句子:(列出“狗”船) 我想让它计算(0.05)*(0.09)*(0.04)=0.00018 我已经有了一个函数,它可以获取每个单词的概率,并且
- 词汇(相关概率):睡眠(0.3),狗(0.09),a(0.2),牛(0.05),牛(0.17),船(0.04),一切(0.15)
- 句子:
(列出“狗”船)
(defn lookup-probability [w outcomes probs]
(if (not= w (first outcomes)) ;;if the current element is not equal to the word we're looking for...
(lookup-probability w (rest outcomes) (rest probs)) ;;...keep cycling through the vocabulary
(first probs) ;;once we find the right word, fetch the corresponding entry in the probability list
)
)
以下是我感到困惑的部分:
(def sentenceprobs '()) ;;STEP 1
(defn compute-BOW-prob [sentence vocabulary probabilities]
(if (not(empty? sentence))
(def sentenceprobs (conj sentenceprobs (lookup-probability (first sentence) vocabulary probabilities)) ;;STEP 2
(compute-BOW-prob (rest sentence) vocabulary probabilities) ;;STEP 3
)
(product sentenceprobs) ;;STEP 4 (the product function just multiplies all the elements of a list together)
)
)
以下是我的总体策略:
(def sentenceprobs '())
(defn compute-BOW-prob [sentence vocabulary probabilities]
(if (not(empty? sentence))
(def sentenceprobs (conj sentenceprobs (lookup-probability (first sentence) vocabulary probabilities))
(compute-BOW-prob (rest sentence) vocabulary probabilities)
)
(product sentenceprobs)
)
(def sentenceprobs '()) ;; <---THIS IS WHAT I ADDED
)
(def sentenceprobs'())
(defn compute BOW prob[句子词汇概率]
(如果(不是(空句))
(def sentenceprobs(conj sentenceprobs(查找概率(第一句话)词汇概率))
(计算BOW prob(休息句)词汇概率)
)
(产品语句问题)
)
(def sentenceprobs'());;请看。它显示了我如何组织一个项目(只需克隆存储库并开始编码!)。特别是研究Clojure和命令式语言之间的差异
我会通过使用映射来保存概率来解决这个问题。然后,您可以使用mapv
(或只是map
)将问题从映射中拉到向量(或列表)中。然后使用(apply*…)
计算乘积:
(ns tst.demo.core
(:use tupelo.test)
(:require
[tupelo.core :as t]))
(def prob-map
{:sleep 0.3
:dog 0.09,
:a 0.2,
:the 0.05,
:cow 0.17,
:boat 0.04,
:everything 0.15})
(defn calc-prob
[words]
(let [probs (mapv #(get prob-map %) words)]
(apply * probs)))
(dotest
(let [sentence [:the :dog :boat]
result (calc-prob sentence)
expected (t/spyx (* 0.05 0.09 0.04)) ; spyx displays the value
]
(is (t/rel= result expected :digits 8))))
您可以通过以下方式运行它:
> lein clean
> lein test
要产生输出:
--------------------------------------
Clojure 1.10.2-alpha1 Java 15
--------------------------------------
Testing tst.demo.core
(* 0.05 0.09 0.04) => 1.7999999999999998E-4
Ran 2 tests containing 1 assertions.
0 failures, 0 errors.
在Alan的回答的基础上构建一点。在这种情况下,你有一个值列表(一个句子中的单词),你想计算一个聚合(根据之前的概率计算,所有这些单词同时出现的概率)。我假设你像Alan一样构建了概率表(虽然我使用字符串而不是关键字作为键)
要执行聚合,我们将使用reduce
,它允许您将集合折叠为单个值。它使用一个函数来完成此操作,该函数接受一个累加器和一个值,并将其应用于集合中的所有元素
代码如下所示:
(def prob-map
{"sleep" 0.3
"dog" 0.09,
"a" 0.2,
"the" 0.05,
"cow" 0.17,
"boat" 0.04,
"everything" 0.15})
(defn compute-BOW-prob [probs sentence]
(reduce (fn [acc word]
(* acc (get probs word 1)))
1
(clojure.string/split sentence #"\s")))
(compute-BOW-prob prob-map "the dog boat")
;; => 1.7999999999999998E-4
它本质上与Alan的解决方案相同,但它没有一个单独的步骤来乘以概率(这也为您节省了一个中间列表,在本例中这很可能不是问题,但如果您有非常大的输入,则可能是)
上面的代码将概率图和一个句子作为输入。然后它拆分句子(我只是使用空格作为分隔符,但您可以根据需要添加标点符号和停止词),并使用提供的函数在列表中进行缩减。该函数使用累加器(acc
)和列表中的一个元素(word
),并将累加器乘以该单词的概率(或1,如果找不到该单词……当然,您可以采取不同的方法来处理)。函数下方的1
是acc
将采用的初始值
这有助于澄清你的想法!
一般来说,您根本不需要修改变量,并且绝对不应该在函数内部使用def
。此外,尽量避免显式使用全局变量,并让函数将其作为参数。正如您所提到的,这不是使用def
的方法。您可以尝试创建一个列表,然后在om多个断开连接的函数调用。这是命令式语言的方式,而不是函数式语言的方式。在这里,我们宁愿匿名创建一个列表,并将其作为函数的返回值传递
(defn comp-bow [sentence vocabulary probabilities]
(if (not (empty? sentence))
(* (comp-bow (rest sentence) vocabulary probabilities)
(lookup-probability (first sentence) vocabulary probabilities))
1))
我试着运行您的代码,但是computebow prob
没有编译,所以我不确定您希望它如何工作
无论如何,这里有一些改进点给你
在第一个版本中,我尝试对原始设计进行尽可能少的修改(def
)。
在您的设计中,您尝试仅在基本情况下返回产品(空句)。对于递归函数来说,这不是一个好的设计,它们应该始终返回相同类型的值。在comp bow
中,这可以通过基本情况返回1和在调用函数中不断增加概率来解决
(defn comp-bow [sentence vocabulary probabilities]
(if (not (empty? sentence))
(* (comp-bow (rest sentence) vocabulary probabilities)
(lookup-probability (first sentence) vocabulary probabilities))
1))
我不知道你是否熟悉let
。这是你在Clojure中分配东西的最后一步,分配只存在于let
列表中。
此设计与您的设计非常相似,因为它创建了概率列表,并且只在最后执行乘法。(我使用apply*
而不是产品(defn comp-bow3 [sentence vocabulary probabilities]
(comp-bow3-sub sentence vocabulary probabilities 1))
(defn comp-bow3-sub [sentence vocabulary probabilities product]
(if (empty? sentence)
product
(recur (rest sentence) vocabulary probabilities
(* product (lookup-probability (first sentence) vocabulary probabilities)))))