网站首页 > 技术文章 正文
在数据分析中,分类变量(categorical variables)需要经过适当的处理,以便能够被大多数机器学习算法所接受。以下是几种常用的处理方法,每种方法都有其独特的优点和缺点↓
【数据介绍】
创建包含数值变量(访客数,单价,支付人数)和分类变量(性别,产品颜色)的数据集↓
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score, mean_squared_error
from statsmodels.api import OLS, add_constant
import category_encoders as ce
n_samples = 200
visitors = np.random.randint(50, 1000, size=n_samples)
price = np.random.uniform(5, 100, size=n_samples)
paying_customers = np.random.randint(1, 50, size=n_samples)
gender = np.random.choice(['男', '女'], size=n_samples)
product_color = np.random.choice(['红', '蓝', '白'], size=n_samples)
sales = (0.5 * visitors + 2 * price + 3 * paying_customers) * (np.where(gender == '男', 2, 1)) + np.random.normal(0, 50, n_samples)
df = pd.DataFrame({
'访客数': visitors,
'单价': price,
'支付人数': paying_customers,
'性别': gender,
'产品颜色': product_color,
'销售额': sales
})
【标签编码(Label Encoding)】
标签编码是将每个类别映射到一个唯一的整数。例如,假设有一个包含三种类别的变量 ['红', '蓝', '绿'],标签编码可能将其转换为 [0, 1, 2]。
优点:
- 简单易用,特别适用于有序的分类变量;
- 不会增加维度,数据集的大小保持不变。
缺点:
- 对于无序的分类变量(例如,颜色),标签编码可能引入错误的顺序关系,导致模型误解这些数据的本质。
encoder = ce.OrdinalEncoder(cols=['性别', '产品颜色'])
X = df.drop(columns=['销售额'])
y = df['销售额']
X_encoded = encoder.fit_transform(X, y)
X_train, X_test, y_train, y_test = train_test_split(X_encoded, y, test_size=0.2, random_state=0)
model = LinearRegression()
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
r2 = r2_score(y_test, y_pred)
mse = mean_squared_error(y_test, y_pred)
X_const = add_constant(X_train)
ols_model = OLS(y_train, X_const).fit()
数据结果指标这里就不详细介绍了,这里模型的结果还是很优秀的,具体的可以参考之前几篇回归分析的内容,里面有详细的介绍。
plt.figure(figsize=(10, 6))
plt.scatter(y_test, y_pred, alpha=0.6, color='b')
plt.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], 'r--', lw=2)
plt.xlabel('实际销售额')
plt.ylabel('预测销售额')
plt.title(f'标签编码\nR2: {r2:.4f}, MSE: {mse:.4f}')
plt.show()
从图形上看,整体效果也还不错。接下来就使用模型进行新数据的预测↓
new_visitors = np.random.randint(50, 1000, size=20)
new_price = np.random.uniform(5, 100, size=20)
new_paying_customers = np.random.randint(1, 50, size=20)
new_gender = np.random.choice(['男', '女'], size=20)
new_product_color = np.random.choice(['红', '蓝', '白'], size=20)
new_data = pd.DataFrame({
'访客数': new_visitors,
'单价': new_price,
'支付人数': new_paying_customers,
'性别': new_gender,
'产品颜色': new_product_color
})
# 对新数据进行标签编码
new_data_encoded = encoder.transform(new_data)
# 对新数据进行预测
new_data['预测销售额'] = model.predict(new_data_encoded)
plt.figure(figsize=(10, 6))
plt.scatter(y_test, y_pred, alpha=0.6, color='b')
plt.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], 'r--', lw=2)
plt.xlabel('实际销售额')
plt.ylabel('预测销售额')
plt.title(f'独热编码\nR2: {r2:.4f}, MSE: {mse:.4f}')
plt.show()
【独热编码(One-Hot Encoding)】
独热编码为每个类别创建一个新的二进制变量。例如,对于变量 ['红', '蓝', '绿'],会生成三个新的变量:红, 蓝, 绿,并用 0 或 1 表示某个类别是否存在。
优点:
- 消除了类别之间的顺序关系,非常适合无序的分类变量;
- 广泛支持,大多数机器学习算法都能处理这种编码方式。
缺点:
- 当类别数较多时,会显著增加数据集的维度,可能导致计算资源和时间的消耗增加。
# 独热编码
encoder = ce.OneHotEncoder(cols=['性别', '产品颜色'], use_cat_names=True)
X_encoded = encoder.fit_transform(X, y)
X_train, X_test, y_train, y_test = train_test_split(X_encoded, y, test_size=0.2, random_state=0)
model = LinearRegression()
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
r2 = r2_score(y_test, y_pred)
mse = mean_squared_error(y_test, y_pred)
X_const = add_constant(X_train)
ols_model = OLS(y_train, X_const).fit()
# 对新数据进行独热编码
new_data_encoded = encoder.transform(new_data)
# 对新数据进行预测
new_data['预测销售额'] = model.predict(new_data_encoded)
【二进制编码(Binary Encoding)】
二进制编码首先将类别转换为整数,然后再将整数转换为二进制表示。例如,对于变量 ['红', '蓝', '绿'],假设它们对应的整数编码为 [1, 2, 3],它们的二进制编码则为 [01, 10, 11]。
优点:
- 比独热编码更节省空间,减少维度;
- 结合了标签编码和独热编码的优点,适用于大类别集合。
缺点:
- 仍然可能引入一定的顺序关系,虽然较弱;
- 复杂度较高,理解和实现上比前两种方法稍难。
encoder = ce.BinaryEncoder(cols=['性别', '产品颜色'])
X_encoded = encoder.fit_transform(X, y)
X_train, X_test, y_train, y_test = train_test_split(X_encoded, y, test_size=0.2, random_state=0)
model = LinearRegression()
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
r2 = r2_score(y_test, y_pred)
mse = mean_squared_error(y_test, y_pred)
X_const = add_constant(X_train)
ols_model = OLS(y_train, X_const).fit()
plt.figure(figsize=(10, 6))
plt.scatter(y_test, y_pred, alpha=0.6, color='b')
plt.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], 'r--', lw=2)
plt.xlabel('实际销售额')
plt.ylabel('预测销售额')
plt.title(f'二进制编码\nR2: {r2:.4f}, MSE: {mse:.4f}')
plt.show()
new_data_encoded = encoder.transform(new_data)
# 对新数据进行预测
new_data['预测销售额'] = model.predict(new_data_encoded)
【频率编码(Frequency Encoding)】
频率编码是用类别出现的频率或概率来替代类别标签。例如,如果红出现了 100次,蓝出现了50次,绿出现了30次,则它们的编码可以是[100, 50, 30]。
优点:
- 保持数据集的大小不变;
- 捕捉类别的重要性(出现频率)。
缺点:
- 频率可能随数据集变化而变化,具有一定的局限性;
- 如果某类别频率过高或过低,可能会引入偏差。
encoder = ce.CountEncoder(cols=['性别', '产品颜色'])
X_encoded = encoder.fit_transform(X, y)
X_train, X_test, y_train, y_test = train_test_split(X_encoded, y, test_size=0.2, random_state=0)
model = LinearRegression()
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
r2 = r2_score(y_test, y_pred)
mse = mean_squared_error(y_test, y_pred)
X_const = add_constant(X_train)
ols_model = OLS(y_train, X_const).fit()
plt.figure(figsize=(10, 6))
plt.scatter(y_test, y_pred, alpha=0.6, color='b')
plt.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], 'r--', lw=2)
plt.xlabel('实际销售额')
plt.ylabel('预测销售额')
plt.title(f'频率编码\nR2: {r2:.4f}, MSE: {mse:.4f}')
plt.show()
new_data_encoded = encoder.transform(new_data)
# 对新数据进行预测
new_data['预测销售额'] = model.predict(new_data_encoded)
【目标编码(Target Encoding)】
目标编码用每个类别对应的目标变量(通常是标签)的平均值来替代类别标签。例如,对于一个分类任务,如果 红 类别的目标变量平均值为 0.8,蓝 类别为 0.5,绿 类别为 0.3,则它们的编码为 [0.8, 0.5, 0.3]。
优点:
- 保留了类别与目标变量之间的关系,有助于提高模型性能;
- 维度不增加,适用于大类别集合。
缺点:
- 容易引入目标泄露(target leakage),需要谨慎处理(例如,通过交叉验证);
- 需要更复杂的处理和理解。
encoder = ce.TargetEncoder(cols=['性别', '产品颜色'])
X_encoded = encoder.fit_transform(X, y)
X_train, X_test, y_train, y_test = train_test_split(X_encoded, y, test_size=0.2, random_state=0)
model = LinearRegression()
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
r2 = r2_score(y_test, y_pred)
mse = mean_squared_error(y_test, y_pred)
X_const = add_constant(X_train)
ols_model = OLS(y_train, X_const).fit()
plt.figure(figsize=(10, 6))
plt.scatter(y_test, y_pred, alpha=0.6, color='b')
plt.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], 'r--', lw=2)
plt.xlabel('实际销售额')
plt.ylabel('预测销售额')
plt.title(f'目标编码\nR2: {r2:.4f}, MSE: {mse:.4f}')
plt.show()
new_data_encoded = encoder.transform(new_data)
# 对新数据进行预测
new_data['预测销售额'] = model.predict(new_data_encoded)
【嵌入编码(Embedding Encoding)】
嵌入编码通常用于深度学习中,通过训练一个嵌入层将类别映射到一个低维的连续向量。例如,一个包含100个类别的变量可以被映射到一个10维的嵌入向量。
优点:
- 可以捕捉类别之间的复杂关系,适用于大规模类别;
- 维度降低,通常对大类别集合很有效。
缺点:
- 需要更多计算资源和训练时间;
- 需要特定的框架和模型(如神经网络)来实现。
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Embedding, Flatten
from sklearn.preprocessing import LabelEncoder
# 标签编码
le_gender = LabelEncoder()
le_color = LabelEncoder()
df['性别'] = le_gender.fit_transform(df['性别'])
df['产品颜色'] = le_color.fit_transform(df['产品颜色'])
# 生成特征和目标变量
X = df[['访客数', '单价', '支付人数', '性别', '产品颜色']]
y = df['销售额']
# 训练和测试集划分
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)
# 嵌入编码
gender_input = tf.keras.Input(shape=(1,))
gender_embed = Embedding(input_dim=len(le_gender.classes_), output_dim=2)(gender_input)
gender_flatten = Flatten()(gender_embed)
color_input = tf.keras.Input(shape=(1,))
color_embed = Embedding(input_dim=len(le_color.classes_), output_dim=3)(color_input)
color_flatten = Flatten()(color_embed)
other_input = tf.keras.Input(shape=(3,))
concat = tf.keras.layers.Concatenate()([other_input, gender_flatten, color_flatten])
dense1 = Dense(128, activation='relu')(concat)
dense2 = Dense(64, activation='relu')(dense1)
output = Dense(1)(dense2)
model = tf.keras.Model(inputs=[other_input, gender_input, color_input], outputs=output)
model.compile(optimizer='adam', loss='mse')
# 训练模型
model.fit([X_train[['访客数', '单价', '支付人数']], X_train['性别'], X_train['产品颜色']], y_train, epochs=100, batch_size=32, verbose=0)
# 预测
y_pred = model.predict([X_test[['访客数', '单价', '支付人数']], X_test['性别'], X_test['产品颜色']])
y_pred = y_pred.flatten()
r2 = r2_score(y_test, y_pred)
mse = mean_squared_error(y_test, y_pred)
嵌入编码:
R2: 0.9138
MSE: 9804.7672
plt.figure(figsize=(10, 6))
plt.scatter(y_test, y_pred, alpha=0.6, color='b')
plt.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], 'r--', lw=2)
plt.xlabel('实际销售额')
plt.ylabel('预测销售额')
plt.title(f'嵌入编码\nR2: {r2:.4f}, MSE: {mse:.4f}')
plt.show()
new_data = pd.DataFrame({
'访客数': new_visitors,
'单价': new_price,
'支付人数': new_paying_customers,
'性别': new_gender,
'产品颜色': new_product_color
})
# 对新数据进行标签编码
new_data['性别'] = le_gender.transform(new_data['性别'])
new_data['产品颜色'] = le_color.transform(new_data['产品颜色'])
# 对新数据进行预测
new_data['预测销售额'] = model.predict([new_data[['访客数', '单价', '支付人数']], new_data['性别'], new_data['产品颜色']]).flatten()
链接是我使用PowerBI整合的历史文章,按类型分类,可以根据需求查询:Microsoft Power BI↓
https://app.powerbi.com/view?r=eyJrIjoiNjI2NWQ3NjktYjU0ZC00ZWZhLTgzMDgtMGI4ZTk1ZDlkODM3IiwidCI6IjI3NDQ3MWQ0LTM4ZDQtNDVlZS1hMmJkLWU1NTVhOTBkYzM4NiJ9
End
猜你喜欢
- 2024-10-12 程序员深夜用Python跑神经网络,只为用中二动作关掉台灯
- 2024-10-12 Pandas第十三课:特征工程与数据预处理
- 2024-10-12 CVPR2019 | 面对高度不均衡数据如何提高精度?这篇文章有妙招
- 2024-10-12 数据特征常用构建方法详解及实例 数据特征包括哪些?
- 2024-10-12 “千克”和“毫升”:单位不同就不能做朋友了吗?
- 2024-10-12 a和one的区别 a与one区别
- 2024-10-12 手把手教你做客户挽留模型【纯技术】
- 2024-10-12 机器学习中的独热编码,你知道多少?
- 2024-10-12 One Hot Encoder 在机器学习分类模型中的重要性
- 2024-10-12 08-人人都懂的人工智能:高维的one-hot编码
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- oraclesql优化 (66)
- 类的加载机制 (75)
- feignclient (62)
- 一致性hash算法 (71)
- dockfile (66)
- 锁机制 (57)
- javaresponse (60)
- 查看hive版本 (59)
- phpworkerman (57)
- spark算子 (58)
- vue双向绑定的原理 (68)
- springbootget请求 (58)
- docker网络三种模式 (67)
- spring控制反转 (71)
- data:image/jpeg (69)
- base64 (69)
- java分页 (64)
- kibanadocker (60)
- qabstracttablemodel (62)
- java生成pdf文件 (69)
- deletelater (62)
- com.aspose.words (58)
- android.mk (62)
- qopengl (73)
- epoch_millis (61)
本文暂时没有评论,来添加一个吧(●'◡'●)