机器学习Notes之One-Hot编码

One-Hot编码是将离散特征转化为欧式空间表示,便于计算特征间距离。当特征大小无意义时,如性别,使用One-Hot编码可避免不合理距离。然而,这可能导致多重共线性问题,可以通过`drop_first=True`去除。同时,处理训练集和测试集时,要确保编码一致,避免未知类别。 sklearn的`OneHotEncoder`可以方便处理这类问题,忽略未知类别。
摘要由CSDN通过智能技术生成

One-hot编码也叫独热编码,又称一位有效编码。方法就是用N位对N个状态进行表示,但是其中只有一位为1,剩下N-1位全为0。例如,特征为性别,就需要变成10和01。
在回归,分类,聚类等机器学习算法中,特征之间距离的计算或相似度的计算是非常重要的。而常用的距离或相似度的计算都是在欧式空间的相似度计算,计算余弦相似性,基于的就是欧式空间。使用独热编码(One-Hot Encoding),将离散特征的取值扩展到了欧式空间,离散特征的某个取值就对应欧式空间的某个点。将离散型特征使用独热编码(One-Hot Encoding),会让特征之间的距离计算更加合理。
举个例子,如果我们现在一个特征有五个取值,如果不采用One-Hot编码,则分别表示为演员=0,厨师=1,公务员=2,教师=3,律师=4,那么教师和厨师的距离为2,律师与厨师的距离为3,这显然是不合理的。比较合理的做法是将两个工作之间的距离表示为sqrt(2),即两个工作之间的距离是一样的。
总结一下,如果特征的大小表示如果有意义的话,比如我们用1-9表示年龄,这种特征的大小表示就是有意义的,所以这种情况下就不需要进行One-Hot编码;如果特征的大小没有意义,仅仅表示状态时则使用One-Hot编码。
pandas实现:首先对f3这个特征做One-Hot编码,接着将生成的df和原来的df进行拼接,最后删除原来的f3特征

df = pd.DataFrame(
    [
        [1000, "male", 23],
        [1001, "female", 22],
        [1002, "male", 69]
    ],
    columns=['id', 'gender', 'age']
)

# step 1: using get_dummies to encode feature
dummy_df = pd.get_dummies(df["gender"])

# step 2: concat dummy_df with original df
df = pd.concat((df, dummy_df), axis=1)

# step 3: remove original feature
df = df.drop("gender", axis=1)

# simplified form
# df = pd.concat((df, pd.get_dummies(df["gender"])), axis=1)
# df = df.drop("gender", axis=1)

存在问题:

  1. 采用这种方法实现会存在问题,比如将性别划分成gender_male和gender_female时,这两种特征其实是冗余的,这个问题在数学中叫做多重共线性(Multicollinearity),在pandas处理时也有人称之为虚拟变量陷阱(Dummy Varialble Trap)。解决办法就是加入参数drop_first=True,作用是除去第一个虚拟变量,然转化后的虚拟变量从k和变成k-1个。
df = pd.DataFrame(
    [
        [1000, "male", 23],
        [1001, "female", 22],
        [1002, "male", 69]
    ],
    columns=['id', 'gender', 'age']
)

# step 1: using get_dummies to encode feature
dummy_df = pd.get_dummies(df["gender"], drop_first=True)

# step 2: concat dummy_df with original df
df = pd.concat((df, dummy_df), axis=1)

# step 3: remove original feature
df = df.drop("gender", axis=1)

# simplified form
# df = pd.concat((df, pd.get_dummies(df["gender"], drop_first=True)), axis=1)
# df = df.drop("gender", axis=1)
  1. 测试集中可能出现训练集中没出现过的变量。解决办法:①将训练集和测试集一起get_dummies,然后再切分;②检测不一致的列,然后在缺少这些列的数据集中加入取值全为0的同名列。③使用sklearn的OneHotEncoder
train = pd.DataFrame(
    [
        [1000, "male", 23],
        [1001, "female", 22],
        [1002, "male", 69]
    ],
    columns=['id', 'gender', 'age']
)

test = pd.DataFrame(
    [
        [1000, "male", 23],
        [1001, "female", 22],
        [1002, "male", 69],
        [1003, "unknown", 88]
    ],
    columns=['id', 'gender', 'age']
)

train = pd.concat((train, pd.get_dummies(train["gender"], drop_first=True)), axis=1)
train.drop("gender", axis=1)
test = pd.concat((test, pd.get_dummies(test["gender"], drop_first=True)), axis=1)
test.drop("gender", axis=1)

for col in list(test.columns.difference(train.columns)):#train没有的列
    df_obj = pd.DataFrame({col:np.squeeze(np.zeros((1,train.shape[0])))})
    train = pd.concat([train,df_obj], axis=1)
for col in list(train.columns.difference(test.columns)):#test没有的列
    df_obj = pd.DataFrame({col:np.squeeze(np.zeros((1,test.shape[0])))})
    test = pd.concat([test,df_obj], axis=1)

sklearn实现:

from sklearn.preprocessing import OneHotEncoder

train = pd.DataFrame(
    [
        [1000, "male", 23],
        [1001, "female", 22],
        [1002, "male", 69]
    ],
    columns=['id', 'gender', 'age']
)

test = pd.DataFrame(
    [
        [1000, "male", 23],
        [1001, "female", 22],
        [1002, "male", 69],
        [1003, "unknown", 88]
    ],
    columns=['id', 'gender', 'age']
)

# drop:k-1 to represent k; handle_unknown:for missing value
encoder = OneHotEncoder(sparse=False, handle_unknown='ignore', drop="first")
# fit
enc = encoder.fit(train[["gender"]])
# 获取新列名
columns = enc.get_feature_names_out(["gender"])
# 转换测试数据
enc_arr = enc.transform(test[["gender"]])
# 生成dataframe
enc_df = pd.DataFrame(enc_arr, columns=columns)
new_data = pd.concat([test, enc_df], axis=1)
new_data.drop(["gender"], axis=1, inplace=True)
new_data
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值