dataframe - 如何根据pyspark数据帧中多列的笛卡尔积创建新列

标签 dataframe pyspark cartesian

让我举一个简单的例子来解释我想要做什么。假设我们有两个非常简单的数据框,如下所示:

Df1
+---+---+---+
| a1| a2| a3|
+---+---+---+
|  2|  3|  7|
|  1|  9|  6|
+---+---+---+

Df2
+---+---+
| b1| b2|
+---+---+
| 10|  2|
|  9|  3|
+---+---+

从 df1, df2,我们需要创建一个新的 df,其中的列是来自 df1, df2 的原始列的笛卡尔积。特别是,新的 df 将有 ‘a1b1’, ‘a1b2’, ‘a2b1’, ‘a2b2’, ‘a3b1’, ‘a3b2’,并且行将是来自 df1, df2 的相应列的乘积。结果 df 应如下所示:
Df3
+----+----+----+----+----+----+
|a1b1|a1b2|a2b1|a2b2|a3b1|a3b2|
+----+----+----+----+----+----+
|  20|   4|  30|   6|  70|  14|
|   9|   3|  81|  27|  54|  18|
+----+----+----+----+----+----+

我搜索了 spark 在线文档以及这里发布的问题,但似乎它们都是关于行的笛卡尔积,而不是列。例如 rdd.cartesian() 提供行中不同值组合的笛卡尔积,如下代码:
r = sc.parallelize([1, 2])
r.cartesian(r).toDF().show()

+---+---+
| _1| _2|
+---+---+
|  1|  1|
|  1|  2|
|  2|  1|
|  2|  2|
+---+---+

但这不是我需要的。同样,我需要创建新列而不是行。在我的问题中,行数将保持不变。我知道udf最终可以解决问题。然而,在我的实际应用程序中,我们有巨大的数据集,创建所有列需要很长时间(大约 500 个新列作为所有可能的列组合)。我们更喜欢一些可以提高效率的向量操作。我可能是错的,但 spark udf 似乎基于行操作,这可能是为什么要花这么长时间才能完成的原因。

非常感谢您的任何建议/反馈/评论。

为方便起见,我在此处附上了简单的代码来创建上面显示的示例数据帧:
df1 = sqlContext.createDataFrame([[2,3,7],[1,9,6]],['a1','a2','a3'])
df1.show()

df2 = sqlContext.createDataFrame([[10,2],[9,3]],['b1','b2'])
df2.show()

最佳答案

据我所知,它并不简单。这是使用 eval 的一个镜头:

# function to add rownumbers in a dataframe
def addrownum(df):
    dff = df.rdd.zipWithIndex().toDF(['features','rownum'])
    odf = dff.map(lambda x : tuple(x.features)+tuple([x.rownum])).toDF(df.columns+['rownum'])
    return odf

df1_ = addrownum(df1)
df2_ = addrownum(df2)
# Join based on rownumbers
outputdf = df1_.rownum.join(df2_,df1_.rownum==df2_.rownum).drop(df1_.rownum).drop(df2_.rownum)

n1 = ['a1','a2','a3']  # columns in set1
n2 = ['b1','b2']       # columns in set2

# I create a string of expression that I want to execute
eval_list = ['x.'+l1+'*'+'x.'+l2 for l1 in n1 for l2 in n2]
eval_str = '('+','.join(eval_list)+')'
col_list = [l1+l2 for l1 in n1 for l2 in n2] 

dfcartesian = outputdf.map(lambda x:eval(eval_str)).toDF(col_list)

其他可能对您有帮助的东西是 spark.ml.feature 中的 Elementwise Product,但它不会那么复杂。您将一个列表中的多个元素明智地提取到另一个列表中,并将特征向量扩展回数据帧。

关于dataframe - 如何根据pyspark数据帧中多列的笛卡尔积创建新列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42305791/

相关文章:

c# - 将笛卡尔坐标转换为图片框坐标 c#

c++ - 以 X-Y 坐标给出的点之间的最短路径距离

python - 通过另一个 DataFrame 中的行将新列映射到 DataFrame

python-3.x - 将字典的特定字典转换为 pandas 数据框 - pandas

python - 派斯帕克。 spark.SparkException : Job aborted due to stage failure: Task 0 in stage 15. 0 失败 1 次,java.net.SocketException:连接重置

java - 生成笛卡尔积java

indexing - 使用 ix() 方法对带有负索引的 Pandas DataFrame 进行切片

python - Pandas - 使用自定义百分位数切割记录

python - dataframe如何通过窗口函数获得相同的groupby

python - pyspark;如何有效地减少值