【问题标题】:How to normalize columns with one-hot encoding efficiently in pandas dataframes?如何在 pandas 数据帧中有效地使用 one-hot 编码规范化列?
【发布时间】:2018-12-24 18:33:18
【问题描述】:

显示了示例数据框的一列:

Fruit   FruitA  FruitB
Apple   Banana  Mango
Banana  Apple   Apple
Mango   Apple   Banana
Banana  Mango   Banana
Mango   Banana  Apple
Apple   Mango   Mango

我想在数据帧Fruit-AppleFruit-MangoFruit-Banana 中引入新列,并在它们分别存在的行中使用 one-hot 编码。因此,所需的输出是:

Fruit   FruitA  FruitB  Fruit-Apple Fruit-Banana    Fruit-Mango
Apple   Banana  Mango   1           1           1
Banana  Apple   Apple   1           1           0
Mango   Apple   Banana  1           1           1
Banana  Mango   Banana  0           1           1
Mango   Banana  Apple   1           1           1
Apple   Mango   Mango   1           0           1

我的代码是:

for i in range(len(data)):
        if (data['Fruits'][i] == 'Apple' or data['FruitsA'][i] == 'Apple' or data['FruitsB'][i] == 'Apple'):
            data['Fruits-Apple'][i]=1
            data['Fruits-Banana'][i]=0
            data['Fruits-Mango'][i]=0
        elif (data['Fruits'][i] == 'Banana' or data['FruitsA'][i] == 'Banana' or data['FruitsB'][i] == 'Banana'):
            data['Fruits-Apple'][i]=0
            data['Fruits-Banana'][i]=1
            data['Fruits-Mango'][i]=0
        elif (data['Fruits'][i] == 'Mango' or data['FruitsA'][i] == 'Mango' or data['FruitsB'][i] == 'Mango'):
            data['Fruits-Apple'][i]=0
            data['Fruits-Banana'][i]=0
            data['Fruits-Mango'][i]=1

但我注意到,如果有很多类型的“水果”,运行此代码所需的时间会显着增加。在我的实际数据中,只有 1074 行,而我尝试使用 one-hot 编码“标准化”的列有 18 个不同的值。因此,for 循环中有 18 个if 条件,并且代码现在还没有运行 15 分钟。这太荒谬了(很高兴知道它为什么要花这么长时间 - 在另一列中只包含 6 种不同类型的值,代码执行的时间要少得多,大约 3 分钟)。

那么,实现此输出的最佳(矢量化)方式是什么?

【问题讨论】:

    标签: python pandas normalization one-hot-encoding


    【解决方案1】:

    joinget_dummiesadd_prefix 一起使用:

    df = df.join(pd.get_dummies(df['Fruit']).add_prefix('Fruit-'))
    print (df)
        Fruit  Fruit-Apple  Fruit-Banana  Fruit-Mango
    0   Apple            1             0            0
    1  Banana            0             1            0
    2   Mango            0             0            1
    3  Banana            0             1            0
    4   Mango            0             0            1
    5   Apple            1             0            0
    

    编辑:如果输入是多列,则按列使用get_dummiesmax

    df = (df.join(pd.get_dummies(df, prefix='', prefix_sep='')
                   .max(level=0, axis=1)
                   .add_prefix('Fruit-')))
    print (df)
        Fruit  FruitA  FruitB  Fruit-Apple  Fruit-Banana  Fruit-Mango
    0   Apple  Banana   Mango            1             1            1
    1  Banana   Apple   Apple            1             1            0
    2   Mango   Apple  Banana            1             1            1
    3  Banana   Mango  Banana            0             1            1
    4   Mango  Banana   Apple            1             1            1
    5   Apple   Mango   Mango            1             0            1
    

    为了获得更好的性能,请使用 MultiLabelBinarizer 并将 DataFrame 转换为 lists:

    from sklearn.preprocessing import MultiLabelBinarizer
    
    mlb = MultiLabelBinarizer()
    df = df.join(pd.DataFrame(mlb.fit_transform(df.values.tolist()),
                      columns=mlb.classes_, 
                      index=df.index).add_prefix('Fruit-'))
    print (df)
        Fruit  FruitA  FruitB  Fruit-Apple  Fruit-Banana  Fruit-Mango
    0   Apple  Banana   Mango            1             1            1
    1  Banana   Apple   Apple            1             1            0
    2   Mango   Apple  Banana            1             1            1
    3  Banana   Mango  Banana            0             1            1
    4   Mango  Banana   Apple            1             1            1
    5   Apple   Mango   Mango            1             0            1
    

    【讨论】:

    • 我已经编辑了问题中的数据框和所需的输出。
    • 但是如果数据框中有更多列,比如VegetableAvegetableB 等呢?如何指定需要一次性编码的列(如问题示例中的FruitFruitAFruitB)?
    • @Kristada673 - 我认为最好使用df.filter(like='Fruit')
    • 对于我的数据框,get_dummiesmax 解决方案分别为每一列生成一个热编码,这不是我想要的。 sklearn 解决方案产生以下错误:TypeError: unorderable types: int() < str().
    • 我没试过,但重启 jupyter notebook 内核后,get_dummiesmax 解决方案现在可以工作了!
    猜你喜欢
    • 2017-02-16
    • 2019-10-11
    • 1970-01-01
    • 2016-11-15
    • 2023-01-16
    • 1970-01-01
    • 2020-11-21
    • 2018-03-29
    • 2020-05-25
    相关资源
    最近更新 更多