【问题标题】:Replacing column values in pyspark by iterating through list通过遍历列表替换 pyspark 中的列值
【发布时间】:2021-02-22 07:00:44
【问题描述】:

我有一个 pyspark 数据框

| ID|colA|colB |colC|
+---+----+-----+----+
|ID1|   3|5.85 |  LB|
|ID2|   4|12.67|  RF|
|ID3|   2|20.78| LCM|
|ID4|   1|   2 | LWB|
|ID5|   6|   3 |  LF|
|ID6|   7|   4 |  LM|
|ID7|   8|   5 |  RS|
+---+----+----+----+

我的目标是将 ColC 中的值替换为 LB、LWB、LF 的值,如下所示。

x = [LB,LWB,LF]
y = [RF,LCM]
z = [LM,RS]

目前我可以通过手动替换每个值来实现这一点,如下面的代码:

# Replacing the values LB,LWF,LF with x

df_new = df.withColumn('ColC',f.when((f.col('ColC') == 'LB')|(f.col('ColC') == 'LWB')|(f.col('ColC') == 'LF'),'x').otherwise(df.ColC))

我的问题是,我们如何通过使用 pyspark 一次动态地遍历列表 (x,y,z) 来替换列的值(在我的示例中为 ColC)?涉及的时间复杂度是多少?另外,如何将 ColB 中的十进制值截断到小数点后 1 位?

【问题讨论】:

    标签: dataframe apache-spark pyspark apache-spark-sql


    【解决方案1】:

    如果您有许多条件要匹配,您可以coalesce when 语句。您还可以使用字典来保存要转换的列,并使用字典推导动态构造 when 语句。至于四舍五入到小数点后一位,可以使用round。

    import pyspark.sql.functions as F
    
    xyz_dict = {'x': ['LB','LWB','LF'],
                'y': ['RF','LCM'],
                'z': ['LM','RS']}
    
    df2 = df.withColumn(
        'colC',
        F.coalesce(*[F.when(F.col('colC').isin(v), k) for (k, v) in xyz_dict.items()])
    ).withColumn(
        'colB',
        F.round('colB', 1)
    )
    
    df2.show()
    +---+----+----+----+
    | ID|colA|colB|colC|
    +---+----+----+----+
    |ID1|   3| 5.9|   x|
    |ID2|   4|12.7|   y|
    |ID3|   2|20.8|   y|
    |ID4|   1| 2.0|   x|
    |ID5|   6| 3.0|   x|
    |ID6|   7| 4.0|   z|
    |ID7|   8| 5.0|   z|
    +---+----+----+----+
    

    【讨论】:

      【解决方案2】:

      您也可以尝试使用 regexp_replace 使用正则表达式:

      import pyspark.sql.functions as f
      
      replacements = [
          ("(LB)|(LWB)|(LF)", "x"),
          ("(LCM)|(RF)", "y"),
          ("(LM)|(RS)", "z")
      ]
      for x, y in replacements:
          df = df.withColumn("colC", f.regexp_replace("colC", x, y))
      

      【讨论】:

        【解决方案3】:

        您可以在数据帧上使用replace 来替换colC 中的值,方法是为映射传递一个dict 对象。和round函数限制colB中的小数位数:

        from pyspark.sql import functions as F
        
        replacement = {
            "LB": "x", "LWB": "x", "LF": "x",
            "RF": "y", "LCM": "y",
            "LM": "z", "RS": "z"
        }
        
        df1 = df.replace(replacement, ["colC"]).withColumn("colB", F.round("colB", 1))
        
        df1.show()
        
        #+---+----+----+----+
        #| ID|colA|colB|colC|
        #+---+----+----+----+
        #|ID1|   3| 5.9|   x|
        #|ID2|   4|12.7|   y|
        #|ID3|   2|20.8|   y|
        #|ID4|   1| 2.0|   x|
        #|ID5|   6| 3.0|   x|
        #|ID6|   7| 4.0|   z|
        #|ID7|   8| 5.0|   z|
        #+---+----+----+----+
        

        【讨论】:

          【解决方案4】:

          你也可以使用isin函数:

          from pyspark.sql.functions import col, when
          
          x = ['LB','LWB','LF']
          y = ['LCM','RF']
          z = ['LM','RS']
          
          df = df.withColumn('ColC', when(col('colC').isin(x), "x")\
                            .otherwise(when(col('colC').isin(y), "y")\
                            .otherwise(when(col('colC').isin(z), "z")\
                            .otherwise(df.ColC))))
          

          如果您以这种方式有一些包含太多值的列表,则您的复杂性低于 blackbishop 的答案,但在这个问题中,他的答案更容易。

          【讨论】:

            猜你喜欢
            • 2021-05-13
            • 2017-10-14
            • 1970-01-01
            • 2018-12-14
            • 1970-01-01
            • 2022-06-16
            • 1970-01-01
            • 2018-11-03
            • 2018-09-17
            相关资源
            最近更新 更多