Skip to main content
 首页 » 编程设计

python之如何在pyspark中对数组中的标签进行编码

2024年09月03日33zhengyun_ustc

例如,我在 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 来完成。

请您参考如下方法:

如果你想使用 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| 
+---------+---+------+------+------+------+