【问题标题】:Split lists in a column into one hot encoded features in pyspark将列中的列表拆分为 pyspark 中的一个热编码特征
【发布时间】:2021-08-14 00:23:00
【问题描述】:

我有一个如下所示的 pyspark 数据框:

id tmp_list other features
1 ['Spain', 'Italy'] xxx
2 ['Spain', 'France', 'USA', 'India'] yyy
3 ['Spain', 'Germany'] zzz

以及如下国家列表:

EU_countries = ['Spain', 'Italy', 'France', 'Germany']

我想做以下事情:

  1. tmp_list 列中提取所有唯一值
  2. EU_countries 中存在的所有值创建新列。对于EU_countries 中不存在的值,创建一个名为other_countries 的列。本质上,为 EU_countries 列表中的每个条目创建列 + 一个名为 other_countries 的额外列。
  3. 如果id 包含EU_countries 列表中的任何国家/地区,则新列Spain 应具有1 作为值否则0。同样适用于EU_countries 列表中的其他国家/地区。
  4. 如果id 包含EU_countries 列表中不存在的任何国家/地区,则应填写other_countries1 否则0

这是我正在寻找的最终输出:

id Spain Italy France Germany other_countries other features
1 1 1 0 0 0 xxx
2 1 0 1 0 1 yyy
3 1 0 0 1 0 zzz

我对此感到头疼。有人可以帮我解决这个问题吗?

非常感谢任何帮助!非常感谢!

【问题讨论】:

  • 试试 pyspark ml 的 onehotencoder?
  • 我认为它会创建不同的列表组合。我的意思是,spain, italy 将是一列,spain,france,USA, india 将是另一列。

标签: python pyspark


【解决方案1】:

第 1 步:将tmp_list 中的所有非欧盟国家/地区替换为常量字符串:

from pyspark.sql import functions as F

df = ...
EU_countries = ['Spain', 'Italy', 'France', 'Germany']

def replaceNonEU(c):
    cond = c == EU_countries[0]
    for country in EU_countries[1:]:
        cond |= (c == country)
    return F.when(cond, c).otherwise(F.lit("other_countries"))

df = df.withColumn("tmp_list", F.array_distinct(F.transform("tmp_list", replaceNonEU)))

#+---+--------------------------------+--------------+
#|id |tmp_list                        |other features|
#+---+--------------------------------+--------------+
#|1  |[Spain, Italy]                  |xxx           |
#|2  |[Spain, France, other_countries]|yyy           |
#|3  |[Spain, Germany]                |zzz           |
#+---+--------------------------------+--------------+

第 2 步:为tmp_list 中的每个可能值创建一个新列,指示该值是否是tmp_list 的元素:

for c in EU_countries + ['other_countries']:
    df = df.withColumn(c, F.array_contains("tmp_list", c).cast("int"))
df = df.drop("tmp_list")

#+---+--------------+-----+-----+------+-------+---------------+
#| id|other features|Spain|Italy|France|Germany|other_countries|
#+---+--------------+-----+-----+------+-------+---------------+
#|  1|           xxx|    1|    1|     0|      0|              0|
#|  2|           yyy|    1|    0|     1|      0|              1|
#|  3|           zzz|    1|    0|     0|      1|              0|
#+---+--------------+-----+-----+------+-------+---------------+

【讨论】:

    【解决方案2】:

    推理和工作就像我在 pandas 中一样。

    1. 爆炸
    2. 创建将非 EU_countries 归为 other_countries 的类别
    3. get_dummies。在这一点上,我感谢this post

    代码如下;

    df=df.select('*').withColumn('tmp_list1', F.explode(col('tmp_list')))#Create new column with exploded list
    df=df.select('*').withColumn('Cat', when(col('tmp_list1').isin(EU_countries),df.tmp_list1).otherwise('other_countries'))#Create another column Cat
    df.groupBy("tmp_list",'other features').pivot("Cat").agg(F.lit(1)).na.fill(0).show()#Get dummies
    
    
    +---------------------------+--------------+------+-------+-----+-----+---------------+
    |tmp_list                   |other features|France|Germany|Italy|Spain|other_countries|
    +---------------------------+--------------+------+-------+-----+-----+---------------+
    |[Spain, Germany]           |zzz           |0     |1      |0    |1    |0              |
    |[Spain, Italy]             |xxx           |0     |0      |1    |1    |0              |
    |[Spain, France, USA, India]|yyy           |1     |0      |0    |1    |1              |
    +---------------------------+--------------+------+-------+-----+-----+---------------+
    

    【讨论】:

    • 根据数据的大小,爆炸+重新分组可能会造成大量的洗牌
    猜你喜欢
    • 2019-11-06
    • 1970-01-01
    • 1970-01-01
    • 2019-05-30
    • 2018-01-29
    • 1970-01-01
    • 1970-01-01
    • 2016-05-08
    • 1970-01-01
    相关资源
    最近更新 更多