scikit-learn中的算法都不直接支持分类变量
不只是scikit-learn中的树算法不能直接使用分类变量,scikit-learn中的算法都不直接支持分类变量。在使用这些算法之前,需要将分类变量转换为独热编码(one-hot)或整数类型。
下面这张截图来自 scikit-learn 的社区,解释了为什么 scikit-learn 不能直接使用分类变量,而需要在建模前将其预处理为数值型特征。截图指出,这是因为 scikit-learn 使用 NumPy 数组或 SciPy 的稀疏矩阵来表示数据集,这两种数据结构都无法直接表示类别变量。
举例来说,在天气这个类别变量特征中,是不能用"Rain"、"Sunny"、"Cloudy"这样的字符串形式的,而是应该使用[1, 0, 0]、[0, 1, 0]、[0, 1, 0] 这样的独热编码来分别表示 "Rain"、 "Sunny"、 "Cloudy"。
除one-hot编码之外,也可以转成整数的编码,如使用0、1、2这样的整数表示"Rain"、"Sunny"、"Cloudy"。但这种表示方式会错误地赋予分类值大小关系,而这并非分类变量本身所具有的特性,所以应避免将类别变量转换成整数形式,而应使用独热编码形式。
可以看出,scikit-learn 只能处理数值型特征,如整数或浮点数。它无法直接处理文本形式的分类变量。因此,需要将分类变量转换为独热编码形式,即包含 {0, 1} 两个数值。这里的 0 和 1 虽然是数值型变量,但它们实际上表示某个特征的存在与否。本质上,这是使用整数 0 和 1 来表示逻辑假和逻辑真。
分类变量的转换例程
下面看一个例子,这是一个使用OneHotEncoder将分类变量转换为独热编码形式的示例代码:
import pandas as pd
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, classification_report
from sklearn.preprocessing import OneHotEncoder
from sklearn.compose import ColumnTransformer
# 创建一个包含离散特征的示例数据集
data = {
'颜色': ['红', '蓝', '绿', '红', '蓝', '绿', '红', '蓝'],
'大小': ['大', '中', '小', '大', '中', '小', '中', '小'],
'形状': ['圆', '方', '三角', '圆', '方', '三角', '方', '圆'],
'类别': ['A', 'B', 'A', 'A', 'B', 'B', 'A', 'B']
}
# 创建DataFrame
df = pd.DataFrame(data)
# 分离特征和目标变量
X = df.drop('类别', axis=1)
y = df['类别']
# 创建ColumnTransformer对象来应用One-Hot编码
ct = ColumnTransformer([('encoder', OneHotEncoder(sparse=False), ['颜色', '大小', '形状'])], remainder='passthrough')
# 对特征进行One-Hot编码
X_encoded = ct.fit_transform(X)
# 获取编码后的特征名称
feature_names = ct.named_transformers_['encoder'].get_feature_names_out(['颜色', '大小', '形状'])
# 创建包含编码后特征的DataFrame
X_encoded_df = pd.DataFrame(X_encoded, columns=feature_names)
# 打印 X_encoded_df 的内容
print("X_encoded_df 的内容:")
print(X_encoded_df)
# 可以添加以下行来限制输出的行数,如果数据集很大的话
# print(X_encoded_df.head(10)) # 只打印前10行
# 打印 X_encoded_df 的基本信息
print("\nX_encoded_df 的基本信息:")
print(X_encoded_df.info())
# 打印 X_encoded_df 的统计摘要
print("\nX_encoded_df 的统计摘要:")
print(X_encoded_df.describe())
# 分割数据集为训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X_encoded_df, y, test_size=0.2, random_state=42)
# 创建并训练CART决策树
cart = DecisionTreeClassifier(random_state=42)
cart.fit(X_train, y_train)
# 在测试集上进行预测
y_pred = cart.predict(X_test)
# 计算准确率
accuracy = accuracy_score(y_test, y_pred)
print(f"模型准确率: {accuracy:.2f}")
# 打印分类报告
print("\n分类报告:")
print(classification_report(y_test, y_pred))
# 打印特征重要性
print("\n特征重要性:")
for feature, importance in zip(X_encoded_df.columns, cart.feature_importances_):
print(f"{feature}: {importance:.4f}")
# 可视化决策树
from sklearn.tree import plot_tree
import matplotlib.pyplot as plt
plt.figure(figsize=(20,10))
plot_tree(cart,
feature_names=list(X_encoded_df.columns),
class_names=list(cart.classes_),
filled=True,
rounded=True)
plt.show()
该代码展示了如何使用决策树模型(CART)对离散类别变量进行处理,并且通过 One-Hot Encoding
的方式将类别变量转换为数值型特征。下面我将逐步解释代码的各个部分,并详细说明如何将类别变量转变成 One-Hot
变量。
1. 创建示例数据集
data = {
'颜色': ['红', '蓝', '绿', '红', '蓝', '绿', '红', '蓝'],
'大小': ['大', '中', '小', '大', '中', '小', '中', '小'],
'形状': ['圆', '方', '三角', '圆', '方', '三角', '方', '圆'],
'类别': ['A', 'B', 'A', 'A', 'B', 'B', 'A', 'B']
}
df = pd.DataFrame(data)
这段代码创建了一个包含 8 条记录的小型数据集。数据集中的特征变量是 颜色、大小 和 形状,目标变量是 类别。每个特征变量都是离散类别变量,并且目标变量“类别”包含 A
和 B
两个类别。
2. 特征与目标变量分离
X = df.drop('类别', axis=1) # 特征
y = df['类别'] # 目标变量
将特征和目标变量分离,X
中包含了所有特征(颜色、大小、形状),而 y
包含了目标变量“类别”。
3. 创建 ColumnTransformer
对象并进行 One-Hot Encoding
ct = ColumnTransformer([('encoder', OneHotEncoder(sparse=False), ['颜色', '大小', '形状'])], remainder='passthrough')
这段代码创建了一个 ColumnTransformer
对象,该对象用于将 One-Hot Encoding
应用于指定的列(颜色
、大小
、形状
)。ColumnTransformer
是 sklearn
中用于将不同的预处理操作应用于不同列的工具。它的主要参数如下:
- [('encoder', OneHotEncoder(sparse=False), ['颜色', '大小', '形状'])]:
encoder
是一个别名,用于标识该ColumnTransformer
中的OneHotEncoder
编码器。OneHotEncoder(sparse=False)
指定使用One-Hot
编码器来将离散类别特征转换为One-Hot
格式,并且sparse=False
表示返回的编码结果是一个密集矩阵(Dense Matrix
),而不是稀疏矩阵(Sparse Matrix
)。['颜色', '大小', '形状']
指定需要进行One-Hot Encoding
的列。
remainder='passthrough'
:- 表示其他未被列出用于
One-Hot Encoding
的列(在本例中不存在)将不作任何处理,直接保留在输出中。
- 表示其他未被列出用于
4. 将特征进行 One-Hot Encoding
X_encoded = ct.fit_transform(X)
这段代码将 One-Hot Encoding
应用于特征 X
。fit_transform
方法会:
- 计算每个特征中所有类别值的
One-Hot
编码映射关系。 - 将所有类别变量转换为
One-Hot
形式的数值矩阵。
5. 获取 One-Hot Encoding
后的特征名称
feature_names = ct.named_transformers_['encoder'].get_feature_names_out(['颜色', '大小', '形状'])
使用 ct.named_transformers_['encoder'].get_feature_names_out()
来获取编码后的特征名称。每个特征会根据其原始特征名称和类别值生成相应的 One-Hot
特征名。例如,颜色中的红、蓝、绿会生成特征名:颜色_红
, 颜色_蓝
, 颜色_绿
。
6. 创建包含 One-Hot
编码后的 DataFrame
X_encoded_df = pd.DataFrame(X_encoded, columns=feature_names)
将 One-Hot
编码后的矩阵转换为 DataFrame
格式,并赋予对应的列名。打印输出时可以看到如下形式的表格:
颜色_红 | 颜色_蓝 | 颜色_绿 | 大小_大 | 大小_中 | 大小_小 | 形状_圆 | 形状_方 | 形状_三角 |
---|---|---|---|---|---|---|---|---|
1.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 |
0.0 | 1.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 1.0 | 0.0 |
0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 1.0 |
... | ... | ... | ... | ... | ... | ... | ... | ... |
7. 数据集划分、模型训练与测试
X_train, X_test, y_train, y_test = train_test_split(X_encoded_df, y, test_size=0.2, random_state=42)
cart = DecisionTreeClassifier(random_state=42)
cart.fit(X_train, y_train)
- 使用
train_test_split
将数据集划分为训练集和测试集,比例为 80% 训练集和 20% 测试集。 - 创建一个
DecisionTreeClassifier
实例,并使用训练集X_train
和y_train
进行模型训练。
8. 预测与评估
y_pred = cart.predict(X_test)
accuracy = accuracy_score(y_test, y_pred)
- 使用训练好的模型在测试集上进行预测,并计算模型的准确率(Accuracy)。
9. 分类报告和特征重要性
print(classification_report(y_test, y_pred))
- 打印分类报告,显示模型在不同类别上的精确度(Precision)、召回率(Recall)和 F1 值。
for feature, importance in zip(X_encoded_df.columns, cart.feature_importances_):
print(f"{feature}: {importance:.4f}")
- 打印每个
One-Hot
编码后的特征在决策树模型中的重要性(Feature Importance)。
10. 可视化决策树
plot_tree(cart, feature_names=list(X_encoded_df.columns), class_names=list(cart.classes_), filled=True, rounded=True)
- 使用
plot_tree
函数可视化决策树。feature_names
参数用于指定特征名称,class_names
用于指定类别名称,filled=True
使节点根据类别填充颜色,rounded=True
使节点边框变为圆角。
总结
- 该代码展示了如何使用
One-Hot Encoding
将离散类别特征转换为数值型特征,并使用DecisionTreeClassifier
进行建模。 One-Hot Encoding
是将每个类别特征转化为多个二进制特征(0 或 1),从而使得模型能够处理这些类别型变量。- 通过
ColumnTransformer
结合OneHotEncoder
的方式,可以在一个步骤中完成多个列的One-Hot
编码,并最终将编码结果用于模型训练和评估。