Spark是创建numpy数组RDD的最快方法

时间:2015-11-19 12:45:01

标签: python numpy apache-spark pyspark rdd

我的火花应用程序正在使用RDD的numpy数组 目前,我正在从AWS S3读取我的数据,并将其表示为 一个简单的文本文件,其中每一行都是一个向量,每个元素都按空格分隔,例如:

1 2 3
5.1 3.6 2.1
3 0.24 1.333

我正在使用numpy的函数loadtxt()来创建一个numpy数组。
然而,这种方法似乎非常慢,我的应用程序花了太多时间(我认为)将我的数据集转换为numpy数组。

你能建议我一个更好的方法吗?例如,我应该将数据集保存为二进制文件吗? 我应该用另一种方式创建RDD吗?

我创建RDD的一些代码:

data = sc.textFile("s3_url", initial_num_of_partitions).mapPartitions(readData)

readData函数:

 def readPointBatch(iterator):
     return [(np.loadtxt(iterator,dtype=np.float64)]

3 个答案:

答案 0 :(得分:3)

使用numpy.fromstring进行简单映射会更加惯用,速度稍快,如下所示:

import numpy as np.

path = ...
initial_num_of_partitions = ...

data = (sc.textFile(path, initial_num_of_partitions)
   .map(lambda s: np.fromstring(s, dtype=np.float64, sep=" ")))

但忽略了你的方法没有什么特别的错误。据我所知,在基本配置中,简单读取数据的速度大约是缓慢的两倍,而且比创建虚拟numpy数组要慢一些。

所以看起来问题出在其他地方。可能是群集配置错误,从S3获取数据的成本甚至是不切实际的期望。

答案 1 :(得分:2)

使用Spark时不应使用numpy。 Spark有自己的处理数据的方法,确保你的有时非常大的文件不会立刻加载到内存中,超出内存限制。您应该使用Spark加载您的文件:

data = sc.textFile("s3_url", initial_num_of_partitions) \
    .map(lambda row: map(lambda x: float(x), row.split(' ')))

现在,根据您的示例,这将输出RDD

>>> print(data.collect())
[[1.0, 2.0, 3.0], [5.1, 3.6, 2.1], [3.0, 0.24, 1.333]]

@edit 有关文件格式和numpy用法的一些建议:

文本文件与CSV,TSV,Parquet或您感觉舒适的任何内容一样好。根据二进制文件加载的Spark文档:

,二进制文件不是首选文件
  

binaryFiles 路径 minPartitions =无

     

注意:实验

     

从HDFS,本地文件系统(在所有节点上都可用)或任何Hadoop支持的文件系统URI作为字节数组读取二进制文件的目录。每个文件都作为单个记录读取,并以键值对的形式返回,其中键是每个文件的路径,值是每个文件的内容。

     

注意:首选小文件,也允许使用大文件,但可能会导致性能下降。

至于numpy用法,如果我是你,我会尝试用原生Spark替换任何外部包,例如pyspark.mlib.random进行随机化:http://spark.apache.org/docs/latest/api/python/pyspark.mllib.html#module-pyspark.mllib.random

答案 2 :(得分:0)

在这种情况下最好的办法是为io使用pandas库。
请参考这个问题:pandas read_csv() and python iterator as input
在那里,您将看到如何替换np.loadtxt()函数,以便创建一个numpy数组的RDD会快得多。