3

我实现了一个函数,它将给定输入集合的 n-gram 作为惰性序列返回。

(defn gen-ngrams
  [n coll]
  (if (>= (count coll) n)
    (lazy-seq (cons (take n coll) (gen-ngrams n (rest coll))))))

当我用更大的输入集合调用这个函数时,我希望看到执行时间线性增加。但是,我观察到的时机比这更糟:

user> (time (count (gen-ngrams 3 (take 1000 corpus))))
"Elapsed time: 59.426 msecs"
998
user> (time (count (gen-ngrams 3 (take 10000 corpus))))
"Elapsed time: 5863.971 msecs"
9998
user> (time (count (gen-ngrams 3 (take 20000 corpus))))
"Elapsed time: 23584.226 msecs"
19998
user> (time (count (gen-ngrams 3 (take 30000 corpus))))
"Elapsed time: 54905.999 msecs"
29998
user> (time (count (gen-ngrams 3 (take 40000 corpus))))
"Elapsed time: 100978.962 msecs"
39998

corpus是一个Cons字符串标记。

是什么导致了这种行为,我该如何提高性能?

4

2 回答 2

5

我认为您的问题与“(count coll)”有关,它在每次调用 ngram 时遍历 coll。

解决方案是使用内置分区函数:

user=> (time (count (gen-ngrams 3 (take 20000 corpus))))
"Elapsed time: 6212.894932 msecs"
19998
user=> (time (count (partition 3 1 (take 20000 corpus))))
"Elapsed time: 12.57996 msecs"
19998

如果对实现感到好奇,请查看分区源http://clojuredocs.org/clojure_core/clojure.core/partition

于 2012-05-12T20:36:12.500 回答
0

我远非 Clojure 专家,但我认为 cons 函数会导致这个问题。尝试使用 list 代替:

(defn gen-ngrams
  [n coll]
  (if (>= (count coll) n)
    (lazy-seq (list (take n coll) (gen-ngrams n (rest coll))))))

我认为 cons 构造了一个比列表更通用的新 seq,因此速度较慢。

编辑:如果“语料库是字符串标记的缺点”,则尝试将其列为列表...

于 2012-05-12T17:38:46.970 回答