import pandas as pd import numpy as np data = pd.read_csv("digit recognizor.csv") # print(data.head()) x = data.iloc[:, 1:] y = data.iloc[:, 0] # print(x.shape) ##(42000, 784) """ 数据量相对夸张,如果使用支持向量机和神经网络,可能会直接跑不出来。使用KNN跑一次需要半个小时 用这个数据,能更体现特征工程的重要性 方差过滤 """ # todo: Filter 过滤法 from sklearn.feature_selection import VarianceThreshold # 方差过滤 # todo::::::::::::::::::::::::::方差过滤 # 不论接下来特征工程要做什么,都要优先消除方差为(默认阈值0)的特征 selector = VarianceThreshold() # 实例化,不填默认方差为0 x_var0 = selector.fit_transform(x) # 删除不合格特征,生成新矩阵 # # print(x.var().values) # 获取所有方差 # # print(np.median(x.var().values)) # 方差中位数 # # 如果想把特征删掉一半 x_fsvar = VarianceThreshold(np.median(x.var().values)).fit_transform(x) # print(x_fsvar.shape) # # # 若特征是伯努利随机变量,假设p=0.8,即二分类特征中某种分类占到80%以上删除这种特征 # x_bvar=VarianceThreshold(0.8*(1-0.8)).fit_transform(x) # print(x_bvar.shape) # todo::::::::::::::::::::::::::相关过滤 """ 1.卡方过滤: 专门针对离散型标签(即分类问题)的相关性过滤 不能计算负数 """ from sklearn.ensemble import RandomForestClassifier as RFC from sklearn.model_selection import cross_val_score from sklearn.feature_selection import SelectKBest # 选择k个 from sklearn.feature_selection import chi2 # 卡方检验 #### 假设在这里我已经我需要300个特征 # x_fschi = SelectKBest(chi2,k=300).fit_transform(x_fsvar,y) # print(x_fschi.shape) # #### 交叉验证查看效果 ## print(cross_val_score(RFC(n_estimators=10, random_state=0), x_fschi,y,cv=5).mean()) #### 使用学习曲线查看最优的特征k数量,大概需要跑5分钟 ## 发现结果是单调递增的,所以得特征都是有用的,卡方值很难界定有效的范围 # import matplotlib.pyplot as plt # score=[] # for i in range(390,200,-10): # x_fschi=SelectKBest(chi2,k=i).fit_transform(x_fsvar,y) # once=cross_val_score(RFC(n_estimators=10,random_state=0),x_fschi,y,cv=5).mean() # score.append(once) # plt.plot(range(390,200,10),score) # plt.show() ######更好的办法,通过p值 ### p值作用 chivalue, pvalues_chi = chi2(x_fsvar, y) # print(chivalue) # 卡方值 # print(pvalues_chi) # p值 # k取多少,我们先要消除所以p值大于设定值,比如0.05或0.01的特征 k = chivalue.shape[0] - (pvalues_chi > 0.05).sum() # 特征总数-大于0.05的特征数总和 print(k)
""" 2. F检验 ANOVA 方差齐性检验,用来捕捉每个特征与标签之间的线性关系的过滤方法 """ # todo: F检验: 寻找俩组数据之间的线性关系 # F 类似卡方,很难界定 # frature_selection.f_classif (F检验分类) # frature_selection.f_regression (F检验回归) from sklearn.feature_selection import f_classif # F, pvalues_f = f_classif(x_fsvar, y) # print(F) # 找出合理的k值 # k = F.shape[0] - (pvalues_f > 0.05).sum() # print(k) # X_fsF = SelectKBest(f_classif, k=k).fit_transform(x_fsvar, y) # cross_val_score(RFC(n_estimators=10, random_state=0), X_fsF, y, cv=5).mean() # todo: 互信息法 """ 3.互信息法: """ # 互信息分类 from sklearn.feature_selection import mutual_info_classif as MIC # 互信息回归 from sklearn.feature_selection import mutual_info_regression # result = MIC(x_fsvar, y) # k = result.shape[0] - sum(result <= 0) ##### # todo::::::::::::::::::::::::::嵌入法 # 重要参数 # estimator 使用的模型评估器 # threshold 特征重要性的阈值 from sklearn.feature_selection import SelectFromModel from sklearn.ensemble import RandomForestClassifier as RFC # RFC_ = RFC(n_estimators=10, random_state=0) # X_embedded = SelectFromModel(RFC_, threshold=0.005).fit_transform(x, y) # 在这里我只想取出来有限的特征。0.005这个阈值对于有780个特征的数据来说,是非常高的 # 只能分到大概0.001的feature_importances_ # print(X_embedded.shape) # 阈值取多少合适? # 学习曲线 (少说起码要跑十分钟) import numpy as np # RFC_.fit(x,y).feature_importances_ # threshold = np.linspace(0,(RFC_.fit(x,y).feature_importances_).max(),20) # score = [] # for i in threshold: # x_embedded = SelectFromModel(RFC_,threshold=i).fit_transform(x,y) # once=cross_val_score(RFC_,x_embedded,y,cv=5).mean() # score.append(once) # plt.plot(threshold,score) # plt.show() # x_embedd = SelectFromModel(RFC_, threshold=0.00067).fit_transform(x, y) # print(cross_val_score(RFC_, x_embedd, y, cv=5).mean()) ##0.939905083368037 # 根据上面的图可以看到,目前最好的范围可能是在0-0.00134之间,再画图具体找到最好的值 # 十几分钟跑完 # score2=[] # for i in np.linspace(0,0.00134,20): # x_embedd = SelectFromModel(RFC_,threshold=i).fit_transform(x,y) # once = cross_val_score(RFC_, x_embedd, y, cv=5).mean() # score2.append(once) # plt.figure(figsize=[20,5]) # plt.plot(np.linspace(0,0.00134,20),score2) # plt.show() ###结论,最高点是0.000564 # 跑一下模型 # x_embedd = SelectFromModel(RFC_, threshold=0.000564).fit_transform(x, y) # cross_val_score(RFC_, x_embedd, y, cv=5).mean() # 结果 0.94083354150556387 # 然后调一下别的,rfc模型的n_estimators # RFC_ = RFC(n_estimators=100, random_state=0) # x_embedd = SelectFromModel(RFC_, threshold=0.000564).fit_transform(x, y) # cross_val_score(RFC_, x_embedd, y, cv=5).mean() # 结果 0.9639525817795566 # todo::::::::::::::::::::::::::包装法 """ 计算成本位于过滤法和嵌入法之间 也是一个特质选择和算法训练同时进行的方法 """ # 目标函数是递归特征消除法 # feature_selection.RFE # 参数 estimator 评估器 # n_features_to_select 想要选择的特征个数 # step 希望移出的特征个数 from sklearn.feature_selection import RFE RFC_ = RFC(n_estimators=10, random_state=0) # selector = RFE(RFC_, n_features_to_select=340, step=50).fit(x, y) # print(selector.support_) # 返回所有特征最后是否被选中的布尔矩阵 # print(selector.support_.sum()) # 最后被选中的特征加和 # print(selector.ranking_) # 返回特征的按次数迭代中的综合重要性的排名 # X_weapper = selector.transform(x) # 使用包装法得到的特征矩阵 # print(cross_val_score(RFC_, X_weapper, y, cv=5).mean()) # 0.9389522459432109 # 对包装法画学习曲线 # 这玩意也要画好久,大概10分钟 # score = [] # for i in range(1, 751, 50): # x_wrapper = RFE(RFC_, n_features_to_select=i, step=50).fit(x, y) # once = cross_val_score(RFC_, x_wrapper, y, cv=5).mean() # score.append(once) # plt.figure(figsize=[20, 5]) # plt.plot(range(1, 751, 50), score) # plt.xticks(range(1, 751, 50)) # plt.show() ##结果,应用50个特征时,模型的表现就已经达到了90%以上 ### 然后就去调吧,调的头皮发麻 # todo:::::总结 # 数据量大的时候,优先使用方差过滤和互信息法,在上其他的特征选择方法 # 逻辑回归时,优先使用嵌入法 # 使用向量机时,优先使用包装法 # 迷茫的时候,过滤法走起 # 崩溃时,建议该行送外卖或者手机贴膜