我正在尝试读取 CSV 文件并将其解析为向量图。因此,映射的键是 CSV 中的列名称,映射的值是包含 CSV 中的值列的向量。
我使用内置函数clojure.data.csv
来读取文件,尽管 CSV 文件(在此处找到)只有 32 MB,但我的代码运行速度确实相当慢。
(require '[clojure.data.csv :as csv]
'[clojure.java.io :as io])
(defn csv->df [file-path]
(with-open [reader (io/reader file-path)]
(let [in-file (csv/read-csv reader)
names (first in-file)
data (rest in-file)]
(zipmap (map keyword names) (apply mapv vector data)))))
(csv->df "data/flights.csv")
我怀疑我正在做一些与惰性序列相关的愚蠢的事情,因为作为 Clojure 新手,我仍然在掌握它们,但我无法确定问题的根本原因。
是否可以重组此功能,使其运行速度不至于缓慢?
您不会从懒惰中受益,因为转置矩阵(这就是
apply map vector
正在做的事情)不能偷懒。但你并没有做任何特别错误的事情。read-csv
在我的机器上进行的测试中,调用该文件并迭代结果所需的时间是 9 秒。你的函数大约需要两倍的时间。因此,您的处理速度并不快,但如果您以某种方式设法在零时间内完成所有后处理,那么您所希望的最好结果是整个过程加速 50%。我认为如果您使用 clojure.data.csv,这些成本是不可避免的。将内容打包到整洁的 Clojure 数据结构中非常方便,但它并不是免费的。我尝试使用 FastCSV 进行比较:读取并丢弃整个文件的速度大约快 20 倍,并且从文件生成向量=向量的速度也同样快。转置仍然很慢,但整个过程只需 5 秒,而不是您的函数的 17 秒。这是我写的:不灵活且笨重,但它产生相同的结果并且足够简单。如果性能确实很重要,您可以融合转置步骤,从不构建行向量,而是为每列维护一个单独的向量,并为遇到的每一行更新每个向量。
这就是TMD的目的。
这在 2.5 秒内构建了数据集,其中从互联网下载数据集大约需要 1 秒。
而且,如您所愿,TMD 数据集在逻辑上是列名称到列数据的映射:
而且,作为奖励(如您所见),数据是有类型的 - 年份列是 336776 个原始 Java 16 位
int
。这将占用更少的内存。