【问题标题】:Filtering DataFrame using the length of a column使用列的长度过滤 DataFrame
【发布时间】:2016-02-15 04:34:52
【问题描述】:

我想使用与列长度相关的条件过滤DataFrame,这个问题可能很简单,但我在 SO 中没有找到任何相关问题。

更具体地说,我有一个DataFrame,只有一个ColumnArrayType(StringType()),我想使用长度作为过滤器过滤DataFrame,我在下面拍摄了一个sn-p。

df = sqlContext.read.parquet("letters.parquet")
df.show()

# The output will be 
# +------------+
# |      tokens|
# +------------+
# |[L, S, Y, S]|
# |[L, V, I, S]|
# |[I, A, N, A]|
# |[I, L, S, A]|
# |[E, N, N, Y]|
# |[E, I, M, A]|
# |[O, A, N, A]|
# |   [S, U, S]|
# +------------+

# But I want only the entries with length 3 or less
fdf = df.filter(len(df.tokens) <= 3)
fdf.show() # But it says that the TypeError: object of type 'Column' has no len(), so the previous statement is obviously incorrect.

我阅读了Column's Documentation,但没有发现任何对此事有用的属性。我很感激任何帮助!

【问题讨论】:

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


    【解决方案1】:

    在 Spark >= 1.5 中,您可以使用 size 函数:

    from pyspark.sql.functions import col, size
    
    df = sqlContext.createDataFrame([
        (["L", "S", "Y", "S"],  ),
        (["L", "V", "I", "S"],  ),
        (["I", "A", "N", "A"],  ),
        (["I", "L", "S", "A"],  ),
        (["E", "N", "N", "Y"],  ),
        (["E", "I", "M", "A"],  ),
        (["O", "A", "N", "A"],  ),
        (["S", "U", "S"],  )], 
        ("tokens", ))
    
    df.where(size(col("tokens")) <= 3).show()
    
    ## +---------+
    ## |   tokens|
    ## +---------+
    ## |[S, U, S]|
    ## +---------+
    

    在 Spark

    from pyspark.sql.types import IntegerType
    from pyspark.sql.functions import udf
    
    size_ = udf(lambda xs: len(xs), IntegerType())
    
    df.where(size_(col("tokens")) <= 3).show()
    
    ## +---------+
    ## |   tokens|
    ## +---------+
    ## |[S, U, S]|
    ## +---------+
    

    如果您使用HiveContext,那么size UDF 与原始 SQL 应该适用于任何版本:

    df.registerTempTable("df")
    sqlContext.sql("SELECT * FROM df WHERE size(tokens) <= 3").show()
    
    ## +--------------------+
    ## |              tokens|
    ## +--------------------+
    ## |ArrayBuffer(S, U, S)|
    ## +--------------------+
    

    对于字符串列,您可以使用上面定义的udflength 函数:

    from pyspark.sql.functions import length
    
    df = sqlContext.createDataFrame([("fooo", ), ("bar", )], ("k", ))
    df.where(length(col("k")) <= 3).show()
    
    ## +---+
    ## |  k|
    ## +---+
    ## |bar|
    ## +---+
    

    【讨论】:

    • 如果列是string 并且我假装按string 的长度进行过滤,那该怎么办?
    • 同一个udf或者length函数。
    【解决方案2】:

    以下是 scala 中字符串的示例:

    val stringData = Seq(("Maheswara"), ("Mokshith"))
    val df = sc.parallelize(stringData).toDF
    df.where((length($"value")) <= 8).show
    +--------+
    |   value|
    +--------+
    |Mokshith|
    +--------+
    df.withColumn("length", length($"value")).show
    +---------+------+
    |    value|length|
    +---------+------+
    |Maheswara|     9|
    | Mokshith|     8|
    +---------+------+
    

    【讨论】:

    • 我的问题有所不同,我指的是一个字符串数组的列。
    【解决方案3】:

    @AlbertoBonsanto:下面的代码过滤器基于数组大小:

    val input = Seq(("a1,a2,a3,a4,a5"), ("a1,a2,a3,a4"), ("a1,a2,a3"), ("a1,a2"), ("a1"))
    val df = sc.parallelize(input).toDF("tokens")
    val tokensArrayDf = df.withColumn("tokens", split($"tokens", ","))
    tokensArrayDf.show
    +--------------------+
    |              tokens|
    +--------------------+
    |[a1, a2, a3, a4, a5]|
    |    [a1, a2, a3, a4]|
    |        [a1, a2, a3]|
    |            [a1, a2]|
    |                [a1]|
    +--------------------+
    
    tokensArrayDf.filter(size($"tokens") > 3).show
    +--------------------+
    |              tokens|
    +--------------------+
    |[a1, a2, a3, a4, a5]|
    |    [a1, a2, a3, a4]|
    +--------------------+
    

    【讨论】:

      猜你喜欢
      • 2016-11-13
      • 1970-01-01
      • 1970-01-01
      • 2013-12-22
      • 1970-01-01
      • 1970-01-01
      • 2014-02-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多