特征增强:清洗数据
识别数据中的缺失值
本章只处理定量特征,因为目前没有足够工具处理缺失的定性特征,特征构建那一章会解决这个问题。
当获得一份数据集时,首先进行探索性分析,之后本书就对皮马印第安人糖尿病预测数据集进行EDA,画了一些直方图分析属性与目标值的关系,同时绘制相关矩阵,查看相关性系数。
开始查看缺失值
- 使用下面代码,查看是否有空的值
data.isnull().sum()
- 查看shape,确定行数与列数,还有确定一下空准确率
data.shape
data['asd'].value_counts(normalize=True)
- 描述性统计
data.describe()
可以发现有些不合理的值,例如BMI最小值是0,这是违背事实的,可能是数据中缺失或不存在的点。
有些列如怀孕次数为0,是很正常的,可以补充为0.
- 必须尽可能了解数据集,以便找到更好的符号填充缺失数据
处理缺失值的方法
- 删除缺失值的行
- 填充缺失值
- 先把0换成None,可以让fillna和dropna正常工作
data['asd']=data['asd'].map(lambda x:x if x!=0 else None)
对全部列操作
for col in columns:
data[col].replace([0],[None],inplace=True)
通过这个方法,可以更准确地分析缺失数据,describe方法是不会对有缺失值的列进行统计
删除有害的行
data_dropped=data.dropna()
# 查看删除了多少行
num_rows_lost = round(100*(data.shape[0]-data_dropped.shape[0])/float(data.shape[0]))
print('retained {}% of rows'.format(num_rows_lost))
要留意删除了多少的行,例子中删除了整整一半的数据,这样说明我们没有尽可能的利用多点的数据,所以可以进行抛弃缺失值前后的比较。
对value_counts()的比较
对均值的比较,data.mean() , data_dropped.mean()
# 均值变化百分比
(pima_dropped.mean() - pima.mean()) / pima.mean()
# 均值变化百分比条形图
ax = ((pima_dropped.mean() - pima.mean()) / pima.mean()).plot(kind='bar', title='%
change in average column values')
ax.set_ylabel('% change')
可以看到有部门的列的均值在删除缺失值后变化比较大,即影响了数据的形状,所以应该保留尽可能多的数据
填充缺失值
采用fillna(填补值,Inplace=true)
对每个列都做有点麻烦,sklearn有个预处理类Imputer模块,我们称其为“填充器”
from sklearn.preprocessing import Imputer
imputer = Imputer(strategy='mean') 实例化对象
data_imputed = imputer.fit_transform(data) 此输出为numpy数组
'我们需要转换为dataframe'
data_imputed = pd.DataFrame(data_imputed,columns=data_column_names)
流水线上的填充缺失值(pipeline和Imputer)
from sklearn.pipeline import Pipeline
knn_params = {'classify_n_neighbors':[1,2,3,4,5,6,7]}
knn = KNeighborsClassifier()
mean_impute = Pipeline([('imputer',Imputer(strategy='mean')),('classify',knn)])
X = data.drop('onsert_diabetes',axis=1) #这是目标值
y = data['onsert_diabetes']
grid = GridSearchCV(mean_impute,knn_params)
grid.fit(X,y)
print(grid.best_score_,grid.best_params_)
案例中,发现删除缺失值的行数的准确率比用0、均值、中位数填充还要高,但是我们希望利用所有行的数据实现类似的性能,所以引入了标准化和归一化
标准化和归一化
采用标准直方图,查看所有列的分布情况,注意到每列的均值、最小值、最大值、标准差的差别很大,我们也可以通过describe函数查看,数据尺度的差距会影响到一些机器学习模型的,例如身高在150~190,但年龄在20 ~ 80之间,算法无法达到最有状态,我们可以通过直方图的sharex和sharey参数,在同一比例下查看每个图表。
data_imputed_mean.hist(figsize=(15,15),sharex=True)
- 归一化是为了将行和列对齐并转化为一致的规则,通常是将定量列转化为同一个静态范围的值,如(0,1),或者按照一些数学规则,如所有列的均值和标准差必须相同。
z-score标准化
利用z分数思想,使均值为0,标准差为1,让KNN这类模型达到最优状态,而不会倾向于较大比例的特征。
z = ( x − μ ) / σ z=(x-\mu)/\sigma z=(x−μ)/σ
scaler = StandardScaler()
z_score = scaler.fit_transform(data[['asd']])
#这里采用双括号,因为转换需要一个dataframe
min-max标准化
m
=
(
x
−
x
m
i
n
)
/
(
x
m
a
x
−
x
m
i
n
)
m=(x-x_{min}) / (x_{max}-x_{min})
m=(x−xmin)/(xmax−xmin)
此公式可以把所有值都会位于0 ~ 1
from sklearn.preprocessing import MinMaxScaler
# 实例化
min_max = MinMaxScaler()
# 使用min-max 标准化
pima_min_maxed = pd.DataFrame(min_max.fit_transform(pima_imputed),
columns=pima_column_names)
这种转换的副作用是标准差会非常小,不利于个别模型,因为异常值权重降低了
行归一化
保证每行有单位范数(unit norm),即每行的向量长度相同,我们认为每行数据都在一个n维空间中,每行都有一个向量范数(长度),计算方法是:
∣
∣
x
∣
∣
=
x
1
2
+
x
1
2
+
.
.
.
+
x
n
2
||x|| = \sqrt{{x_1}^2+{x_1}^2+...+{x_n}^2}
∣∣x∣∣=x12+x12+...+xn2
这是L2范数,暂时不提及其他类型范数,我们关心要每行都有相同范数
np.sqrt((pima_imputed**2).sum(axis=1)).mean()
# 归一化之前的矩阵的平均范数
223.36222025823744
#归一化之后的范数
from sklearn.preprocessing import Normalizer # 行归一化
normalize = Normalizer()
pima_normalized = pd.DataFrame(normalize.fit_transform(pima_imputed),
columns=pima_column_names)
np.sqrt((pima_normalized**2).sum(axis=1)).mean()
# 行归一化后矩阵的平均范数
1.0
受尺度影响的一些算法
- KNN,依赖于欧几里得距离
- K-mean,依赖欧几里得距离
- 逻辑回归、svm、神经网络,若使用梯度下降来学习权重
- PCA,特征向量将偏向于较大的列