day 35打卡
day 机器学习管道pipeline
基础概念
pipeline在机器学习领域被称为“管道”也可以翻译为“流水线”是机器学习中一个重要的概念。
通常会按照一定的顺序对数据进行预处理、特征提取、模型训练和模型评估等。转换器(transformer)
是一个用于对数据进行预处理和特征提取的estimator,他实现一个transformer 。转换器通常用于对数据进行预处理,例如对数据进行归一化,标准化、缺失值等,转换器也用于对数据进行特征提取,例如对数据进行特征选择、特征组合等。转换器也可以用于对数据进行特征提取。
转换器的特点是无状态,不会存储任何与无关于数据的状态信息。转换器仅根据输入数据学习转换规则。并在训练集上学习转换规则,并在训练集之外的新数据上应用这些规则。
常见的转换器包括数据缩放器(如standardscaler,MinMaxScaler)、特征选择器(如 selectbest\PCA)特征提取器(如CountVectorizer、TF-idfvectorizer)等估计器(estimator)
估计器是实现机器学习算法的对象或类。它用于拟合(fit)数据并进行预测,估计是机器学习模型的基本组成部分,用于从数据中学习模型、进行预测和进行模型评估。
估计器主要方法是fit 和predict。fit 方法用于根据输入数据学习模型的参数和规律,而predict 方法用于根据学习到的参数和规律对新数据进行预测。
估计器的特点是有状态的,他们在训练过程中存储了关于数据的状态信息,以便在预测阶段使用。估计器通过学习训练数据中的模型和规律进行预测。因此估计器需要在训练集上进行训练,并使用训练得倒的模型参数对新数据进行预测。
管道
了解了分类器和估计器,所以可以理解为咋机器学习由转换器、估计器、按照一定顺序组合在一起来完成流程。
机器学习的管道机制通过将多个转换器和估计器顺序连接在一起,可以构建一个一个完整的数据处理和模型训练流程。pipeline 最大的价值和核心应用场景之一,就是与交叉验证和网格搜索等结合使用:
1、防止数据泄漏:这是在使用交叉验证时,pipeline自动完成预处理并在每个折叠内独立(fit transform)的关键优势;
2、简化超参数调优:可以方便同时调优预处理步骤和模型的参数。代码演示
没有pipline 的代码# 先运行之前预处理好的代码
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
warnings.filterwarnings('ignore')plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
data=pd.read_csv('/Users/gj/东财-学习/python相关资料学习/Python60DaysChallenge-main/data.csv')discrete_features = data.select_dtypes(include=['object']).columns.tolist()
home_ownership_mapping={'Own Home':1,'Rent':2,'Have Mortgage':3,'Home Mortgage':4
}
data['Home Ownership']=data['Home Ownership'].map(home_ownership_mapping)
years_in_mortgage_mapping={'<1 year':1,'1 year':2,'2 years':3,'3 years':4,'4 years':5,'5 years':6,'6 years':7,'7 years':8,'8 years':9,'9 years':10,'10+ years':11
}
data['Years in current job']=data['Years in current job'].map(years_in_mortgage_mapping)data=pd.get_dummies(data,columns=['Purpose'])
data2=pd.read_csv('/Users/gj/东财-学习/python相关资料学习/Python60DaysChallenge-main/data.csv')
list_final=[]
for i in data.columns:if i not in data2.columns:list_final.append(i)
for i in list_final:data[i]=data[i].astype(int)term_mapping={'Short Term':0,'Long Term':1
}
data['Term']=data['Term'].map(term_mapping)
data.rename(columns={'Term':'Long Term'},inplace=True)
continuous_features = data.select_dtypes(include=['int64','float64']).columns.tolist()
from sklearn.model_selection import train_test_split
X=data.drop(['Credit Default'],axis=1)
y=data['Credit Default']
X_train,X_test,y_train,y_test=train_test_split(X,y,test_size=0.2,random_state=42)
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score,classification_report,confusion_matrix
import warnings
warnings.filterwarnings('ignore')
print ("-----1、默认参数随机森林(训练集)-》测试集")
import time
start_time=time.time()
rf_model=RandomForestClassifier(random_state=42)
rf_model.fit(X_train,y_train)
rf_pred=rf_model.predict(X_test)
end_time=time.time()
print(f"默认参数随机森林分类器耗时:{end_time-start_time:.4f}秒")print("\n默认参数随机森林分类器 在测试集上的分类报告:")
print(classification_report(y_test, rf_pred))
print("默认随机森林在测试集上的混淆矩阵")
print (confusion_matrix(y_test,rf_pred))
pipeline的代码教学
导入库和数据加载import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import time
import warnings
warnings.filterwarnings('ignore')plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus']=False
from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import OrdinalEncoder,OneHotEncoder,StandardScaler
from sklearn.impute import SimpleImputer
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report,confusion_matrixdata=pd.read_csv("/Users/gj/东财-学习/python相关资料学习/Python60DaysChallenge-main/data.csv")
print ("原属数据加载完成,形状为:",data.shape)
print ("数据前五行:\n",data.head())
# ----分离特征和标签
y=data['Credit Default']
X=data.drop(['Credit Default'],axis=1)
print("\n 特征和标签分离完成")
print("特征形状:",X.shape)
print("标签形状:",y.shape)# 划分训练集和测试集
X_train,X_test,y_train,y_test=train_test_split(X,y,test_size=0.2,random_state=42)
print("\n 训练集和测试集划分完成")
print("训练集形状:",X_train.shape)
print("测试集形状:",X_test.shape)
print("训练集标签形状:",y_train.shape)
print("测试集标签形状:",y_test.shape)定义预处理步骤
colum transformer 的核心
# --- 定义不同列的类型和它们对应的预处理步骤 ---
# 这些定义是基于原始数据 X 的列类型来确定的# 识别原始的 object 列 (对应你原代码中的 discrete_features 在预处理前)
object_cols = X.select_dtypes(include=['object']).columns.tolist()
# 识别原始的非 object 列 (通常是数值列)
numeric_cols = X.select_dtypes(exclude=['object']).columns.tolist()# 有序分类特征 (对应你之前的标签编码)
# 注意:OrdinalEncoder默认编码为0, 1, 2... 对应你之前的1, 2, 3...需要在模型解释时注意
# 这里的类别顺序需要和你之前映射的顺序一致
ordinal_features = ['Home Ownership', 'Years in current job', 'Term']
# 定义每个有序特征的类别顺序,这个顺序决定了编码后的数值大小
ordinal_categories = [['Own Home', 'Rent', 'Have Mortgage', 'Home Mortgage'], # Home Ownership 的顺序 (对应1, 2, 3, 4)['< 1 year', '1 year', '2 years', '3 years', '4 years', '5 years', '6 years', '7 years', '8 years', '9 years', '10+ years'], # Years in current job 的顺序 (对应1-11)['Short Term', 'Long Term'] # Term 的顺序 (对应0, 1)
]
# 构建处理有序特征的 Pipeline: 先填充缺失值,再进行有序编码
ordinal_transformer = Pipeline(steps=[('imputer', SimpleImputer(strategy='most_frequent')), # 用众数填充分类特征的缺失值('encoder', OrdinalEncoder(categories=ordinal_categories, handle_unknown='use_encoded_value', unknown_value=-1))
])
print("有序特征处理 Pipeline 定义完成。")# 标称分类特征 (对应你之前的独热编码)
nominal_features = ['Purpose'] # 使用原始列名
# 构建处理标称特征的 Pipeline: 先填充缺失值,再进行独热编码
nominal_transformer = Pipeline(steps=[('imputer', SimpleImputer(strategy='most_frequent')), # 用众数填充分类特征的缺失值('onehot', OneHotEncoder(handle_unknown='ignore', sparse_output=False)) # 进行独热编码, sparse_output=False 使输出为密集数组
])
print("标称特征处理 Pipeline 定义完成。")# 连续特征 (对应你之前的众数填充 + 添加标准化)
# 从所有列中排除掉分类特征,得到连续特征列表
# continuous_features = X.columns.difference(object_cols).tolist() # 原始X中非object类型的列
# 也可以直接从所有列中排除已知的有序和标称特征
continuous_features = [f for f in X.columns if f not in ordinal_features + nominal_features]# 构建处理连续特征的 Pipeline: 先填充缺失值,再进行标准化
continuous_transformer = Pipeline(steps=[('imputer', SimpleImputer(strategy='most_frequent')), # 用众数填充缺失值 (复现你的原始逻辑)('scaler', StandardScaler()) # 标准化,一个好的实践 (如果你严格复刻原代码,可以移除这步)
])
print("连续特征处理 Pipeline 定义完成。")# --- 构建 ColumnTransformer ---
# 将不同的预处理应用于不同的列子集,构造一个完备的转化器
# ColumnTransformer 接收一个 transformers 列表,每个元素是 (名称, 转换器对象, 列名列表)
preprocessor = ColumnTransformer(transformers=[('ordinal', ordinal_transformer, ordinal_features), # 对 ordinal_features 列应用 ordinal_transformer('nominal', nominal_transformer, nominal_features), # 对 nominal_features 列应用 nominal_transformer('continuous', continuous_transformer, continuous_features) # 对 continuous_features 列应用 continuous_transformer],remainder='passthrough' # 如何处理没有在上面列表中指定的列。# 'passthrough' 表示保留这些列,不做任何处理。# 'drop' 表示丢弃这些列。
)print("\nColumnTransformer (预处理器) 定义完成。")
# print(preprocessor) # 可以打印 preprocessor 对象看看它的结构构建完整的pipelinepipeline=Pipeline(steps=[('preprocessor',preprocessor),('classifier',RandomForestClassifier(random_state=42))
])
print("\n 完整的pipeline定义完成")
使用pipeline进行训练和评估
# -----1.使用pipeline 在划分好的训练集和测试集上评估
print("\n-----1.默认参数随机森林(训练集)——测试集")
start_time=time.time()
pipeline.fit(X_train,y_train)
pipeline_pred=pipeline.predict(X_test)
end_time=time.time()
print(f"pipeline训练耗时:{end_time-start_time:.4f}秒")
print("\n 默认随机森林 在测试集上的分类报告:")
print(classification_report(y_test, pipeline_pred))
print ("\n默认随机森林 在测试集上的混淆矩阵:")
print(confusion_matrix(y_test, pipeline_pred))代码汇总
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import time
import warnings
warnings.filterwarnings('ignore')plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# pipeline 相关预处理工具
from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer# 用于将预处理应用于不同的列,之前是对datafame 的某一列手动处理,如果在pipeline中直接用standSCaler 等函数就会对所有列处理,所以用这个工具
from sklearn.preprocessing import StandardScaler,OneHotEncoder,OneHotEncoder# 用于数据预处理from sklearn.impute import SimpleImputer# 用于处理缺失值# 机器学习相关库
from sklearn.ensemble import RandomForestClassifier# 随机森林分类器
from sklearn.metrics import classification_report,confusion_matrix,accuracy_score,precision_score,recall_score,f1_score# 用于评估模型性能
from sklearn.model_selection import train_test_split# 用于划分训练集和测试集data=pd.read_csv('/Users/gj/东财-学习/python相关资料学习/Python60DaysChallenge-main/data.csv')y=data['Credit Default']
X=data.drop(['Credit Default'],axis=1)# 划分
X_train,X_test,y_train,y_test=train_test_split(X,y,test_size=0.2,random_state=42)
object_cols=X.select_dtypes(include=['object']).columns.tolist()# 选择类别型变量ordinal_features = ['Home Ownership', 'Years in current job', 'Term']
ordinal_categories=[['Own Home', 'Rent', 'Have Mortgage', 'Home Mortgage'], # Home Ownership 的顺序 (对应1, 2, 3, 4)['< 1 year', '1 year', '2 years', '3 years', '4 years', '5 years', '6 years', '7 years', '8 years', '9 years', '10+ years'], # Years in current job 的顺序 (对应1-11)['Short Term', 'Long Term'] # Term 的顺序 (对应0, 1)
]
# 先用众数填充分类特征的缺失值,然后进行有序编码
ordinal_transformer = Pipeline(steps=[('imputer', SimpleImputer(strategy='most_frequent')), # 用众数填充分类特征的缺失值('encoder', OrdinalEncoder(categories=ordinal_categories, handle_unknown='use_encoded_value', unknown_value=-1))
])
# 分类特征
nominal_features=['Purpose']
nominal_transformer=Pipeline(steps=[('imputer',SimpleImputer(strategy='most_frequent')),('onehot',OneHotEncoder(handle_unknown='ignore',sparse_output=False ) )
])
# 连续特征
continuous_features=X.columns.difference(object_cols).tolist()# 先用众数填充缺失值,进行标准化
continuous_transformer=Pipeline(steps=[('imputer',SimpleImputer(strategy='most_frequent')),('scaler',StandardScaler())
])
# ---构建columntransformer
preprocessor=ColumnTransformer(transformers=[('ordinal',ordinal_transformer,ordinal_features),('nominal',nominal_transformer,nominal_features),('continuous',continuous_transformer,continuous_features) ],remainder='passthrough'
)# ----1.使用pipeline在划分的训练集呵测试集
print("------1.默认参数随机森林(训练集)---测试集")
start_time=time.time()
pipeline.fit(X_train,y_train)
pipeline_pred=pipeline.predict(X_test)
end_time=time.time()
print(f"默认参数随机森林分类器耗时:{end_time-start_time:.4f}秒")
print("默认参数随机森林分类器 在测试集上的分类报告:")
print(classification_report(y_test, pipeline_pred))
print("默认参数随机森林分类器 在测试集上的混淆矩阵:")
print(confusion_matrix(y_test, pipeline_pred))
@浙大疏锦行