Python机器学习库sklearn数据预处理,数据集构建,特征选择

# 显示数据的缺失值
import pandas as pd
from io import StringIO
 
csv_data = '''A,B,C,D
1.0,2.0,3.0,4.0
5.0,6.0,,8.0
10.0,11.0,12.0,'''
# csv_data = unicode(csv_data)
df = pd.read_csv(StringIO(csv_data))
print(df)

1.缺失值处理

df.isnull().sum()  #isnull判断每个位置是否有NaN,计算每一个特征中:有几个样本在该特征上存在缺失 

1.直接删除缺省值多的样本或者特征

df.dropna()  #删除存在缺失值的样本

df.dropna(axis=1)#删除存在缺失值的特征

df.dropna(how='all')  #山所有特征都为缺失的样本

df.dropna(thresh=4)  #删除特征数少于参数指定个数的样本

df.dropna(subset=['C'])  #删除在指定特征处有缺失值的样本

2.处理类别型数据
import pandas as pd
df=pd.DataFrame([['green','M',10.1,'class1'],
                ['red','L',13.5,'class2'],
               ['blue','XL',15.3,'class1']])
df.columns=['color','size','price','classlabel']
df

1)序列特征映射
size_mapping={'XL':3,'L':2,'M':1}
df['size']=df['size'].map(size_mapping)#将size特征列的XL等字符替换成字典
size_mapping#映射对应的数字
df

2)类别编码
import numpy as np
class_mapping={label:idx for idx,label in enumerate(np.unique(df['classlabel']))}
#enumerate将列表参数映射成带序号的元组对
#class_mapping作用是找出出现一个新classlabel时的index
class_mapping

用映射字典将分类标签转换为整数

df['classlabel']=df['classlabel'].map(class_mapping)
df

创建反向映射,将转换后的分类标签匹配到原来的字符串

inv_class_mapping={v:k for k,v in class_mapping.items()}
df['classlabel']=df['classlabel'].map(inv_class_mapping)
df

fit_transform方法只是分别调用fit和transform的一种快捷的方式

我们也可以在scikit-learn中直接调用LabelEncoder类来实现转换

同时也可以用inverse_transform方法将分类的整数型标签转换为原来的字符串形式

from sklearn.preprocessing import LabelEncoder
class_le=LabelEncoder()
y=class_le.fit_transform(df['classlabel'].values)
y
class_le.inverse_transform(y)

3)对类别型的特征用one-hot编码
X=df[['color','size','price']].values
from sklearn.preprocessing import LabelEncoder
color_le=LabelEncoder()
X[:,0]=color_le.fit_transform(X[:,0])#对color特征列进行顺序出现编码
X

我们发现,执行上面的代码之后,Numpy阵列X的第一列现在有了新的颜色值,其编码格式如下。

  • blue = 0
  • green = 1
  • red = 2
#检验color特征列编码序号原理,对应df结构看
from sklearn.preprocessing import LabelEncoder
color_le=LabelEncoder()
color_le.fit(df['color'])
color_le.classes_

为名词特征列的每一个唯一值创建一个新的虚拟特征。于是我们把color特征转换为三个新的特征:blue,green,red。然后我们使用二进制值来表示样本的每一种特定颜色。比如说green样本可以编码为blue=0,green=1,red=0。我们可以调用scikit-learn.preprocessing模块中的OneHotEncoder类来实现这种转换。

#from sklearn.preprocessing import OneHotEncoder
#ohe = OneHotEncoder(categorical_features=[0])
#ohe.fit_transform(X).toarray()
#错误提示的意思是函数__init__()得到了一个不期望得到的参数,
#看样OneHotEncoder不希望我么提供参数’categorical_features’。
#这里是因为scikit-learn 在版本0.22.1之后取消了OneHotEncoder的参数categorical_features
from sklearn.compose import ColumnTransformer
ohe =ColumnTransformer([("color",OneHotEncoder(),[0])],remainder = 'passthrough')
X = ohe.fit_transform(X)
X

还有一个更方便的通过独热编码创建虚拟特征的方法是在pandas中调用get_dummies方法。把get_dummies方法应用到数据帧,只转换字符串,而保持所有其他列不变。

pd.get_dummies(df[['price','color','size']])#pandas内的独热方法get_dummies()

注:当使用独热编码对数据集进行编码时,必须小心其会带来的多重共线性,对于某些方法这可能会带来问题(例如那些需要进行矩阵求逆的方法)。高度相关的特征很难计算反转矩阵,因此可能会导致数值估计不稳定。为减少变量之间的关联性,可以直接从独热编码阵列中删除一个特征列。尽管删除一个特征列,但并没有失去任何一个重要的信息。删除之后特征信息仍然得到保存,因为观察到另外几种特征为零,就可知余下的观察结果为被删除的一列。

