创建一个新的spark数据帧,其中包含另一个数据帧的成对组合?

时间:2018-02-20 20:43:50

标签: apache-spark pyspark spark-dataframe

考虑以下代码

question = spark.createDataFrame([{'A':1,'B':5},{'A':2,'B':5},
                             {'A':3,'B':5},{'A':3,'B':6}])
#+---+---+
#|  A|  B|
#+---+---+
#|  1|  5|
#|  2|  5|
#|  3|  5|
#|  3|  6|
#+---+---+

如何创建如下所示的spark数据框:

solution = spark.createDataFrame([{'C':1,'D':2},{'C':1,'D':3},
                             {'C':2,'D':3},{'C':5,'D':6}])
#+---+---+
#|  C|  D|
#+---+---+
#|  1|  2|
#|  1|  3|
#|  2|  3|
#|  5|  6|
#+---+---+

这是三元闭合的概念,我根据已连接的边连接三角形的第三条边。

我必须有(1,2)因为(1,5)和(2,5)存在,所以我必须有(1,3)因为(1,5)和(3,5)存在,并且我必须有(2,3)因为(2,5)和(3,5)存在。我必须有(5,6)因为(3,5)和(3,6)存在(两个方向的边缘)。 (5,6)不应该有一个额外的条目,因为从A映射到6没有两对。由于A中没有第二个映射到6的实例,(5,6)没有被添加。

2 个答案:

答案 0 :(得分:0)

试试这个,

import pyspark.sql.functions as F
from pyspark.sql.types import *
from itertools import combinations

df = spark.createDataFrame([{'A':1,'B':5},{'A':2,'B':5},
                         {'A':3,'B':5},{'A':3,'B':6}])

def pairs(list_):
    if len(set(list_)) > 1:
        return [[int(x[0]),int(x[1])] for x in combinations(set(list_), r=2)]
    else:
        return None

triadic_udf = F.udf(pairs, ArrayType(ArrayType(IntegerType())))
cols = ['C','D']
splits = [F.udf(lambda val:val[0],IntegerType())\
         ,F.udf(lambda val:val[1],IntegerType())]

df1 = df.groupby('B').agg(F.collect_list('A').alias('A'))\
                 .withColumn('pairs',F.explode(triadic_udf(F.col('A'))))\
                 .dropna().select('pairs')

df2 = df.groupby('A').agg(F.collect_list('B').alias('B'))\
                 .withColumn('pairs',F.explode(triadic_udf(F.col('B'))))\
                 .dropna().select('pairs')

solution = df1.union(df2).select([s('pairs').alias(c) for s,c in zip(splits,cols)])

solution.show()

答案 1 :(得分:0)

val df = sc.parallelize(Array((1,5),(2,5),(3,5),(3,6),(1,7),(2,7))).toDF("A","B")
df.union(df.select("B","A"))
  .groupByKey(r => r.getInt(0))
  .flatMapGroups({
    (K,Vs) => Vs.map(_.getInt(1)).toArray.combinations(2).map(a => (a(0), a(1)))
  })
  .dropDuplicates
  .show

这是在Scala中,而不是Python,但应该很容易转换。我添加了一些额外的数据点来说明为什么dropDuplicates是必要的。我基本上只是按照我上面在评论中写的步骤: 1)将原始数据帧附加到自身,但B和A切换为
2)按A组分组 3)flatmap组到所有成对组合(我认为这有scala函数)
4)将新列映射到单独的C和D列(我实际上并没有这样做)
5)如果需要,过滤重复