Clojure CSV 匹配文件
Clojure CSV Matching Files
我有 2 个 csv 文件,文件 F1 中有大约 22K 条记录,文件 F2 中有 50K 条记录,都包含公司名称和地址信息。我需要对姓名、地址和 phone 进行模糊匹配。 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 是地图的集合。规则是包含来自 f1、f2 和容差级别的列名称的序列集合。代码是 运行 并且按预期运行。但我的问题是,执行大约需要 2 个小时。我阅读了转换器如何通过消除中间块来帮助提高性能,但我无法想象我将如何在我的案例中应用它。关于如何制作这个 better/faster 有什么想法吗?
22k x 50k 超过 10 亿种组合。乘以 3 个模糊规则,您将进行 30 亿次计算。其中大部分都被浪费了。
加快速度的唯一方法是对所有组合进行一些预排序或其他预修剪。例如,只有邮政编码相同时才进行模糊计算。如果您浪费时间尝试匹配来自 N.Y 的人。和佛罗里达州,您将放弃 99% 或更多的工作
:while
对比 :when
您在这种情况下对 :while
的使用似乎与您陈述的问题不符。当 match-row
为真时,您的 for 表达式将继续运行,并在第一个错误结果处完全停止。 :when
将遍历所有组合,并仅包括 match-row
在生成的惰性序列中为真的组合。差异解释here.
例如:
(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])
您的代码将 运行 保持 2 小时,这真的很奇怪,因为这意味着在这两个小时内,对 (match-row j h r)
的每次调用都返回 true,只有最后一个返回 false。我会再次检查结果,看看它是否真的有意义。
需要多长时间?
让我们先做一些纸巾背面的数学运算。如果您想将 22k 条记录中的每条记录与 55k 条记录中的每条记录进行比较,您将进行 22k * 55k 比较,这是没有办法的。
22k * 55k = 1,210,000,000
这是一个很大的数字!
比较的费用是多少?
在维基百科上浏览半分钟后,jaccard 是关于集合的。
以下将对成本进行粗略估计,尽管它可能非常低端。
(time (clojure.set/difference (set "foo") (set "bar")))
这在我的计算机上大约需要十分之一毫秒。
(/ (* 22e3 55e3) ;; Number of comparisons.
10 ; milliseconds
1000 ;seconds
60 ;minutes
60) ;hours
;=> 33.611111111111114
那是 33 个半小时。这是对个人成本的低端估计,还没有计算你想要比较姓名、地址和 phone 的事实(?)。因此,如果每次比较都在第一行失败,则需要 33 小时,如果它们都到达最后一行,则需要 99 小时。
在进行任何微优化之前,您需要研究算法,找到一些不需要进行超过十亿次比较的聪明方法。如果您需要这方面的帮助,您至少需要提供一些示例数据。
吹毛求疵
match-row
中 anon fn 的缩进令人困惑。我会使用一个自动缩进的编辑器,并坚持 99% 的时间,因为 lisp 程序员通过缩进读取嵌套,比如 python。 editors/autoindenters之间略有不同,但都符合嵌套。
(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)))
此外,match-row
需要在使用前定义(它可能在您的实际代码中,在编译时看到)。
我有 2 个 csv 文件,文件 F1 中有大约 22K 条记录,文件 F2 中有 50K 条记录,都包含公司名称和地址信息。我需要对姓名、地址和 phone 进行模糊匹配。 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 是地图的集合。规则是包含来自 f1、f2 和容差级别的列名称的序列集合。代码是 运行 并且按预期运行。但我的问题是,执行大约需要 2 个小时。我阅读了转换器如何通过消除中间块来帮助提高性能,但我无法想象我将如何在我的案例中应用它。关于如何制作这个 better/faster 有什么想法吗?
22k x 50k 超过 10 亿种组合。乘以 3 个模糊规则,您将进行 30 亿次计算。其中大部分都被浪费了。
加快速度的唯一方法是对所有组合进行一些预排序或其他预修剪。例如,只有邮政编码相同时才进行模糊计算。如果您浪费时间尝试匹配来自 N.Y 的人。和佛罗里达州,您将放弃 99% 或更多的工作
:while
对比 :when
您在这种情况下对 :while
的使用似乎与您陈述的问题不符。当 match-row
为真时,您的 for 表达式将继续运行,并在第一个错误结果处完全停止。 :when
将遍历所有组合,并仅包括 match-row
在生成的惰性序列中为真的组合。差异解释here.
例如:
(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])
您的代码将 运行 保持 2 小时,这真的很奇怪,因为这意味着在这两个小时内,对 (match-row j h r)
的每次调用都返回 true,只有最后一个返回 false。我会再次检查结果,看看它是否真的有意义。
需要多长时间?
让我们先做一些纸巾背面的数学运算。如果您想将 22k 条记录中的每条记录与 55k 条记录中的每条记录进行比较,您将进行 22k * 55k 比较,这是没有办法的。
22k * 55k = 1,210,000,000
这是一个很大的数字!
比较的费用是多少?
在维基百科上浏览半分钟后,jaccard 是关于集合的。 以下将对成本进行粗略估计,尽管它可能非常低端。
(time (clojure.set/difference (set "foo") (set "bar")))
这在我的计算机上大约需要十分之一毫秒。
(/ (* 22e3 55e3) ;; Number of comparisons.
10 ; milliseconds
1000 ;seconds
60 ;minutes
60) ;hours
;=> 33.611111111111114
那是 33 个半小时。这是对个人成本的低端估计,还没有计算你想要比较姓名、地址和 phone 的事实(?)。因此,如果每次比较都在第一行失败,则需要 33 小时,如果它们都到达最后一行,则需要 99 小时。
在进行任何微优化之前,您需要研究算法,找到一些不需要进行超过十亿次比较的聪明方法。如果您需要这方面的帮助,您至少需要提供一些示例数据。
吹毛求疵
match-row
中 anon fn 的缩进令人困惑。我会使用一个自动缩进的编辑器,并坚持 99% 的时间,因为 lisp 程序员通过缩进读取嵌套,比如 python。 editors/autoindenters之间略有不同,但都符合嵌套。
(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)))
此外,match-row
需要在使用前定义(它可能在您的实际代码中,在编译时看到)。