如何在DataFrame中跨组使用QuantileDiscretizer?

时间:2017-05-02 16:27:45

标签: scala apache-spark apache-spark-sql apache-spark-mllib

我有一个包含以下列的DataFrame。

scala> show_times.printSchema
root
 |-- account: string (nullable = true)
 |-- channel: string (nullable = true)
 |-- show_name: string (nullable = true)
 |-- total_time_watched: integer (nullable = true)

这是关于客户观看特定节目的次数的数据。我应该根据观看的总时间对每个节目的客户进行分类。

数据集总共有1.33亿行,其中192个不同show_names

对于每个个人节目,我应该将客户分为3类(1,2,3)。

我使用Spark MLlib的QuantileDiscretizer

目前,我循环播放每个节目并按顺序方式运行QuantileDiscretizer,如下面的代码所示。

enter image description here

我最终想要的是以下样本输入来获取样本输出。

示例输入:

account,channel,show_name,total_time_watched
acct1,ESPN,show1,200
acct2,ESPN,show1,250
acct3,ESPN,show1,800
acct4,ESPN,show1,850
acct5,ESPN,show1,1300
acct6,ESPN,show1,1320
acct1,ESPN,show2,200
acct2,ESPN,show2,250
acct3,ESPN,show2,800
acct4,ESPN,show2,850
acct5,ESPN,show2,1300
acct6,ESPN,show2,1320

示例输出:

account,channel,show_name,total_time_watched,Time_watched_bin
acct1,ESPN,show1,200,1
acct2,ESPN,show1,250,1
acct3,ESPN,show1,800,2
acct4,ESPN,show1,850,2
acct5,ESPN,show1,1300,3
acct6,ESPN,show1,1320,3
acct1,ESPN,show2,200,1
acct2,ESPN,show2,250,1
acct3,ESPN,show2,800,2
acct4,ESPN,show2,850,2
acct5,ESPN,show2,1300,3
acct6,ESPN,show2,1320,3

是否有一种更高效,更分散的方式来使用某些groupBy - 类似的操作,而不是循环遍历每个show_name并将其一个接一个地捆绑?

2 个答案:

答案 0 :(得分:0)

我对QuantileDiscretizer一无所知,但认为您最关心的是应用QuantileDiscretizer的数据集。我想你想弄清楚如何将输入数据集拆分成每个show_name的较小数据集(你说输入数据集中有192个不同的show_name)。

解决方案1:分区镶木地板数据集

我注意到您使用镶木地板作为输入格式。我对格式的理解非常有限但是我注意到人们正在使用一些分区方案将大数据集拆分成更小的块,然后他们就可以处理他们喜欢的任何内容(按照某些分区方案)。

在您的情况下,分区方案可以包括show_name

这会使你的案件变得微不足道,因为分裂是在写作时完成的(又名不再是我的问题)。

请参阅How to save a partitioned parquet file in Spark 2.1?

解决方案2:Scala的未来

根据您的迭代解决方案,您可以将每次迭代包装到您要提交以并行处理的Future

Spark SQL' SparkSession(和Spark Core' s SparkContext)是线程安全的。

解决方案3:数据集的filterunion运营商

在遵循这个解决方案之前我会三思而行,因为它会给你的肩膀增加负担,我认为可以通过解决方案1轻松解决。

鉴于您已经获得了一个大的1.33亿行拼花文件,我首先使用show_name运算符按filter构建192个数据集(正如您构建{ {1}}这是违反名称的,因为它是show_rdd而非DataFrame)和RDD(再次与您一样)。

请参阅Dataset API

解决方案4:使用窗口函数

我认为这可以起作用,但我自己也没有检查过。

您可以使用窗口函数(请参阅WindowSpec和列的over运算符)。

窗口函数会为您提供分区(窗口),而union 以某种方式over应用于窗口/分区。然而,这将需要"解构" QuantileDiscretizer进入QuantileDiscretizer训练模型,以某种方式再次将结果模型拟合到窗口。

我认为这是可行的,但我自己并没有这样做。遗憾。

答案 1 :(得分:-1)

这是一个较早的问题。但是,回答该问题将有助于将来遇到相同情况的人。

可以使用熊猫udf函数来实现。熊猫UDF函数的输入和输出都是数据帧。我们需要提供输出数据帧的架构,如下面的代码示例中的注释所示。下面的代码示例可以达到所需的结果。

output_schema = StructType(df.schema.fields + [StructField('Time_watched_bin', IntegerType(), True)])

@pandas_udf(output_schema, PandasUDFType.GROUPED_MAP)
# pdf: pandas dataframe
def get_buckets(pdf):
    pdf['Time_watched_bin'] = pd.cut(pdf['total_time_watched'], 3, labels=False)
        
    return pdf

df = df.groupby('show_name').apply(get_buckets)

df将具有带有存储桶信息的新列“ Time_watched_bin”。