Pyspark 多个spark核密度估计的并行计算与推理

Pyspark 多个spark核密度估计的并行计算与推理,pyspark,Pyspark,我想做 分段或分组Pypark核密度估计 将得到的密度估计器连接到另一个数据帧并进行推断 例如,假设我有一个如下所示的数据帧: data=[{'id':1, 'samples':[3,56,40]}, {'id':2, 'samples':[-3,80,45,45,2]}] 这些数据是由以下内容生成的 df.groupBy('id').agg(F.collect_list('sample').alias('samples')) 其中df很大。然后想象我有另一个大数据帧,比如: d

我想做

  • 分段或分组Pypark核密度估计
  • 将得到的密度估计器连接到另一个数据帧并进行推断
  • 例如,假设我有一个如下所示的数据帧:

    data=[{'id':1, 'samples':[3,56,40]},
          {'id':2, 'samples':[-3,80,45,45,2]}]
    
    这些数据是由以下内容生成的

    df.groupBy('id').agg(F.collect_list('sample').alias('samples'))
    
    其中
    df
    很大。然后想象我有另一个大数据帧,比如:

    data2 = [{'id':1, 'val': 10},
             {'id':1, 'val': 39},
             {'id':2, 'val': 5}]
    
    我想得到这三个值的概率,10,39,5,关于我上面得到的两个密度估计

    例如,一个Python程序可以做到这一点

    import scipy.stats
    
    data_to_define_pdfs=[{'id':1, 'samples':[3,56,40]},
                         {'id':2, 'samples':[-3,80,45,45,2]}]
    kdes = {}
    for row in data_to_define_pdfs:
        kdes[row['id']] = scipy.stats.gaussian_kde(row['samples'])
    
    inferrence_data = [
        {'id': 1, 'val': 10},
        {'id': 1, 'val': 39},
        {'id': 2, 'val': 5}]
    
    for row in inferrence_data:
        kde = kdes[row['id']]
        row['prob'] = kde.pdf(x=row['val'])[0]
    
    import pprint
    pprint.pprint(inferrence_data)
    
    哪个会输出

    [{'id': 1, 'prob': 0.008817584549791962, 'val': 10},
     {'id': 1, 'prob': 0.012149240532443975, 'val': 39},
     {'id': 2, 'prob': 0.008013522166302479, 'val': 5}]
    

    我有一个解决方案,我将所有样本与用于推断的数据连接起来,这不是最优的,因为我可能会复制很多样本,我正在为我应用kde的数据中的每一行重新生成python scipy kde对象-但这是一个开始,我可以想象做一些更聪明的事情:

    data_to_define_pdfs_flat = []
    for row in data:
        for sample in row['samples']:
            data_to_define_pdfs_flat.append({'id':row['id'], 'sample': sample})
    
    df_sample = spark.createDataFrame(data=data_to_define_pdfs_flat,
                                      schema=T.StructType([T.StructField('id', T.IntegerType(), False),
                                                           T.StructField('sample', T.FloatType(), False)]))
    df_samples = df_sample.groupBy('id').agg(F.collect_list('sample').alias('samples'))
    
    df_infer = spark.createDataFrame(data=data2,
                                     schema=T.StructType([T.StructField('id', T.IntegerType(), False),
                                                          T.StructField('val', T.FloatType(), False)]))
    
    df_infer2 = df_infer.join(df_samples, on='id')
    
    
    def do_inference(df):
        def f(samples, val):
            kde = scipy.stats.gaussian_kde(samples)
            return float(kde.pdf(val)[0])
    
        udf_f = F.udf(f, T.FloatType())
        return df.withColumn('prob', udf_f(F.col('samples'), F.col('val')))
    
    
    df_infer2 = do_inference(df=df_infer2)
    df_samples.show()
    df_infer2.show()
    

    我有一个解决方案,我将所有样本与用于推断的数据连接起来,这不是最优的,因为我可能会复制很多样本,我正在为我应用kde的数据中的每一行重新生成python scipy kde对象-但这是一个开始,我可以想象做一些更聪明的事情:

    data_to_define_pdfs_flat = []
    for row in data:
        for sample in row['samples']:
            data_to_define_pdfs_flat.append({'id':row['id'], 'sample': sample})
    
    df_sample = spark.createDataFrame(data=data_to_define_pdfs_flat,
                                      schema=T.StructType([T.StructField('id', T.IntegerType(), False),
                                                           T.StructField('sample', T.FloatType(), False)]))
    df_samples = df_sample.groupBy('id').agg(F.collect_list('sample').alias('samples'))
    
    df_infer = spark.createDataFrame(data=data2,
                                     schema=T.StructType([T.StructField('id', T.IntegerType(), False),
                                                          T.StructField('val', T.FloatType(), False)]))
    
    df_infer2 = df_infer.join(df_samples, on='id')
    
    
    def do_inference(df):
        def f(samples, val):
            kde = scipy.stats.gaussian_kde(samples)
            return float(kde.pdf(val)[0])
    
        udf_f = F.udf(f, T.FloatType())
        return df.withColumn('prob', udf_f(F.col('samples'), F.col('val')))
    
    
    df_infer2 = do_inference(df=df_infer2)
    df_samples.show()
    df_infer2.show()
    

    如果您可以在本地存储KDE的所有样本,我有一个熊猫数据帧解决方案——至少在这个玩具示例中是这样。由于熊猫数据帧是如何使用内存的,所以它似乎总是很难大规模工作

    在这个解决方案中,kde都在主节点上形成,并发送到所有任务节点-每个kde都是该id的所有样本数据的函数,因此我必须对生成
    df_样本的数据进行子样本

    def do_inference_pd(df_infer, df_samples):
        rows = df_samples.collect()
        kdes = {}
        for row in rows:
            row = row.asDict(True)
            kdes[row['id']] = scipy.stats.gaussian_kde(np.array(row['samples']))
    
        def kde_prob(pdf):
            kde = kdes[pdf.id[0]]
            x = pdf.val
            return pdf.assign(prob=kde(x))
    
        df_infer_prob = df_infer.withColumn('prob', F.lit(0.0))
        sch_str = df_infer2.schema.simpleString()
        f = F.pandas_udf(f=kde_prob, returnType=sch_str, functionType=F.PandasUDFType.GROUPED_MAP)
        df_infer_prob = df_infer_prob.groupBy('id').apply(f)
        return df_infer_prob
    
    
    df_infer_prob = do_inference_pd(df_infer=df_infer, df_samples=df_samples)
    

    如果您可以在本地存储KDE的所有样本,我有一个熊猫数据帧解决方案——至少在这个玩具示例中是这样。由于熊猫数据帧是如何使用内存的,所以它似乎总是很难大规模工作

    在这个解决方案中,kde都在主节点上形成,并发送到所有任务节点-每个kde都是该id的所有样本数据的函数,因此我必须对生成
    df_样本的数据进行子样本

    def do_inference_pd(df_infer, df_samples):
        rows = df_samples.collect()
        kdes = {}
        for row in rows:
            row = row.asDict(True)
            kdes[row['id']] = scipy.stats.gaussian_kde(np.array(row['samples']))
    
        def kde_prob(pdf):
            kde = kdes[pdf.id[0]]
            x = pdf.val
            return pdf.assign(prob=kde(x))
    
        df_infer_prob = df_infer.withColumn('prob', F.lit(0.0))
        sch_str = df_infer2.schema.simpleString()
        f = F.pandas_udf(f=kde_prob, returnType=sch_str, functionType=F.PandasUDFType.GROUPED_MAP)
        df_infer_prob = df_infer_prob.groupBy('id').apply(f)
        return df_infer_prob
    
    
    df_infer_prob = do_inference_pd(df_infer=df_infer, df_samples=df_samples)
    

    如果您还包含了所需的输出,并对其计算方式进行了明确的解释,这将非常有用。感谢您的关注!我添加了一个例子。你有没有找到其他选择?如果你也包含了所需的输出,并解释了它是如何计算的,那会很有帮助。谢谢你的关注!我加了一个例子,你有没有其他选择?