from sklearn import svm
from sklearn.datasets import samples_generator
from sklearn.feature_selection import SelectKBest, f_regression
from sklearn.pipeline import make_pipeline
from sklearn.pipeline import Pipeline
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
# samples_generator是datasets模块下用于数据生成的模块,其中包括常用的make_开头的各种数据生成函数。
# make_classification函数生成用于解决分类问题的随机数据样本。
# 函数首先为每个类别生成符合正态分布的数据簇(标准差=1),特征维度为n_informative,平均为每个类别生成数据簇,再引入特征相互依赖关系和随机添加噪音
# 不重排数据的话,X的特征分布为:原始的n_informative个特征,跟着n_redundant个线性相关的组合特征(与n_informative中特征相关)
# 再跟着n_repeated个重复特征(复制n_informative和n_redundant中的特征),并从中随机替换数值,剩下的特征填充随机噪音
# 因此,有用的特征包含在前(n_informative+n_redundant+n_repeated)个特征中
# n_smaples参数,样本数目
# n_features参数,特征中数目,默认为20个
# n_informative、n_redundant、n_repeated参数如上文
# n_classes参数,类别数目,默认为2
# n_clusters_per_class参数,每个类别下的数据簇数目
# weights参数,列表类型或空值,表示分配给每个类别的样本数目占比是多少
# class_sep参数,数值越大,各类数据分得越开,表示分类越容易进行
# shuffle参数,是否重排数据,为真的话,样本和特征都会重排
# 返回值为(n_samples,n_features)大小的训练数据样本,和(n_samples)大小的样本分类标签
X, y = samples_generator.make_classification(n_features=20, n_informative=3, n_redundant=0, n_classes=4, n_clusters_per_class=2)
# model_selection模块下的函数,从数据集中随机抽取训练数据集和测试数据集
# test_size参数,测试集规模,默认25%
# train_size参数,训练集规模,默认自动计算(测试集剩下的)
# random_state参数,保证每次抽取的数据集和测试集是一致的
# 返回一个列表,列表长度是传入参数中数组个数的二倍,即所有传入的数组都被按照同样的抽取规则分成了两份(前提是传入的数组长度一致)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)
# anova svm-c
# 1)anova filter, take 3 best ranked features
# SelectKBest特征选择类,feature_selection模块中的类,选择k个得分最高的特征
# 第一个参数是评分函数,该函数根据传入的训练数据和标签数据,返回每个特征的评分数组(一对评分值scores和pvalue,或者单个评分值scores)
# 评分函数只能是用于分类的函数
# 第二个参数k,表示选择评分最高的k个特征,默认是10
# 该类有两个数组类的属性,第一个数组是scores评分数组,每个特征的评分,第二个数组为pvalues数组(或者不反悔,根据上一个参数而定)
# 该类的fit方法,执行评分函数,选择合适的特征
# fit_transform方法,添加可选参数,执行评分函数,返回转换后的训练数据
# transform方法,只留下被选择的特征,其他特征删除
# reverse_transform方法,反转换函数,将执行过转换操作的数据反转回原始的版本,恢复转换过程中被删掉的特征
anova_filter = SelectKBest(f_regression, k=3)
# 2)svm
# LinearSVC线性支持向量分类模型,svm模块中,还要一个LinearSVR线性支持向量回归模型
# 与SVC模型类似,也是基于线性核函数,只不过前者依赖于线性模型包实现,而SVC依赖于支持向量机包实现。所以LinearSVC在选择惩罚和损失函数上更灵活
# 当样本中存在数值较大的数据时,标准化后效果更好
# 该模型支持稀疏矩阵也支持密集矩阵数据
# 如果是多分类问题,模型是基于 1 vs the rest 规则实现
# penalty参数,用于惩罚中的范式,默认是L2范式
# loss参数,损失函数
# C参数,对错误项的敏感度
# coef_属性,每一个分类中特征的权重,仅在线性核模型中有效,二分类情况下为(n_features),多分类情况下为(n_classes, n_features)
# 该类中decision_function方法,预测每个样本的评分,评分是根据样本到超平面的距离计算
# fit方法,基于训练数据训练模型
# predict方法,根据训练好的模型,对数据做出预测
clf = svm.LinearSVC()
# make_pipeline函数,pipeline模块中的函数,基于给的模型构造管道类的快捷方法,它既不需要也不允许给模型命名,程序会自动用模型的type值的小写进行命名
# 管道类有点像linux中的管道,按照顺序一个一个执行模型
# 步骤参数,模型列表
# 可选参数memory,是否在执行模型后缓存模型
# 返回值为Pipeline类
# anova_svm = make_pipeline(anova_filter, clf)
anova_svm = Pipeline([('anova_filter', anova_filter),('linearsvc', clf)])
# Pipeline管道类,按序列执行一系列的转换器和一个最终的模型。管道中间的元素一定是起数据转换作用的转换器,即它们必须实现了fit或者transform方法
# 而最后一个元素只需要实现fit方法即可。管道中的转换器通过memory参数被缓存下来
# 管道的目的是把一系列参数不同,但可以交叉验证的步骤组合到一起,因此它允许通过步骤名称+‘__’+参数名称来修改某一个步骤的参数
# 并且可以通过将步骤名称赋值给另一个模型来替换管道中的步骤内容,将步骤设置为‘passthrough’或者‘None’可以直接跳过这一步
# 该类中decision_function方法,应用一系列的转换,和最后一个模型的decision_function
# fit方法,训练模型
# fit_predict方法,转换后调用最后一个模型的fit_predict方法
# fit_transform方法、predict方法、score方法,原理同上
# 这一步针对训练数据和标签数据应用anova_filter转换获取三个最佳特征,再执行LinearSVC分类器
anova_svm.fit(X_train, y_train)
# 对测试数据进行预测
y_pred = anova_svm.predict(X_test)
# 给出针对分类结果度量的文本形式
# 头两个参数分别为真实值和预测值
# labels参数,度量方式的标签,可以是列表,展示多种度量方式的结果,默认包含准确率、召回率、f1分值、支持率
# sample_weight参数,样本的权重,样本权重不同,对分类结果的度量存在影响
print(classification_report(y_test, y_pred))
# 使用管道中的转换器,对管道中最后一个模型LinearSVC的coef_属性进行反转换
coef = anova_svm[:-1].inverse_transform(anova_svm['linearsvc'].coef_)
print(coef)
在执行coef变量这条语句时,无论构建pipeline对象是通过make_pipeline还是通过构造函数,均会报错:
'Pipeline' object is not subscriptable(Pipeline对象不支持下标)
或者:
'Pipeline' object does not support indexing(Pipeline对象不支持索引)
暂时没有找到解决办法,改用Pipeline构造器实例化也有这个问题,但看了一下源码,源码中就是将步骤参数组成一个steps列表,不知道为什么居然不支持索引