通过比较pyspark数据框中的多个列来更新列

时间:2018-05-18 23:21:37

标签: apache-spark pyspark

我在data frame中有一个pyspark,如下所示。

+-----+---+---+----+
|tests|val|asd|cnty|
+-----+---+---+----+
|test1|  Y|  1|null|
|test2|  N|  2|  UK|
| null|  Y|  1|  UK|
|test1|  N|  2|null|
|test1|  N|  3|null|
|test3|  N|  4| AUS|
|test4|  Y|  5|null|
+-----+---+---+----+

我希望在任何给定的testscnty具有val Y时更新该值,然后更新该tests或{{1}的所有值应该更新为cnty。如果不是那么他们有什么价值。

我在下面做了

Y

以上并没有给我想要的结果。您可以看到from pyspark.sql import Window import pyspark.sql.functions as f df1 = df.select('tests', f.max('val').over(Window.partitionBy('tests')).alias('val'), 'asd', 'cnty') +-----+---+---+----+ |tests|val|asd|cnty| +-----+---+---+----+ |test1| Y| 1|null| |test1| Y| 2|null| |test1| Y| 3|null| |test2| N| 2| UK| |test3| N| 4| AUS| |test4| Y| 5|null| | null| Y| 1| UK| +-----+---+---+----+ test2 cnty UK val N cnty UK val Y val Y该记录的resultWebBrowser然后根据我的要求,这两个记录的JavaScript应为HKEY_CURRENT_USER SOFTWARE Microsoft Internet Explorer Main FeatureControl FEATURE_BROWSER_EMULATION myapp.exe = (DWORD) 00011000 。但async中并非如此。

2 个答案:

答案 0 :(得分:2)

您只检查了测试列,但是您忘记检查cnty列。为此你需要另一个windowSpec for cnty列,并使用when内置函数组合两个windowSpecs来获得你想要的结果

from pyspark.sql import window as w
windowSpec1 = w.Window.partitionBy('tests').orderBy('asd')
windowSpec2 = w.Window.partitionBy('cnty').orderBy('asd')

from pyspark.sql import functions as f
df = df.select(f.col('tests'), f.when(f.max('val').over(windowSpec1)== 'Y', 'Y').otherwise(f.when(f.max('val').over(windowSpec2)== 'Y', 'Y').otherwise(f.col('val'))).alias('val'), f.col('asd'), f.col('cnty'))
df.show(truncate=False)

应该给你

+-----+---+---+----+
|tests|val|asd|cnty|
+-----+---+---+----+
|test4|Y  |5  |null|
|test3|N  |4  |AUS |
|test1|Y  |1  |null|
|test1|Y  |2  |null|
|test1|Y  |3  |null|
|test2|Y  |2  |UK  |
|null |Y  |1  |UK  |
+-----+---+---+----+

我希望这能解释为什么你没有得到理想的结果。

<强>更新

以上解决方案要求两个window函数同时运行,这可能会导致一些内存问题。您可以分别运行一个window函数来分别检查testscnty

from pyspark.sql import window as w
windowSpec1 = w.Window.partitionBy('tests').orderBy('asd')
windowSpec2 = w.Window.partitionBy('cnty').orderBy('asd')

from pyspark.sql import functions as f
df = df.withColumn('val', f.when(f.max('val').over(windowSpec1)== 'Y', 'Y').otherwise(f.col('val')))\
    .withColumn('val', f.when(f.max('val').over(windowSpec2)== 'Y', 'Y').otherwise(f.col('val')))

这将产生相同的结果。

答案 1 :(得分:1)

您可以尝试以下方法。将数据帧左连接到使用&#39; Y&#39;过滤的同一数据帧右边的值:如果找到则应用Y,否则获取现有值。

df.alias('a').join(
    df.filter(col('val')='Y').alias('b'),
    on=(col('a.tests') == col('b.tests')) | (col('a.cnty') == col('b.cnty')),
    how='left'
  )
  .withColumn('final_val',when(col('b.val').isNull(), col('a.val')).otherwise(col('b.val')))
  .select('a.tests','a.asd','a.cnty','final_val')

唯一的问题是,可能存在重复问题,但最好是对数据进行测试,并在必要时进行重复数据删除。