将PySpark中的两个DataFrame合并成矩阵

时间:2019-11-21 18:29:02

标签: python dataframe apache-spark pyspark

我在PySpark脚本中有2个DataFrame。

DF1具有以下数据:

+-----+--------------+
| id  |  keyword     |
+-----+--------------+
| 1   |  banana      |
| 2   |  apple       |
| 3   |  orange      |
+-----+--------------+

DF2具有以下数据:

+----+---------------+
| id | tokens        |
+----+---------------+
| 13 | ['abc', 'def']|
| 14 | ['ghi', 'jkl']|
| 15 | ['mno', 'pqr']|
+----+---------------+

我希望通过结合以上两个DataFrame并在关键字和python函数定义的标记之间执行一些复杂的计算(计算并不重要)来构建第三个DataFrame:

def complex_calculation(keyword, tokens):
    // some various stuff that produces a numeric result between the keyword and the tokens
    // e.g. result = 0.7768756
    return result

最终结果应如下所示:

+-------------+---------+--------+--------+
| keyword     |   13    |   14   |   15   |
+-------------+---------+--------+--------+
|  banana     |  0.5345 | 0.4325 | 0.6543 |
|  apple      |  0.2435 | 0.7865 | 0.9123 |
|  orange     |  0.3765 | 0.6942 | 0.2765 |
+-------------+---------+--------+--------+

1 个答案:

答案 0 :(得分:0)

在这种情况下,您的复杂计算功能实际上非常重要,因为您要执行的操作如下:

  1. 创建两个表的笛卡尔积
table1 = spark._sc.parallelize([[1,"banana"], 
                                [2,"apple"],
                                [3,"orange"]]).toDF(["id","keyword"])

table2 = spark._sc.parallelize([[13, ['abc', 'def']], 
                                [14, ['ghi', 'jkl']],
                                [15, ['mno', 'pqr']]]).toDF(["id","token"])
  1. 具有聚合功能的数据透视。现在,这就是您的功能发挥作用的地方。如您所见,我正在使用f.count()作为聚合函数。
(
    table1.select("keyword")
          .crossJoin(table2)
          .groupBy('keyword')
          .pivot('id')
          .agg(f.count("token"))
).show()

+-------+---+---+---+
|keyword| 13| 14| 15|
+-------+---+---+---+
| orange|  1|  1|  1|
|  apple|  1|  1|  1|
| banana|  1|  1|  1|
+-------+---+---+---+
  1. 如果您想使用一些自定义的聪明计算方法,则确实有两个选择。如果您有能力使用Scala,则可以编写UDAF(用户定义的聚合函数)并将此jar注册到您的Spark集群。或者,您可以使用以下内容查看pandas udfs
from pyspark.sql.functions import pandas_udf
from pyspark.sql.functions import PandasUDFType

@pandas_udf("struct<agg_key: string, parameter1: parameter1_type>", PandasUDFType.GROUPED_MAP)
def my_agg_function(df):
    df = pd.DataFrame(
       df.groupby(agg_key).apply(lambda x: (...))
    df.reset_index(inplace=True, drop=False)
    return df

然后您使用pandas udf,例如

spark_df.groupBy("keyword").pivot("id").apply(my_agg_function(...)))

但是,尽管进行了矢量化的最佳尝试,pandas udf仍然不是很好,并且可能会对性能产生重大影响。希望这可以帮助。 pandas udf的更多信息,请点击此处:https://spark.apache.org/docs/latest/api/python/pyspark.sql.html#pyspark.sql.functions.pandas_udf

理想情况下,您应该尝试尽可能多地使用spark函数来进行复杂的聚合,因为Tungsten可以在后台对其进行优化,并为您提供最佳性能。