Spark矩阵乘法代码需要花费大量时间来执行

时间:2017-06-11 22:02:02

标签: apache-spark pyspark

我在Spyder上使用findspark.init()设置了一个简单的PySpark环境,并且我在localhost上运行代码。我很困惑简单矩阵乘法如何在Spark中使用BlockMatrix花费数小时和数小时的时间,而相同的代码需要几分钟才能在numpy上运行。

以下是我使用的代码:

import numpy as np
import pandas as pd
from sklearn import cross_validation as cv
import itertools
import random
import findspark
import time
start=time.time()

findspark.init()

from pyspark.mllib.linalg.distributed import *
from pyspark.sql import SparkSession
from pyspark import SparkContext, SparkConf
conf = SparkConf().setAppName('myapp')

sc = SparkContext(conf=conf)
spark = SparkSession(sc)

from pyspark.mllib.linalg.distributed import *

def as_block_matrix(rdd, rowsPerBlock=1024, colsPerBlock=1024):
    return IndexedRowMatrix(
        rdd.zipWithIndex().map(lambda xi: IndexedRow(xi[1], xi[0]))
    ).toBlockMatrix(rowsPerBlock, colsPerBlock)

def prediction(P,Q):
#    np.r_[ pp,np.zeros(len(pp)) ].reshape(2,20)
    Pn=np.r_[ P,np.zeros(len(P)),np.zeros(len(P)),np.zeros(len(P)),np.zeros(len(P)) ].reshape(5,len(P))
    Qn=np.r_[ Q,np.zeros(len(Q)),np.zeros(len(Q)),np.zeros(len(Q)),np.zeros(len(Q)) ].reshape(5,len(Q))
    A = Pn[:1]
    B = Qn[:1].T
    distP = sc.parallelize(A)
    distQ = sc.parallelize(B)
    mat=as_block_matrix(distP).multiply(as_block_matrix(distQ))
    blocksRDD = mat.blocks
    m=(list(blocksRDD.collect())[0][1])
    #print(m)
    return m.toArray()[0,0]

for epoch in range(1):
    for u, i in zip(users,items):
        e = R[u, i] - prediction(P[:,u],Q[:,i]) 

1 个答案:

答案 0 :(得分:1)

不知道矩阵的大小使得回答这个问题变得更加困难,但是如果你正在处理高维稀疏矩阵,那么pyspark进行矩阵乘法的方式就有一个可能存在的问题。为了乘以稀疏矩阵,pyspark将稀疏矩阵转换为密集矩阵。这在文档中说明:

http://spark.apache.org/docs/latest/api/python/pyspark.mllib.html#pyspark.mllib.linalg.distributed.BlockMatrix.multiply

指出:

  

multiply(other)Left将此BlockMatrix与另一个BlockMatrix相乘。此矩阵的colsPerBlock必须等于other的rowsPerBlock。如果other包含任何SparseMatrix块,则必须将它们转换为DenseMatrix块。输出BlockMatrix仅包含DenseMatrix块。这可能会导致一些性能问题,直到添加了对两个稀疏矩阵相乘的支持。

据我所知,如果您打算使用内置矩阵数据类型,那么就没有很好的解决方法。一种解决方法是放弃矩阵数据类型,并使用rdd或dataframe join操作手动滚动自己的矩阵乘法。例如,如果您可以使用数据框,则以下内容已经过测试,并且可以大规模运行:

from pyspark.sql.functions import sum

def multiply_df_matrices(A,B):
    return A.join(B,A['column']==B['row'])\
            .groupBy(A['row'],B['column'])\
            .agg(sum(A['value']*B['value']).alias('value'))

你可以通过加入两个rdds来做类似的事情。