使用机器学习进行文本标记
Text labeling with machine learning
我想根据一组预定义的 类 标记一堆银行交易(下面的示例,它是 clojure
中的地图)。我尝试了一种朴素的贝叶斯方法,但有时它完全给我错误的标签。
根据我的研究,我应该使用监督 ML 算法,类似于针对多类分类调整的线性 SVM。问题是我真的对机器学习一无所知。第二个问题是大多数 clojure 库都过时了。
{:label "5339134-17-CPR-FARMODISSEIA LD", :value -13271 :class :health}
{:label "PAG.SERV. 10297 779747511", :value -2889 :class :utilities}
{:label "5339134-14-CPR-GREEN PEPER", :value -1785 :class :restaurants}
{:label "5339134-03-LEV-Av Alm Kings", :value -4000 :class :atm}
{:label "5339134-02-LEV-Big Field, 1", :value -7000 :class :atm}
{:label "IMPOSTO DE SELO", :value -17 :class :banking}
所以大多数类似的交易都有90%的相似文本(参见示例::atm
),我相信这应该是一个简单的问题。
我的问题:
- 我可以使用哪些算法?
- 我应该如何准备数据?我相信我只有两个特征,tx 标签和 tx 值。我看到的一些教程有一堆向量,但我不知道 if/how 将字符串数据转换为正确的 ML 格式。
clj 或 java 中的任何示例将不胜感激。
既然你在问题中说过
most of the similar transactions have like 90% similar text
我认为首先找出哪些交易标签彼此相似并将它们组合在一起是有意义的。然后你有有限数量的组,每个标签所属的组可以用作名义属性来代替文本本身。如果同一 class 中的交易具有相似的标签文本,那么希望这应该允许 classification 算法轻松绘制标签与 class.
之间的相关性
我尝试使用这些依赖项实现解决方案:
[[org.clojure/clojure "1.8.0"]
[clj-fuzzy "0.4.0"]
[cc.artifice/clj-ml "0.8.5"]
[rm-hull/clustering "0.1.3"]]
对标签进行聚类后,朴素贝叶斯方法似乎对我很有效:
(require '[clj-fuzzy.metrics :as fm]
'[clj-ml.classifiers :as classify]
'[clj-ml.data :as data]
'[clustering.core.qt :as qt])
(def data
[{:label "5339134-17-CPR-FARMODISSEIA LD", :value -13271 :class :health}
{:label "PAG.SERV. 10297 779747511", :value -2889 :class :utilities}
{:label "5339134-14-CPR-GREEN PEPER", :value -1785 :class :restaurants}
{:label "5339134-03-LEV-Av Alm Kings", :value -4000 :class :atm}
{:label "5339134-02-LEV-Big Field, 1", :value -7000 :class :atm}
{:label "IMPOSTO DE SELO", :value -17 :class :banking}])
(def clusters
(into {}
(for [cluster (qt/cluster fm/levenshtein (map :label data) 13 1)
s cluster]
[s (keyword (str "cluster" (hash cluster)))])))
(def dataset
(-> (data/make-dataset "my-data"
[:value
{:label (seq (set (vals clusters)))}
{:class [:health :utilities :restaurants :atm :banking]}]
(map (juxt :value (comp clusters :label) :class) data))
(data/dataset-set-class :class)))
(def data-map
(let [m (into {} (map (juxt data/instance-to-map identity)
(data/dataset-seq dataset)))]
(into {} (for [x data]
[x (-> x (update :label clusters) (update :value double) m)]))))
(def classifier
(-> (classify/make-classifier :bayes :naive)
(classify/classifier-train dataset)))
(defn foo []
(for [x data]
(->> x
data-map
data/instance-set-class-missing
(classify/classifier-classify classifier)
(assoc x :predicted))))
(run! prn (foo))
;; {:label "5339134-17-CPR-FARMODISSEIA LD", :value -13271, :class :health, :predicted :health}
;; {:label "PAG.SERV. 10297 779747511", :value -2889, :class :utilities, :predicted :utilities}
;; {:label "5339134-14-CPR-GREEN PEPER", :value -1785, :class :restaurants, :predicted :restaurants}
;; {:label "5339134-03-LEV-Av Alm Kings", :value -4000, :class :atm, :predicted :atm}
;; {:label "5339134-02-LEV-Big Field, 1", :value -7000, :class :atm, :predicted :atm}
;; {:label "IMPOSTO DE SELO", :value -17, :class :banking, :predicted :banking}
虽然我对 ML 很陌生,所以如果有什么我忽略的地方请告诉我。
此外,在我的实现中,我使用 QT 聚类对输入数据集中的标签进行一次性分区,但如果目标是随着时间的推移继续合并新数据,则可能需要使用流聚类算法代替。看起来这可能用 k-means 可行,但这需要实现 "Levenshtein averaging" 函数。另外,我不确定我使用的聚类库是否支持基于其初始结果的迭代,因此可能需要进一步实施。
我想根据一组预定义的 类 标记一堆银行交易(下面的示例,它是 clojure
中的地图)。我尝试了一种朴素的贝叶斯方法,但有时它完全给我错误的标签。
根据我的研究,我应该使用监督 ML 算法,类似于针对多类分类调整的线性 SVM。问题是我真的对机器学习一无所知。第二个问题是大多数 clojure 库都过时了。
{:label "5339134-17-CPR-FARMODISSEIA LD", :value -13271 :class :health}
{:label "PAG.SERV. 10297 779747511", :value -2889 :class :utilities}
{:label "5339134-14-CPR-GREEN PEPER", :value -1785 :class :restaurants}
{:label "5339134-03-LEV-Av Alm Kings", :value -4000 :class :atm}
{:label "5339134-02-LEV-Big Field, 1", :value -7000 :class :atm}
{:label "IMPOSTO DE SELO", :value -17 :class :banking}
所以大多数类似的交易都有90%的相似文本(参见示例::atm
),我相信这应该是一个简单的问题。
我的问题:
- 我可以使用哪些算法?
- 我应该如何准备数据?我相信我只有两个特征,tx 标签和 tx 值。我看到的一些教程有一堆向量,但我不知道 if/how 将字符串数据转换为正确的 ML 格式。
clj 或 java 中的任何示例将不胜感激。
既然你在问题中说过
most of the similar transactions have like 90% similar text
我认为首先找出哪些交易标签彼此相似并将它们组合在一起是有意义的。然后你有有限数量的组,每个标签所属的组可以用作名义属性来代替文本本身。如果同一 class 中的交易具有相似的标签文本,那么希望这应该允许 classification 算法轻松绘制标签与 class.
之间的相关性我尝试使用这些依赖项实现解决方案:
[[org.clojure/clojure "1.8.0"]
[clj-fuzzy "0.4.0"]
[cc.artifice/clj-ml "0.8.5"]
[rm-hull/clustering "0.1.3"]]
对标签进行聚类后,朴素贝叶斯方法似乎对我很有效:
(require '[clj-fuzzy.metrics :as fm]
'[clj-ml.classifiers :as classify]
'[clj-ml.data :as data]
'[clustering.core.qt :as qt])
(def data
[{:label "5339134-17-CPR-FARMODISSEIA LD", :value -13271 :class :health}
{:label "PAG.SERV. 10297 779747511", :value -2889 :class :utilities}
{:label "5339134-14-CPR-GREEN PEPER", :value -1785 :class :restaurants}
{:label "5339134-03-LEV-Av Alm Kings", :value -4000 :class :atm}
{:label "5339134-02-LEV-Big Field, 1", :value -7000 :class :atm}
{:label "IMPOSTO DE SELO", :value -17 :class :banking}])
(def clusters
(into {}
(for [cluster (qt/cluster fm/levenshtein (map :label data) 13 1)
s cluster]
[s (keyword (str "cluster" (hash cluster)))])))
(def dataset
(-> (data/make-dataset "my-data"
[:value
{:label (seq (set (vals clusters)))}
{:class [:health :utilities :restaurants :atm :banking]}]
(map (juxt :value (comp clusters :label) :class) data))
(data/dataset-set-class :class)))
(def data-map
(let [m (into {} (map (juxt data/instance-to-map identity)
(data/dataset-seq dataset)))]
(into {} (for [x data]
[x (-> x (update :label clusters) (update :value double) m)]))))
(def classifier
(-> (classify/make-classifier :bayes :naive)
(classify/classifier-train dataset)))
(defn foo []
(for [x data]
(->> x
data-map
data/instance-set-class-missing
(classify/classifier-classify classifier)
(assoc x :predicted))))
(run! prn (foo))
;; {:label "5339134-17-CPR-FARMODISSEIA LD", :value -13271, :class :health, :predicted :health}
;; {:label "PAG.SERV. 10297 779747511", :value -2889, :class :utilities, :predicted :utilities}
;; {:label "5339134-14-CPR-GREEN PEPER", :value -1785, :class :restaurants, :predicted :restaurants}
;; {:label "5339134-03-LEV-Av Alm Kings", :value -4000, :class :atm, :predicted :atm}
;; {:label "5339134-02-LEV-Big Field, 1", :value -7000, :class :atm, :predicted :atm}
;; {:label "IMPOSTO DE SELO", :value -17, :class :banking, :predicted :banking}
虽然我对 ML 很陌生,所以如果有什么我忽略的地方请告诉我。
此外,在我的实现中,我使用 QT 聚类对输入数据集中的标签进行一次性分区,但如果目标是随着时间的推移继续合并新数据,则可能需要使用流聚类算法代替。看起来这可能用 k-means 可行,但这需要实现 "Levenshtein averaging" 函数。另外,我不确定我使用的聚类库是否支持基于其初始结果的迭代,因此可能需要进一步实施。