通过遍历列表替换pyspark中的列值

uwopmtnx  于 2021-07-13  发布在  Spark
关注(0)|答案(4)|浏览(440)

我有一个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个十进位?

nbysray5

nbysray51#

你可以 coalesce 这个 when 如果你有很多条件要匹配的话。还可以使用字典保存要转换的列,并构造 when 动态地使用dict理解语句。至于四舍五入到小数点后1位,你可以用 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|
+---+----+----+----+
sigwle7e

sigwle7e2#

你可以用 replace 在dataframe上替换 colC 通过传递Map的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|

# +---+----+----+----+
unhi4e5o

unhi4e5o3#

您还可以使用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答案要小,但在这个问题上,他的答案更简单。

fafcakar

fafcakar4#

您还可以使用regexp\u 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))

相关问题