调用get_dummies函数时,可以通过传递True参数给drop_first删除第一列。

print(pd.get_dummies(df[['price','color','size']],drop_first=True))


划分数据集(训练集与测试集)

导入数据集
from sklearn import datasets
import pandas as pd
winedata = datasets.load_wine()
wineData = pd.DataFrame(winedata['data'],columns=winedata['feature_names'])
wineData.to_csv('winedata.csv')
df_wine=pd.read_csv('winedata.csv')
df_wine.columns = ['class label','alcohol','malic acid','ash','alcalinity of ash','magnesium','total phenols','flavanoids','nonflavanoid phenols','proanthocyanins','color intensity','hue','od280/od315 of diluted wines','proline']
#print('class labels',np.unique(df_wine['class label']))
df_wine.head() 

划分
from sklearn.model_selection import train_test_split  # 划分数据集
X,y=df_wine.iloc[:,1].values,df_wine.iloc[:,0].values#df_wine数据的第一列作为标签类别,其余列作为特征
X_train,X_test,y_train,y_test=train_test_split(X,y,test_size=0.3,random_state=0)#全部数据的30%作为测试集
X_train.shape,X_test.shape
对连续值特征做幅度缩放

特征缩放是数据预处理过程中至关重要的一步,但是却极易被人们忽略。
决策树和随机森林是机器学习算法中为数不多的不需要进行特征缩放的算法。

目前,将不同的特征缩放到相同的区间有两种常用的方法:归一化和标准化。这俩个词在不同的领域中使用较为宽松,其含义由具体语境所确定。
归一化
多数情况下,归一化指的是将特征的值放到区间[0,1],它是最小-最大缩放的一个特例。

标准化
当遇到需将数据限定在一个有界区间的情况时,我们常采用最小-最大缩放来尽心有效的规范化。

在scikit-learn中已经实现了最小-最大缩放,使用方法如下

from sklearn.preprocessing import MinMaxScaler
#区间[0,1]上的均匀分布缩放,按单个特征列看
mms = MinMaxScaler()
X_train_norm = mms.fit_transform(X_train)
X_test_norm = mms.transform(X_test)

scikit-learn也已经实现了标准化类:

from sklearn.preprocessing import StandardScaler
#N[0,1]正态分布缩放
stdsc = StandardScaler()
X_train_std = stdsc.fit_transform(X_train)
X_test_std = stdsc.transform(X_test)

注意:我们只是使用了StandardScaler对训练数据进行拟合,并使用相同的拟合参数来完成对测试集以及未知数据的转换。所以用的是stdsc.trainsform而不是stdsc.fit_transform

特征选择
1)L正则化的截断型效应选择
from sklearn.linear_model import LogisticRegression
lr = LogisticRegression(C = 0.1, penalty = 'l1',solver='liblinear')
#lr.fit(X_train_std,y_train)
#print('Training accuracy:',lr.score(X_train_std ,y_train))
#print('Test accuracy:',lr.score(X_test_std,y_test))

lr.fit(X_train_std.T,y_train.T.reshape(-1))
print('Training accuracy:',lr.score(X_train_std.T ,y_train.T.reshape(-1)))
print('Test accuracy:',lr.score(X_test_std.T,y_test.T.reshape(-1)))

import matplotlib.pyplot as plt
fig=plt.figure()
ax=plt.subplot(111)
colors=['blue','green','red','cyan','magenta','yellow','black','pink','lightgreen','lightblue','gray','indigo','orange']
weights,params=[],[]
for c in range(-4,6):
    lr=LogisticRegression(penalty='l1',C=10**c,solver='liblinear',random_state=0)
    lr.fit(X_train_std,y_train)
    weights.append(lr.coef_[1])
    params.append(10**c)
weights=np.array(weights)
for column,color in zip(range(weights.shape[1]),colors):
    plt.plot(params,weights[:,column],label=df_wine.columns[column+1],color=color)
    #column+1去掉第一列label列
    plt.axhline(0,color='black',linestyle='--',linewidth=1)
    plt.xlim([10**(-5),10**5])
    plt.ylabel('weight coefficient')
    plt.xlabel('C')
    plt.xscale('log')
    plt.legend(loc='upper left')
    ax.legend(loc='upper center',bbox_to_anchor=(1.38,1.03),ncol=1,fancybox=True)
    plt.show()

