Apache spark DataFrame.withColumn()使用管道的costomized UDF工作得非常慢

Apache spark DataFrame.withColumn()使用管道的costomized UDF工作得非常慢,apache-spark,pyspark,apache-spark-sql,bigdata,user-defined-functions,Apache Spark,Pyspark,Apache Spark Sql,Bigdata,User Defined Functions,现在,我正在使用ML和Pipeline pypark API实现一个模糊分类器,我的问题是在规则库(RB)生成的最后阶段,我希望将结果作为一个新的“预测”列进行预测 为此,我使用df.withColumn()作为模糊原则,它使用INFERENCE_udf进行决策。在这种情况下,我不知道为什么它不适用于大数据集。 (如果我在类中移动最后四个方法,我将面临序列化问题。) 对于非常小的数据集,一切都正常,对于大数据集,规则生成和传输正确,问题在于withColumn的速度慢?!你有类似的经验或想法吗

现在,我正在使用ML和Pipeline pypark API实现一个模糊分类器,我的问题是在规则库(RB)生成的最后阶段,我希望将结果作为一个新的“预测”列进行预测

为此,我使用df.withColumn()作为模糊原则,它使用INFERENCE_udf进行决策。在这种情况下,我不知道为什么它不适用于大数据集。 (如果我在类中移动最后四个方法,我将面临序列化问题。) 对于非常小的数据集,一切都正常,对于大数据集,规则生成和传输正确,问题在于withColumn的速度慢?!你有类似的经验或想法吗

class FuzzyClassifier(Estimator, HasFeaturesCol, HasLabelCol,HasInputCol, HasPredictionCol):
    .
    .
    .
    def _fit(self, df):
        rb_p,rb_n=self.GenerateRules(df)             
        fuzzyModel=FuzzyModel(labelCol=self.getLabelCol(),featuresCol=self.getFeaturesCol(),RB_Pos=rb_p,RB_Neg=rb_n)               
        return (fuzzyModel)

class FuzzyModel(Model,HasFeaturesCol, HasLabelCol):
    .
    .
    .
    def _transform(self, df):         
            RB_N=self.getRB_Neg()
            RB_P=self.getRB_Pos()
            MFsParams=Fuzzifier().getMFsParams()   
            df = df.withColumn('prediction', infrence_udf(RB_P,RB_N,MFsParams)('features'))
            return   df 

def infrence_udf(RB_P,RB_N,MFsParams):
            return F.udf(lambda l: infrence(l,RB_P,RB_N,MFsParams), DoubleType()) 

def infrence(sampleRow,RB_P,RB_N,MFsParams):
        p=getCoverageDegree(sampleRow,RB_P,MFsParams)
        n=getCoverageDegree(sampleRow,RB_N,MFsParams)
        if  p > n :       #  degree 'PositiveClass'  > 'NegetiveClass'
            predictedLabed = 1.0
        elif p < n:    #  degree  'PositiveClass'  > 'NegetiveClass'
            predictedLabed = 0.0
        else:
             predictedLabed = random.randrange(0, 2)
        return float(predictedLabed)

def getCoverageDegree(sampleRow, RB,MFsParams):        
    # calc sum of the mathching degrees of all rules and each sample row   
    RB=np.array(RB.reshape(RB.shape[0],RB.shape[2]))
    x=np.array([sampleRow,]*len(RB))  # sampleRow is replicated
    degree=np.sum(np.array([getMatchingDegree(xp,r,MFsParams) for xp,r in zip(x,RB)]))
    return degree


def getMatchingDegree(xp, r_i,MFsParams):  
    mfValues=np.array([trimf(xp_i,MFsParams[a_ji-1]) for xp_i,a_ji in zip(xp,r_i)])        
    m=np.prod(mfValues, axis=0)
    return m

def trimf(z,p):
        a,b,c=p[0],p[1],p[2]
        if (z<=a) or (z>=c):
            y = 0
        elif (a <= z <= b):
            y = (z-a) / (b-a)
        elif (b <= z <= c):
            y = (c-z) / (c-b)
        return y 
类模糊分类器(估计器、HasFeaturesCol、HasLabelCol、HasInputCol、HasPredictionCol):
.
.
.
def_配合(自身、df):
rb_p,rb_n=自发电机(df)
fuzzyModel=fuzzyModel(labelCol=self.getLabelCol(),featuresCol=self.getFeaturesCol(),RB_Pos=RB_p,RB_Neg=RB_n)
返回(模糊模型)
类模糊模型(模型、HasFeaturesCol、HasLabelCol):
.
.
.
def_变换(自,df):
RB_N=self.getRB_Neg()
RB_P=self.getRB_Pos()
MFsParams=fuzzizer().getMFsParams()
df=df.withColumn('prediction',inforence_udf(RB_P,RB_N,MFsParams)('features'))
返回df
定义信息自定义项(RB\U P、RB\U N、MFsParams):
返回F.udf(lambda l:infonce(l,RB_P,RB_N,MFsParams),DoubleType()
定义信息(采样器OW、RBU P、RB N、MFsParams):
p=getCoverageDegree(sampleRow、RB_p、MFsParams)
n=获取覆盖度(sampleRow、RB_n、MFsParams)
如果p>n:#度“正类”>“负类”
predictedLabed=1.0
elif p阴性等级
predictedLabed=0.0
其他:
predictedLabed=random.randrange(0,2)
返回浮动(预测标记)
def getCoverageDegree(采样器OW、RB、MFsParams):
#计算所有规则和每个样本行的匹配度之和
RB=np.数组(RB.整形(RB.形状[0],RB.形状[2]))
x=np。数组([sampleRow,]*len(RB))#sampleRow被复制
degree=np.sum(np.array([getMatchingDegree(xp,r,MFsParams))表示xp,r在zip(x,RB)中)
回归度
def获取匹配度(xp、r_i、MFsParams):
mfValues=np.array([trimf(xp_i,MFsParams[a_ji-1]),用于xp_i,zip中的a_ji(xp,r_i)])
m=np.prod(mfValues,轴=0)
返回m
def trimf(z,p):
a、 b,c=p[0],p[1],p[2]
如果(z=c):
y=0

elif(a这是由于您编码它的方式。 我推荐 1.使用spark重写函数
2.将GetCoverage Degree放在withcolumn语句之前

您遇到的问题可能是由于UDF的工作方式:对于每一行,Spark必须将Java对象转换为Python对象,然后执行所需的操作,然后将其带回Java对象。如果可以,请使用框架附带的ML算法(Spark有MLlib),或者尝试使用
pandas\u udf
s来处理较大的块,而不是一行一行。@Oliver W.谢谢你的快速评论,问题是pandas udf不能处理数组(我想!),对吗?features列是一个int向量,应该是预测的基础。@user3600673,谢谢你的回答,你能解释更多吗“使用spark重写函数”,我需要基于我的分类器进行推理,这是spark的内置函数无法完成的,因此我使用用户定义函数(UDF)。??@fatemeAghaei,代码让我感觉像是开始!函数调用中的函数太多了。重写我的意思是使用spark核心抽象而不是熊猫(rdd/dataset而不是np)…这将有助于spark引擎的优化。