Day 17 : 模型前的资料处理 (1)

虽然好的模型和参数可以提高成效,但通常最关键还是资料本身。基本上资料的品质决定了八成以上模型的成效,因此大家有必要对自己的资料有所认识和了解。

而在做机器学习的问题,花费最多的通常也是资料处理;我们如果做好资料处理甚至可以大幅提升模型成效。

今天会引导大家认识常用的资料处理的方式,包含常用的 pandas 和 sklearn 套件。我会使用铁达尼号的资料来示范。

1. 资料探索

Pandas 探索

train.pivot_table(columns=['Embarked'])

pandas_profiling

回顾一下在 pandas篇 有提到可以用 pandas_profiling 可以更方便探索资料

import numpy as np
import pandas as pd
from pandas_profiling import ProfileReport
import seaborn as sns
import matplotlib.pyplot as plt

train = pd.read_csv('train.csv')
profile = ProfileReport(train, title="Pandas Profiling Report")
profile

# Saving the report
profile.to_file("titantic_profiling_report.html")

相关系数

相关系数 r 介於 -1~1之间

  • 当 r >0 表示正相关;当 r < 0 表示负相关
  • 当 r = 0 表示两变数之前为无线性相关
  • 当 |r| <= 0.4 表示两变数之间为低度相关
  • 当 0.4 <= |r| <0.7 表示两变数之间为显着性相关
  • 当 |r| > 0.7 表示两变数之间为高度相关
  • 当 |r| = 1 表示两变数之间为完全线性相关

由於 Sex 不是数值,先进行转换

train['Sex_encoder'] = train.Sex.apply(lambda x: 1 if x=='male' else 0)
train.corr()

我们大概先从相关系数得知以下事情:

  • Pclass 和 Fare 是显着性相关
  • Pclass 和 Survived 是有低度相关
  • Pclass 和 Age 是低度相关
  • Parch 和 SibSp 是有显着性相关
  • Sex 和 Survived 有相关

发现 Survived 跟 Pclass 、 Sex 有关系,这与我们要预测的方向会很有关系

绘图

绘制图型可以快速掌握资料

sns.countplot(train['Sex'], hue=train['Survived'])

删除重复值或异常

这招非常重要,有时候资料很脏,还是要确定一下是否有无重复的资料或异常。

train[train.duplicated()]

2.处理遗漏值

# isnull() 若资料为空值则为 True,反之则为 False
train.isnull().head()
# isnull() + sum() 搭配操作
train.Age.isnull().sum()
# count 仅会计算非空值
train.count()

# 综合运用 依照空值数量排序
total = train.isnull().sum().sort_values(ascending=False)
print(total)

# 或是调整成百分比型式
percent =(train.isnull().sum()/train.isnull().count()).sort_values(ascending=False)
missing_data = pd.concat([total, percent], axis=1, keys=['Total', 'Percent'])
missing_data

遗漏值的处理方法

通常有以下几招

  • 用其他的均值来填补遗漏值,例如平均数、中位数、众数,我们可以依照资料特性填补
  • 使用特殊值来填补离漏值,如-1 通常不要重复就好,把遗漏值归类成一个类别
  • 忽略有缺失值的样本,直接把该栏位 drop 。若遗漏值太多且该栏位也无相关性应该可以 drop
  • 使用其他栏位的均值添补遗漏值,例如可以利用其他栏位去简单计算该栏位的值
  • 使用另外的机器学习演算法预测缺失值,例如可以利用其他栏位去预测该栏位的值
# 使用 dropna
## 预设是只有有空值就删掉那笔
train.dropna()
# 使用 dropna
## 要全部为空才清楚那一笔资料
train.dropna(how='all')
# 使用 dropna
## 可以指定作用在哪一行
train.dropna(subset=['Fare'])

填补遗漏值方法

# 使用 fillna
## 空值都填上 -1
train.fillna(-1)
## 填上平均数
print(train['Age'].mean())
train['Age'].fillna(train['Age'].mean())
## 使用中位数填补
train['Fare'] = train['Fare'].fillna(train['Fare'].median())
## 使用出现次数最多的值填补
most = train['Embarked'].mode()[0]
train['Embarked'] = train['Embarked'].fillna(most)