2)遍历子特征集选择法
from sklearn.base import clone
from itertools import combinations
import numpy as np
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split
class SBS():
    def __init__(self,estimator,k_features,scoring=accuracy_score,test_size=0.25,random_state=1):
        self.scoring=scoring
        self.estimator=clone(estimator)#构造一个具有相同参数的估计器
        self.k_features=k_features
        self.test_size=test_size
        self.random_state=random_state
    def fit(self,X,y):
        X_train,X_test,y_train,y_test=train_test_split(X,y,test_size=self.test_size,random_state=self.random_state)
        dim=X_train.shape[1]
        self.indices_=tuple(range(dim))
        self.subsets_=[self.indices_]
        score=self._calc_score(X_train,y_train,X_test,y_test,self.indices_)#全特征组合得分
        self.scores_=[score]
        
        while dim>self.k_features:#至少要考虑到K_features个特征
            scores=[]
            subsets=[]
            for p in combinations(self.indices_,r=dim-1):#combinations求组和,不取全部13个特征:每次只取12个特征,11个特征……
                score=self._calc_score(X_train,y_train,X_test,y_test,p)
                scores.append(acore)
                subsets.append(p)
            best=np.argmax(scores)#argmax求分数最高的特征组合所在的索引
            self.indices_=subsets[best]#根据索引,区分赎罪该特征组合
            selt.subsets_.append(self.indices_)#同个数特征的各个组合中,得分最高的组合构成的列表
            dim-=1
            self.scores_.append(scores[best])#同个数特征的各个组合中,最优特征组合的得分构成的列表
        self.k_score_=self.scores_[-1]#每k个特征组合的最好得分,直接取scores_列表中最好加入的元素
        return self
    
    def transform(self,X):
        return X[:,self.indices_]
    
    def _calc_score(self,X_train,y_train,X_test,y_test,indices):
        self.estimator.fit(X_train[:,indices],y_train)
        y_pred=self.estimator.predict(X_test[:,indices])
        score=self.scoring(y_test,y_pred)#用sccuracy_score方法计算
        return score
    #indices_是每个维度最优特征组合元组,subsets_是包含各个维度最优特征组合元组的列表,scores_是包含各个维度最优特征组合得分的列表
    
import matplotlib.pyplot as plt
from sklearn.neighbors import KNeighborsClassifier
knn=KNeighborsClassifier(n_neighbors=2)
sbs=SBS(knn,k_features=1)
#sbs.fit(X_train_std,y_train)
sbs.fit(X_train_std.T,y_train.T.reshape(-1))

k_feat=[len(k) for k in sbs.subsets_]
plt.plot(k_feat,sbs.scores_,marker='o')
plt.ylim([0.7,1.1])
plt.ylabel('Accurary')
plt.xlabel('Number of features')
plt.grid()
plt.tight_layout()
plt.show()

k5=list(sbs.subsets_[8])
print(df_wine.columns[1:][k5])#去除第一个标签列计数

knn.fit(X_train_std.T,y_train.T.reshape(-1))#全部特征建模得分
print('Training accuracy:',knn.score(X_train_std.T,y_train.T.reshape(-1)))
print('Test sccuracy:',knn.score(X_test_std.T,y_test.T.reshape(-1)))

knn.fit(X_train_std[:,k5],y_train)#只选k5组合包含的特征建模得分
print('Training accuracy:',knn.score(X_train_std[:,k5],y_train))
print('Test sccuracy:',knn.score(X_test_std[:,k5],y_test))

3)通过随机森林对特征重要性排序
from sklearn.ensemble import RandomForestClassifier
feat_labels=df_wine.columns[1:]#特征列名
forest=RandomForestClassifier(n_estimators=2000,random_state=0,n_jobs=-1)#2000棵树,并行工作数是运行服务器决定
forest.fit(X_train,y_train)
importances=forest.feature_importances_ #feature_importances_特征列重要性占比
indices=np.argsort(importances)[::-1] #对参数从小到大排序的索引序号取逆,即最重要特征索引-->最不重要特征索引
for f in range(X_train.shape[1]):
    print("%2d%-*s%f"%(f+1,30,feat_labels[indices[f]],importances[indices[f]]))
    #-*s表示左对齐字段feat_labels[indices[f]]宽度为30
plt.title('Feature Importances')
plt.bar(range(X_train.shape[1]),importances[indices],color='lighblue',align='center')
plt.xticks(range(X_train.shape[1]),feat_labels[indices],rotation=90)
plt.xlim([-1,X_train.shape[1]])
plt.tight_layout()
plt.show()

from sklearn.feature_selection import SelectFromModel
sfm=SelectFromModel(forest,threshold=0.15,prefit=True)
#forest参数是建模完带特征重要信息的估计器,threshold是特征筛选阈值
X_selected=sfm.transform(X_train)#transform对样本X_train进行了选定特征列过滤
X_selected.shape

for f in range(X_selected.shape[1]):
    print("%2d%-*s%f"%(f+1,30,feat_labels[indices[f]],importances[indices[f]]))
   

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值