虽然好的模型和参数可以提高成效,但通常最关键还是资料本身。基本上资料的品质决定了八成以上模型的成效,因此大家有必要对自己的资料有所认识和了解。
而在做机器学习的问题,花费最多的通常也是资料处理;我们如果做好资料处理甚至可以大幅提升模型成效。
今天会引导大家认识常用的资料处理的方式,包含常用的 pandas 和 sklearn 套件。我会使用铁达尼号的资料来示范。
train.pivot_table(columns=['Embarked'])
回顾一下在 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之间
由於 Sex 不是数值,先进行转换
train['Sex_encoder'] = train.Sex.apply(lambda x: 1 if x=='male' else 0)
train.corr()
我们大概先从相关系数得知以下事情:
发现 Survived 跟 Pclass 、 Sex 有关系,这与我们要预测的方向会很有关系
绘制图型可以快速掌握资料
sns.countplot(train['Sex'], hue=train['Survived'])
这招非常重要,有时候资料很脏,还是要确定一下是否有无重复的资料或异常。
train[train.duplicated()]
# 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
通常有以下几招
# 使用 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)
我们需要建立一个门槛值去界定离群值,因此我们将资料进行标准化
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)
从上图也很明显地看到有三个点异常高,可以考虑移除
透过上述的资料处理,相信大家对资料有一点的认识,接着我们可以进行找特徵
有些特徵是差距实在太大,会让某些模型无法容易学习,因此我们要调整资料的 range,通常是进行标准化。
# 票价的资料有极端值,我们希望可以缩小差距
sns.distplot(x=train["Fare"])
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)
中位数和四分位数标准化,可以有效缩放离群值
from sklearn.preprocessing import RobustScaler
X = train[["Fare"]]
scaler = RobustScaler().fit(X)
X_scaled = scaler.transform(X)
基本上演算法只是接近这份资料可以达到的预测水平上界,但透过特徵处理,或许可以大幅将预测上界往上移动。因此了解资料後新增特徵,或许预测会更准确!
# 可以新增一个家庭大小,由於有父母数量和兄弟姊妹数量的栏位,合成一个新的栏位
train['family_size'] = train['Parch'] + train['SibSp']
>>: 【在 iOS 开发路上的大小事-Day17】透过 Firebase 来管理使用者 (Sign in with Google 篇) Part1
以前年轻时,常说我只是一颗小小的螺丝钉没什麽用处, 接着就会听到家中长一辈的人正向鼓励着说:「每一个...
一. 介绍 transformer就是像前述介绍的,他就是一个seq2seq model,将一个序列...
如图 pancode: div 设计成 各种形状 三角形。五角形 六角形 的方法 制作参考引用 ht...
最基本的 问答时间 到底为甚麽要用终端机?可以用最少的容量来做事(图形介面还要读取图片) 是不是打指...
「我们是认真严肃地看待命名这件事,请您牢记这一点」 取自: Clean Code (p.20) 前...