11.6 一些提示与性能考量
准备特征
尽管机器学习演讲中经常着重强调所使用的算法,但切记在实践中,每个算法的好坏只取决于你所使用的特征!
特征准备是大规模机器学习中最重要的一步。
添加信息更丰富的特征(例如与其他数据集连接以引入更多信息)与将现有特征转为合适的向量表示(例如缩放向量)都能极大地帮助改进结果。
-
缩放输入特征
使用 StandardScaler 处理特征来平等对待特征。 - 正确提取文本特征
使用诸如 NLTK(http://www.nltk.org)这样的外部库来提词,在使用 TF-IDF 提取特征时,在有代表性的语料库上使用 IDF。 - 为分类标上正确的标签
MLlib要求分类的标签是0到C–1之间,其中C表示分类的总数。
配置算法
在正规化选项可用时,MLlib 中的大多数算法都会在正则化打开时表现得更好(在预测准确度方面)。
此外,大多数基于 SGD 的算法需要大约 100 轮迭代来获得较好的结果。
MLlib 尝试提供合适的默认值,但是你应该尝试增加迭代次数,来看看是否能够提高精确度。
缓存RDD以重复使用
MLlib 中的大多数算法都是迭代的,对数据进行反复操作。
因此,在把输入数据集传给MLlib 前使用 cache() 将它缓存起来是很重要的。
即使数据在内存中放不下,你也应该尝试 persist(StorageLevel.DISK_ONLY) 。
在 Python 中,MLlib 会把数据集在从 Python 端传到 Java 端时在 Java 端自动缓存,因此没有必要缓存你的 Python RDD,除非你在自己的程序中还要用到它。
而在 Scala 和 Java 中,则需要由你来决定是否执行缓存操作。
识别稀疏程度
当你的特征向量包含很多零时,用稀疏格式存储这些向量会为大规模数据集节省巨大的时间和空间。
- 在空间方面,当至多三分之二的位为非零值时,MLlib 的稀疏表示比它的稠密表示要小。
- 在数据处理代价方面,当至多 10% 的位为非零值时,稀疏向量所要花费的代价也会更小。
这是因为使用稀疏表示需要对向量中的每个元素执行的指令比使用稠密向量表示时要多。
但是如果使用稀疏表示能够让你缓存使用稠密表示时无法缓存的数据,即使数据本身比较稠密,你也应当选择稀疏表示。
并行度
对于大多数算法而言,你的输入 RDD 的分区数至少应该和集群的 CPU 核心数相当,这样才能达到完全的并行。
默认情况下 Spark 会为文件的每个“块”创建一个分区,而块一般为 64 MB。
- 可以通过向 SparkContext.textFile() 这样的函数传递分区数的最小值来改变默认行为。 例如 sc.textFile(“data.txt”, 10) 。
- 可以对 RDD 调用 repartition(numPartitions) 来将 RDD 分区成 numPartitions 个分区。
你始终可以通过 Spark 的网页用户界面看到每个 RDD 的分区数。
同时,注意不要使用太多分区,因为这会增加通信开销。