【问题标题】:Mode of row as a new column in PySpark DataFramePySpark DataFrame 中作为新列的行模式
【发布时间】:2019-06-07 00:28:31
【问题描述】:

是否可以根据先前列的最大值添加新列,其中先前的列是字符串文字。考虑以下数据框:

df = spark.createDataFrame(
    [
        ('1',25000,"black","black","white"),
        ('2',16000,"red","black","white"),
    ],
    ['ID','cash','colour_body','colour_head','colour_foot']
)

那么目标框架应该是这样的:

df = spark.createDataFrame(
    [
        ('1',25000,"black","black","white", "black" ),
        ('2',16000,"red","black","white", "white" ),
    ],
    ['ID','cash','colour_body','colour_head','colour_foot', 'max_v']
)

如果没有可检测的最大值,则应使用最后一个有效颜色。

是否有某种可用的反击可能性或 udf?

【问题讨论】:

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


    【解决方案1】:

    围绕statistics.mode 定义一个UDF 以计算具有所需语义的逐行模式:

    import statistics
    
    from pyspark.sql.functions import udf, col
    from pyspark.sql.types import StringType
    
    def mode(*x):
        try:
            return statistics.mode(x)
        except statistics.StatisticsError:
            return x[-1]
    
    mode = udf(mode, StringType())
    

    df.withColumn("max_v", mode(*[col(c) for c in df.columns if 'colour' in c])).show()
    
    +---+-----+-----------+-----------+-----------+-----+
    | ID| cash|colour_body|colour_head|colour_foot|max_v|
    +---+-----+-----------+-----------+-----------+-----+
    |  1|25000|      black|      black|      white|black|
    |  2|16000|        red|      black|      white|white|
    +---+-----+-----------+-----------+-----------+-----+
    

    【讨论】:

    • 这是使用udf 比API 函数更好的情况。
    • @pault 我在研究中做了尽职调查并阅读了大约 30 个链接,但找不到任何有关按行模式的有用信息。 PySpark 在习惯了 pandas 和 mode(axis=1) 之类的简单事物后受到严重限制:P
    • 可以完成——它需要一个explode(或者可能是一个posexplode),然后是一个count,然后是一个rank,使用两个单独的Window 函数。
    • 这来自takes it as a challenge使用API​​函数寻找解决方案的人...
    【解决方案2】:

    对于任意数量的列的一般情况,udf solution by @cs95 是要走的路。

    但是,在这种只有 3 列的特定情况下,您实际上可以仅使用 pyspark.sql.functions.when 来简化逻辑,这将是 more efficient than using a udf

    from pyspark.sql.functions import col, when
    
    def mode_of_3_cols(body, head, foot):
        return(
            when(
                (body == head)|(body == foot), 
                body
            ).when(
                (head == foot),
                head
            ).otherwise(foot)
        )
    
    df.withColumn(
        "max_v", 
        mode_of_3_cols(col("colour_body"), col("colour_head"), col("colour_foot"))
    ).show()
    #+---+-----+-----------+-----------+-----------+-----+
    #| ID| cash|colour_body|colour_head|colour_foot|max_v|
    #+---+-----+-----------+-----------+-----------+-----+
    #|  1|25000|      black|      black|      white|black|
    #|  2|16000|        red|      black|      white|white|
    #+---+-----+-----------+-----------+-----------+-----+
    

    您只需要检查任何两列是否相等 - 如果是,则该值必须是模式。如果不是,则返回最后一列。

    【讨论】:

    • 实际上,您可以简化逻辑以删除第二个when 条件,因为无论哪种情况您都会返回foot,但如果有人想返回不同的默认值,我会保留它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-08-18
    • 1970-01-01
    • 1970-01-01
    • 2017-11-07
    • 1970-01-01
    • 2022-11-02
    • 1970-01-01
    相关资源
    最近更新 更多