web-dev-qa-db-ja.com

Pyspark Dataframe Apply関数を2つの列に

2つのPySparkデータフレームdf1df2があるとします。

df1=   'a' 
        1    
        2    
        5    

df2=   'b'
        3
        6

そして、各df2['b']の最も近いdf1['a']値を見つけ、df1の新しい列として最も近い値を追加します。

つまり、df1['a']の各値xについて、すべてのy in df2['b']についてmin(abx(x-y))を達成するyを見つけたいと思います(注:達成できるyは1つだけであると想定できます最小距離)、そして結果は

'a'    'b'
 1      3
 2      3
 5      6

次のコードを試して、距離行列を最初に作成しました(最小距離を達成する値を見つける前に)。

from pyspark.sql.types import IntegerType
from pyspark.sql.functions import udf

def dict(x,y):
    return abs(x-y)
udf_dict = udf(dict, IntegerType())

sql_sc = SQLContext(sc)
udf_dict(df1.a, df2.b)

与える

Column<PythonUDF#dist(a,b)>

それから私は試しました

sql_sc.CreateDataFrame(udf_dict(df1.a, df2.b))

エラー/出力を出さずに永久に実行されます。

私の質問は:

  1. 私はSparkを初めて使用するので、出力DataFrameを効率的に構築する方法はありますか? (私の方法は、最初にすべてのaおよびb値の距離行列を作成し、次にminの値を見つけることです)
  2. 私のコードの最後の行の何が問題になっていますか、そしてそれをどのように修正しますか?
8
Chianti5

あなたの2番目の質問から始めます-あなたは既存のデータフレームにのみUDFを適用できます、あなたはこのようなものを考えていたと思います:

>>> df1.join(df2).withColumn('distance', udf_dict(df1.a, df2.b)).show()
+---+---+--------+
|  a|  b|distance|
+---+---+--------+
|  1|  3|       2|
|  1|  6|       5|
|  2|  3|       1|
|  2|  6|       4|
|  5|  3|       2|
|  5|  6|       1|
+---+---+--------+

しかし、内部absを使用して、この距離を適用するより効率的な方法があります。

>>> from pyspark.sql.functions import abs
>>> df1.join(df2).withColumn('distance', abs(df1.a -df2.b))

次に、以下を計算して一致する数値を見つけることができます。

>>> distances = df1.join(df2).withColumn('distance', abs(df1.a -df2.b))
>>> min_distances = distances.groupBy('a').agg(min('distance').alias('distance'))
>>> distances.join(min_distances, ['a', 'distance']).select('a', 'b').show()
+---+---+                                                                       
|  a|  b|
+---+---+
|  5|  6|
|  1|  3|
|  2|  3|
+---+---+
8
Mariusz