如何在熊猫数据帧中使用一键编码有效地规范化列?

时间:2018-07-17 06:47:56

标签: python pandas normalization one-hot-encoding

显示示例数据框的列:

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中引入新的列,并在它们分别存在的行中使用一键编码。因此,所需的输出是:

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行,而我尝试使用“一键编码”“标准化”的列具有18个不同的值。因此,在for循环中有18个if条件,并且代码现在还没有结束运行15分钟。这太荒谬了(很高兴知道为什么要花这么长时间-在另一列只包含6种不同类型的值的代码中,执行代码所花的时间要少得多,大约3分钟)。

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

1 个答案:

答案 0 :(得分:4)

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转换为list

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