簡體   English   中英

在 pyspark 中加入沒有 ON 子句但具有多列條件和填充標志的數據幀

[英]Joining dataframes without ON clause but with multiple column condition and populate flag in pyspark

我正在嘗試通過與某些列條件匹配來加入 2 個數據框並從 A 中檢索 ID。 基本上我必須用來自 A 的 ID 填充 B 中的 '0' 並且我沒有為此的 ON 子句,所以我可能需要交叉連接,但問題是我只需要設置 B。

下面是我用 pyspark 寫的測試數據

import sys
from pyspark.sql.functions import lit, count, col, when
from pyspark.sql.window import Window
# Create the two dataframes
B = sqlContext.createDataFrame([(0,'Sam',100,'ind','IT','2/11/2019'),
                                          (0,'Tom',2000,'usa','HR','2/11/2019'),
                                 (0,'Kom',3500,'uk','IT','2/11/2019'),
                                          (0,'Nom',4000,'can','HR','2/11/2019'),
                                 (0,'Vom',5000,'mex','IT','2/11/2019'),
                                          (0,'XYZ',5000,'mex','IT','2/11/2019')],
                                 ['ID','AName','ASal','BAddress','CDept','DJoin_Date'])
A = sqlContext.createDataFrame([(11,'Sam',100,'ind','ITA','2/11/2019'),(22,'Tom',2000,'usa','HRA','2/11/2019'),
                                  (33,'Kom',3000,'uuk','ITA','2/11/2019'),(44,'Nom',4000,'can','HRA','2/11/2019'),
                                  (55,'Xum',5000,'mex','ITA','2/11/2019'),(77,'XYZ',5000,'mex','ITA','2/11/2019')],
                                 ['ID','AName','ASal','BAddress','CDept','DJoin_Date'])
A.show()
B.show()
  1. 我需要加入 2 個數據框
  2. if(B.AName= A.Aname and B.ASal= A.ASal ) 那么我需要獲取 ID 並將它們放入 B.ID 並生成一個值為“case1”的指示符列
  3. if(B.AName= A.Aname and B.ASal= A.ASal )and (B.BAddress= A.BAddress ) 然后我需要獲取 ID 並將它們放入 B.ID 並生成一個值為 'case1 的指示符列和案例2'

預期 output 是

ID,AName,ASal,BAddress,CDept,DJoin_Date,indicator
11,Sam,100,ind,IT,2/11/2019,case1 and case2
22,Tom,2000,usa,HR,2/11/2019,case1 and case2
33,Kom,3500,uk,IT,2/11/2019,case1
44,Nom,4000,can,HR,2/11/2019,case1 and case2
0,Vom,5000,mex,IT,2/11/2019,
77,XYZ,5000,mex,IT,2/11/2019,case1 and case2

最好的方法是什么。對於條件檢查,我嘗試在 withColumn 中使用 udf,但我還需要返回 2 個值(ID 和指標)。 所以我認為 udf 在這種情況下不起作用

更新 1


另一個疑問與同一個問題有關。 我不想為此創建另一個線程。 所以在這里問。

假設我在兩個 df 中還有一列,即 ID、AName、ASal、BAddress、CDept、DJoin_Date、ID2

如果 Name 和 sal 匹配,B.ID 應該包含 A.ID 的值,但是如果地址匹配而不是用 A.ID 替換 B.ID,我需要用 B.ID2 = A.ID2 替換它們

我能在同一個 select 查詢中做到這一點嗎? 通過獲取指標標志值? 例如,如果指標 == 案例 1 和案例 2,則替換 B.ID2=A.ID2。 但是 select 語句中的新指標列是否可用於進行條件檢查(因為指標列不是 A 或 B 數據幀的一部分)?

更新 2


對數據集進行了一些更改

  import sys
from pyspark.sql.functions import lit, count, col, when
from pyspark.sql.window import Window
# Create the two dataframes
B = sqlContext.createDataFrame([(0,'Sam',100,'ind','IT',0),
                                          (0,'Tom',2000,'usa','HR',30),
                                 (0,'Kom',3500,'uk','IT',-8),
                                          (0,'XYZ',5000,'mex','IT',25)],
                                 ['ID','AName','ASal','BAddress','CDept','ID2'])
A = sqlContext.createDataFrame([(11,'Sam',100,'Korea','ITA',500),(22,'Jack',2000,'usa','HRA',4500),
                                  (33,'Kom',3500,'uk','ITA',5009)],
                                 ['ID','AName','ASal','BAddress','CDept','ID2'])

