我有两个csv文件,文件F1中有大约22K条记录,文件F2中有50条记录,两条文件都包含公司名称和地址信息。我需要在名称,地址和电话上进行模糊匹配。 F1中的每条记录都需要与F2中的每条记录进行模糊匹配。我已经制作了第三个文件R3,它是一个包含模糊匹配规则的csv,其中F1列到F2列,具有模糊容差级别。我试图用for循环这样做 -
(for [j f1-rows
h f2-rows
r r3-rows
:while (match-row j h r)]
(merge j h))
(defn match-row [j h rules]
(every?
identity
(map (fn [rule]
(<= (fuzzy/jaccard
((keyword (first rule)) j)
((keyword (second rule)) h))
((nth rule 2))))
rules)))
f1-rows和f2-rows是map的集合。规则是包含来自f1,f2的列名和容差级别的序列的集合。代码正在运行并按预期运行。但我的问题是,执行大约需要2个小时。我读到了传感器如何通过消除中间块来帮助提高性能,但我无法想象我将如何应用于我的情况。关于如何让这更好/更快的任何想法?
答案 0 :(得分:5)
:while
vs :when
在这种情况下,您使用:while
似乎不符合您声明的问题。当match-row
为真时,你的for-expression将继续运行,并在第一个错误结果时完全停止。 :when
将迭代所有组合,并且仅包含{* 1}}在生成的lazy-seq中为真的那些组合。区别在于here.
例如:
match-row
你的代码运行2个小时真的很奇怪,因为这意味着在这两个小时内,(for [i (range 10)
j (range 10)
:while (= i j)]
[i j]) ;=> ([0 0])
(for [i (range 10)
j (range 10)
:when (= i j)]
[i j]) ;=> ([0 0] [1 1] [2 2] [3 3] [4 4] [5 5] [6 6] [7 7] [8 8] [9 9])
的每次调用都返回true,只有最后一个返回false。我会再次检查结果,看看它是否真的有意义。
让我们先做一些背后的数学计算。如果你想将22k记录中的每一个与55k记录中的每一个进行比较,那么你将进行22k * 55k的比较,没有办法解决这个问题。
22k * 55k = 1,210,000,000
这是一个很大的数字!
比较的成本是多少?
从维基百科的半分钟看,jaccard是关于集合的东西。 以下将对成本进行估算,尽管它可能非常低端。
(match-row j h r)
在我的电脑上花了大约十分之一毫秒。
(time (clojure.set/difference (set "foo") (set "bar")))
那是33个半小时。这是对个人成本的低端估计,而不是计算每个人(?)上的名称,地址和电话比较的事实。因此,如果每个比较在第一行失败,则为33小时,如果它们都到达最后一行,则为99小时。
在进行任何微优化之前,您需要通过找到一些不需要进行超过十亿次比较的巧妙方法来处理算法。如果您需要帮助,至少需要提供一些样本数据。
(/ (* 22e3 55e3) ;; Number of comparisons.
10 ; milliseconds
1000 ;seconds
60 ;minutes
60) ;hours
;=> 33.611111111111114
内的anon fn的缩进令人困惑。我会使用一个自动缩进的编辑器,并坚持99%的时间,因为lisp程序员通过缩进读取嵌套,如python。编辑器/自动编辑器之间存在一些细微的差别,但它们都与嵌套一致。
match-row
此外,(defn match-row [j h rules]
(every?
identity
(map (fn [rule]
(<= (fuzzy/jaccard
((keyword (first rule)) j)
((keyword (second rule)) h))
((nth rule 2))))
rules)))
需要在使用之前定义(它可能在您的实际代码中,在编译时看到)。
答案 1 :(得分:0)
22k x 50k超过10亿种组合。乘以3个模糊规则&amp;你的计算量是30亿。其中大部分是浪费。
加快速度的唯一方法是对所有组合进行一些预分类或其他预修剪。例如,如果zipcodes是相同的,则只进行模糊计算。如果你浪费时间试图匹配N.Y.和佛罗里达州的人,你就会丢掉99%或更多的工作