我有一个大文本文件,由Gigaword构建的Word2Vec向量组成(大小超过3GB),每行都是一个单词及其对应的向量。它按频率排序,因此列表中的高频率字高于低频字。
对于给定的单词列表,我需要构建一个包含单词及其word2vec向量的Scala Map。以下是我的方法:
对于每个单词,将文件作为迭代器打开:
val it = scala.io.Source.fromFile(filePath).getLines()
使用find
查找匹配的字词,如果找不到则使用默认值:
val match = it.find(_.split(" ").head == word).getOrElse("zzz" 0d)
这是我的完整方法:
def buildArray2b: (Double, Array[(String, breeze.linalg.DenseVector[Double])]) = {
val startAll = System.currentTimeMillis().toDouble
val stream = (for (word <- this.vocabulary.map(each => each.toLowerCase)) yield {
println("starting " + word)
val start = System.currentTimeMillis().toDouble
println("building iterator")
val iterator = Source.fromInputStream(this.inputStream).getLines()
println("finding")
val line = iterator.find(it => it.split(" ").head == word).getOrElse("zzz 0.0")
println("found")
val splitLine = line.split(" ") //split string into elements
val tail = splitLine.tail.map(_.toDouble) //build w2v vector
val vectorizedLine = splitLine.head -> breeze.linalg.DenseVector(tail) //build map entry
val stop = System.currentTimeMillis().toDouble
println(word + ":" + (stop - start) / 1000d)
vectorizedLine
}).toArray
val stopAll = System.currentTimeMillis().toDouble
val elapsed = (stopAll - startAll) / 1000d
(elapsed, stream)
}
以下是有时候找到以下单词的输出&#34; a&#34; &#34;不切实际&#34;和&#34;&#34;:
scala> w2v.buildArray2
a:0.001
quixotic:0.795
the:25.6
我不知道为什么它没有时间去寻找&#34; quixotic&#34; (这应该是#34;远远低于&#34;在列表中与&#34; a&#34;&#34;&#34;&#34;),但永远找到单词&#34;&#34; ;
我对数据结构的经验很少,所以我很感激(1)对这个问题的任何见解,以及(2)关于如何使这个过程更有效的任何建议。
为此,我已尝试过以下方法:
json4s
)将该.json文件直接打开到地图中。我遇到了内存错误(我已经为此项目分配了14g内存)。提前感谢任何评论/见解!
答案 0 :(得分:2)
只要您没有内存问题,使用Map[String,Vector[String]]
就是一个很好的选择。
读取文件一次并将数据放入Map中。您已经差不多了,因为几乎所有Seq[Tuple2]
都可以使用toMap
轻松转换为地图。
每个密钥都会得到constant time access
。
这将增加额外的间接步骤。它只会让需要解析和处理的数据增长,并使进程更慢。
引用官方Scala文档:http://www.scala-lang.org/api/current/index.html#scala.collection.Iterator They have a hasNext method for checking if there is a next element available, and a next method which returns the next element and discards it from the iterator.
因此,根据定义,Iterator
不可重复使用。
答案 1 :(得分:1)
Scala的Iterator
是有状态的,不打算共享或重用。任何可能的共享或重用完全取决于迭代的底层资源。即您可以安全地多次迭代文件,但在下载流上重用迭代器是没有意义的。
你可以在线性时间&amp;将vocabulary
转换为Map
或Set
,以获得恒定的空间。在较高级别,您需要迭代word2vec文件中的每一行,并检查该单词是否在您的vocabulary
中,然后如果它是添加该单词&amp;像这样的地图重量:
val vocab = this.vocabulary.toSet
val it = Source.fromInputStream(inputStream).getLines
val result: Map[String, DenseVector] = foldLeft(Map.empty[String, DenseVector]){(acc, line) =>
val Array(word, weight) = line.split(" ")
if(vocab.contains(word))
acc + (word -> breeze.linalg.DenseVector(weight.toDouble))
else
acc
}
foldLeft
从迭代器的左侧(即头部)遍历整个文件。在每一行,它检查单词是否是词汇单词,然后如果是,则将其添加到地图(acc
),然后在处理完所有迭代器后返回该地图。