# 用上下资料进行填补
## 前一个数据进行填充
train.Cabin.fillna(method='pad')
## 後一个数据进行填充
train.Cabin.fillna(method='bfill')
# 用插值法
train.Age.interpolate()

比较一下插值法前後的 displot

sns.distplot(train.Age, kde=True)

sns.distplot(train.Age.interpolate(method ='linear'), kde=True)

3.离群值处理

我们需要建立一个门槛值去界定离群值,因此我们将资料进行标准化

from sklearn.preprocessing import StandardScaler
#standardizing data
scaled = StandardScaler().fit_transform(train['Fare'][:,np.newaxis]);
low_range = scaled[scaled[:,0].argsort()][:10]
high_range= scaled[scaled[:,0].argsort()][-10:]
print('outer range (low) of the distribution:')
print(low_range)
print('\nouter range (high) of the distribution:')
print(high_range)

from scipy import stats
sns.distplot(x=train["Fare"])
fig = plt.figure()
res = stats.probplot(train['Fare'], plot=plt)

从上图也很明显地看到有三个点异常高,可以考虑移除

4.特徵工程

透过上述的资料处理,相信大家对资料有一点的认识,接着我们可以进行找特徵

特徵缩放

有些特徵是差距实在太大,会让某些模型无法容易学习,因此我们要调整资料的 range,通常是进行标准化。

# 票价的资料有极端值,我们希望可以缩小差距
sns.distplot(x=train["Fare"])

取 log 的方法
sns.distplot(x=np.log(train["Fare"] + 1))

平均数变异数标准化
from sklearn.preprocessing import StandardScaler

scaler = StandardScaler().fit(train[['Age']])
X_scaled = scaler.transform(train[['Age']])
最大值最小值标准化
from sklearn.preprocessing import MinMaxScaler

scaler = MinMaxScaler(feature_range=(0, 1)).fit(train[["Fare"]])
X_scaled = scaler.transform(train[["Fare"]])
绝对值最大标准化

资料会被缩放到 [-1, 1]之间

from sklearn.preprocessing import MaxAbsScaler
X = train[["Fare"]]
scaler = MaxAbsScaler().fit(X)
X_scaled = scaler.transform(X)
RobustScaler

中位数和四分位数标准化,可以有效缩放离群值

from sklearn.preprocessing import RobustScaler
X = train[["Fare"]]
scaler = RobustScaler().fit(X)
X_scaled = scaler.transform(X)

特徵处理

基本上演算法只是接近这份资料可以达到的预测水平上界,但透过特徵处理,或许可以大幅将预测上界往上移动。因此了解资料後新增特徵,或许预测会更准确!

# 可以新增一个家庭大小,由於有父母数量和兄弟姊妹数量的栏位,合成一个新的栏位
train['family_size'] = train['Parch'] + train['SibSp']

<<:  DAY14 呼叫功能列表样板

>>:  【在 iOS 开发路上的大小事-Day17】透过 Firebase 来管理使用者 (Sign in with Google 篇) Part1

Day18. Blue Prism制造齿轮 -BP Object页 将成绩写入Excel中

以前年轻时,常说我只是一颗小小的螺丝钉没什麽用处, 接着就会听到家中长一辈的人正向鼓励着说:「每一个...

[Day23] NLP会用到的模型(六)-transformer架构

一. 介绍 transformer就是像前述介绍的,他就是一个seq2seq model,将一个序列...

前端工程日记 30日 名片设计

如图 pancode: div 设计成 各种形状 三角形。五角形 六角形 的方法 制作参考引用 ht...

6. 来玩终端机

最基本的 问答时间 到底为甚麽要用终端机?可以用最少的容量来做事(图形介面还要读取图片) 是不是打指...

Day 03: 有意义的命名、好的注解、垂直 & 水平编排

「我们是认真严肃地看待命名这件事,请您牢记这一点」 取自: Clean Code (p.20) 前...