df = B.join(A, ['AName', 'ASal'], 'left').select(
    F.coalesce(A.ID, B.ID).alias('ID'),
    'AName',
    'ASal',
    B.BAddress,
    B.CDept,
    F.when(
        A.ID.isNull() & (B.BAddress == A.BAddress),
        'case2'
    ).when(
        A.ID.isNotNull() & (B.BAddress == A.BAddress),
        'case1 and case2'
    ).when(
        A.ID.isNotNull(),
        'case1'
    ).alias('indicator'),
    F.when(
        A.ID.isNotNull() & (B.BAddress == A.BAddress),
        A.ID2
    ).otherwise(B.ID2).alias('ID2')
)

Output

  +---+-----+----+--------+-----+---------------+----+
| ID|AName|ASal|BAddress|CDept|      indicator| ID2|
+---+-----+----+--------+-----+---------------+----+
| 33|  Kom|3500|      uk|   IT|case1 and case2|5009|
| 11|  Sam| 100|     ind|   IT|          case1|   0|
|  0|  XYZ|5000|     mex|   IT|           null|  25|
|  0|  Tom|2000|     usa|   HR|           null|  30|
+---+-----+----+--------+-----+---------------+----+

預期 output

+---+-----+----+--------+-----+---------------+----+
| ID|AName|ASal|BAddress|CDept|      indicator| ID2|
+---+-----+----+--------+-----+---------------+----+
| 33|  Kom|3500|      uk|   IT|case1 and case2|5009|
| 11|  Sam| 100|     ind|   IT|          case1|   0|
|  0|  XYZ|5000|     mex|   IT|           null|  25|
|  0|  Tom|2000|     usa|   HR|           **case2|  4500**|
+---+-----+----+--------+-----+---------------+----+
  1. 我需要加入 2 個數據框
  2. if(B.AName= A.Aname and B.ASal= A.ASal ) 那么我需要獲取 ID 並將它們放入 B.ID 並生成一個值為“case1”的指示符列

3.if(B.BAddress= A.BAddress) 然后我需要獲取 A.ID2 並將它們放入 B.ID2 並生成一個值為“case2”的指標列 4. if(B.AName= A.Aname and B .ASal= A.ASal ) 和 (B.BAddress= A.BAddress ) 然后我需要獲取 ID 並將它們放入 B.ID 並生成一個值為“case1 和 case2”的指示符列

我正在努力達到第三點。 但它正在返回 null

您可以對 AName 和 ASal 進行左連接,並使用when檢查 A.ID 是否為 null 的指示符(這表明 AName 和 ASal 上沒有匹配項)。 如果不是null,則表示有匹配,則可以分配地址是否匹配的指標。

import pyspark.sql.functions as F

df = B.join(A, ['AName', 'ASal'], 'left').select(
    F.coalesce(A.ID, B.ID).alias('ID'),
    'AName',
    'ASal',
    B.BAddress,
    B.CDept,
    B.DJoin_Date,
    F.when(
        A.ID.isNotNull() & (B.BAddress == A.BAddress),
        'case1 and case2'
    ).when(
        A.ID.isNotNull(),
        'case1'
    ).alias('indicator')
).orderBy('ID')

df.show()
+---+-----+----+--------+-----+----------+---------------+
| ID|AName|ASal|BAddress|CDept|DJoin_Date|      indicator|
+---+-----+----+--------+-----+----------+---------------+
|  0|  Vom|5000|     mex|   IT| 2/11/2019|           null|
| 11|  Sam| 100|     ind|   IT| 2/11/2019|case1 and case2|
| 22|  Tom|2000|     usa|   HR| 2/11/2019|case1 and case2|
| 33|  Kom|3500|      uk|   IT| 2/11/2019|          case1|
| 44|  Nom|4000|     can|   HR| 2/11/2019|case1 and case2|
| 77|  XYZ|5000|     mex|   IT| 2/11/2019|case1 and case2|
+---+-----+----+--------+-----+----------+---------------+

如果您還有一個 ID2 列,您可以執行類似的操作

df = B.join(A, ['AName', 'ASal'], 'left').select(
    F.coalesce(A.ID, B.ID).alias('ID'),
    'AName',
    'ASal',
    B.BAddress,
    B.CDept,
    B.DJoin_Date,
    F.when(
        A.ID.isNotNull() & (B.BAddress == A.BAddress),
        'case1 and case2'
    ).when(
        A.ID.isNotNull(),
        'case1'
    ).alias('indicator'),
    F.when(
        A.ID.isNotNull() & (B.BAddress == A.BAddress),
        B.ID2
    ).otherwise(A.ID2)
)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM