【问题标题】:How to encode labels from array in pyspark如何在pyspark中对数组中的标签进行编码
【发布时间】:2019-05-06 07:47:51
【问题描述】:

例如,我在 name 中有具有分类特征的 DataFrame:

 from pyspark.sql import SparkSession

 spark = SparkSession.builder.master("local").appName("example")
 .config("spark.some.config.option", "some-value").getOrCreate()

 features = [(['a', 'b', 'c'], 1),
             (['a', 'c'], 2),
             (['d'], 3),
             (['b', 'c'], 4), 
             (['a', 'b', 'd'], 5)]

 df = spark.createDataFrame(features, ['name','id'])
 df.show()

输出:

+---------+----+
|     name| id |
+---------+----+
|[a, b, c]|   1|
|   [a, c]|   2|
|      [d]|   3|
|   [b, c]|   4|
|[a, b, d]|   5|
+---------+----+

我想得到什么:

+--------+--------+--------+--------+----+
| name_a | name_b | name_c | name_d | id |
+--------+--------+--------+--------+----+
| 1      | 1      | 1      | 0      | 1  |
+--------+--------+--------+--------+----+
| 1      | 0      | 1      | 0      | 2  |
+--------+--------+--------+--------+----+
| 0      | 0      | 0      | 1      | 3  |
+--------+--------+--------+--------+----+
| 0      | 1      | 1      | 0      | 4  |
+--------+--------+--------+--------+----+
| 1      | 1      | 0      | 1      | 5  |
+--------+--------+--------+--------+----+

我找到了same queston,但没有任何帮助。 我尝试使用PySpark.ML 中的VectorIndexer,但在将name 字段转换为vector type 时遇到了一些问题。

 from pyspark.ml.feature import VectorIndexer

 indexer = VectorIndexer(inputCol="name", outputCol="indexed", maxCategories=5)
 indexerModel = indexer.fit(df)

我收到以下错误:

Column name must be of type org.apache.spark.ml.linalg.VectorUDT@3bfc3ba7 but was actually ArrayType

我找到了一个解决方案here,但它看起来过于复杂。但是,我不确定是否只能使用VectorIndexer

【问题讨论】:

    标签: python apache-spark pyspark pyspark-sql


    【解决方案1】:

    如果您想在 Spark ML 中使用输出,最好使用CountVectorizer

    from pyspark.ml.feature import CountVectorizer
    
    # Add binary=True if needed
    df_enc = (CountVectorizer(inputCol="name", outputCol="name_vector")
        .fit(df)
        .transform(df))
    df_enc.show(truncate=False)
    
    +---------+---+-------------------------+
    |name     |id |name_vector              |
    +---------+---+-------------------------+
    |[a, b, c]|1  |(4,[0,1,2],[1.0,1.0,1.0])|
    |[a, c]   |2  |(4,[0,1],[1.0,1.0])      |
    |[d]      |3  |(4,[3],[1.0])            |
    |[b, c]   |4  |(4,[1,2],[1.0,1.0])      |
    |[a, b, d]|5  |(4,[0,2,3],[1.0,1.0,1.0])|
    +---------+---+-------------------------+
    

    否则收集不同的值:

    from pyspark.sql.functions import array_contains, col, explode
    
    names = [
        x[0] for x in 
        df.select(explode("name").alias("name")).distinct().orderBy("name").collect()]
    

    并选择带有array_contains的列:

    df_sep = df.select("*", *[
        array_contains("name", name).alias("name_{}".format(name)).cast("integer") 
        for name in names]
    )
    df_sep.show()
    
    +---------+---+------+------+------+------+
    |     name| id|name_a|name_b|name_c|name_d|
    +---------+---+------+------+------+------+
    |[a, b, c]|  1|     1|     1|     1|     0|
    |   [a, c]|  2|     1|     0|     1|     0|
    |      [d]|  3|     0|     0|     0|     1|
    |   [b, c]|  4|     0|     1|     1|     0|
    |[a, b, d]|  5|     1|     1|     0|     1|
    +---------+---+------+------+------+------+
    

    【讨论】:

      【解决方案2】:

      explode 来自pyspark.sql.functionspivot

      from pyspark.sql import functions as F
      features = [(['a', 'b', 'c'], 1),
                   (['a', 'c'], 2),
                   (['d'], 3),
                   (['b', 'c'], 4),
                   (['a', 'b', 'd'], 5)]
      df = spark.createDataFrame(features, ['name','id'])
      df.show()
      +---------+---+
      |     name| id|
      +---------+---+
      |[a, b, c]|  1|
      |   [a, c]|  2|
      |      [d]|  3|
      |   [b, c]|  4|
      |[a, b, d]|  5|
      +---------+---+
      
      df = df.withColumn('exploded', F.explode('name'))
      
      df.drop('name').groupby('id').pivot('exploded').count().show()
      +---+----+----+----+----+
      | id|   a|   b|   c|   d|
      +---+----+----+----+----+
      |  5|   1|   1|null|   1|
      |  1|   1|   1|   1|null|
      |  3|null|null|null|   1|
      |  2|   1|null|   1|null|
      |  4|null|   1|   1|null|
      +---+----+----+----+----+
      

      id排序并将null转换为0

      df.drop('name').groupby('id').pivot('exploded').count().na.fill(0).sort(F.col('id').asc()).show()
      +---+---+---+---+---+
      | id|  a|  b|  c|  d|
      +---+---+---+---+---+
      |  1|  1|  1|  1|  0|
      |  2|  1|  0|  1|  0|
      |  3|  0|  0|  0|  1|
      |  4|  0|  1|  1|  0|
      |  5|  1|  1|  0|  1|
      +---+---+---+---+---+
      

      explode 为给定数组或映射中的每个元素返回一个新行。然后您可以使用pivot 来“转置”新列。

      【讨论】:

        猜你喜欢
        • 2020-11-05
        • 1970-01-01
        • 2010-10-09
        • 1970-01-01
        • 1970-01-01
        • 2020-10-30
        • 2019-03-19
        • 1970-01-01
        相关资源
        最近更新 更多