Day 34:Pandas 实战 Kaggle titanic 幸存预测之 7 步数据清洗
发布日期:2022年3月12日 18:02 阅读: 214 访问: 215
数据清洗(data cleaning)是机器学习和深度学习进入算法步前的一项重要任务,总结为下面几个步骤。步骤 1:读入 CSV 数据;步骤 2:预览数据;步骤 3:统计每一列的空值;步骤 4:填充空值;步骤 5:特征工程,子步骤包括删除一些特征列,创建新的特征列,创建数据分箱;
数据清洗(data cleaning)是机器学习和深度学习进入算法步前的一项重要任务,总结为下面几个步骤。
- 步骤 1:读入 CSV 数据;
- 步骤 2:预览数据;
- 步骤 3:统计每一列的空值;
- 步骤 4:填充空值;
- 步骤 5:特征工程,子步骤包括删除一些特征列,创建新的特征列,创建数据分箱;
- 步骤 6:对分类列编码,常用的包括,调用 Sklearn 中 LabelEncode 编码、Pandas 中哑编码;
- 步骤 7:再验证核实。
今天使用泰坦尼克数据集,完整介绍以上步骤的具体操作过程。
1. 读入数据
使用 Pandas,读入 CSV 训练数据,然后了解每个字段的含义,数据有多少行和多少列等。
import pandas as pd
data_raw = pd.read_csv('train.csv')
data_raw
结果如下,一共训练集有 891 行数据,12 列
- PassengerId: 乘客的 Id
- Survived:乘客生还情况,取值 1、2
- Pclass:乘客等级,取值 1、2、3
- SibSp:乘客的兄弟姐妹和配偶在船上的人数
- Parch:乘客的父母和孩子在船上的人数
- Fare:乘船的费用
- Cabin:舱的编号
- Embarked:分类变量,取值 S、C、Q
其他几个特征比较好辨别,不再解释。
2. 数据预览
Pandas 提供 2 个好用的方法:info、describe。
- info 统计出数据的每一列类型,是否为 null 和个数;
- describe 统计出数据每一列的统计学属性信息,平均值、方差、中位数、分位数等。
data_raw.info()
data_raw.describe(include='all')
结果:
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 12 columns):
PassengerId 891 non-null int64
Survived 891 non-null int64
Pclass 891 non-null int64
Name 891 non-null object
Sex 891 non-null object
Age 714 non-null float64
SibSp 891 non-null int64
Parch 891 non-null int64
Ticket 891 non-null object
Fare 891 non-null float64
Cabin 204 non-null object
Embarked 889 non-null object
dtypes: float64(2), int64(5), object(5)
memory usage: 83.7+ KB
3. 检查 null 值
实际使用的数据,null 值在所难免。如何快速找出 DataFrame 每一列的 null 值个数?
使用 Pandas 能非常方便实现,只需下面一行代码:
data.isnull().sum()
- data.isnull():逐行逐元素查找元素值是否为 null。
- sum():默认在 axis 为 0 上完成一次 reduce 求和。
结果:
PassengerId 0
Survived 0
Pclass 0
Name 0
Sex 0
Age 177
SibSp 0
Parch 0
Ticket 0
Fare 0
Cabin 687
Embarked 2
dtype: int64
查看每列的空值占比:
import matplotlib.pyplot as plt
import seaborn as sns
x_raw = data_raw.columns
data1_null = data_raw.isnull().sum()
null_rate = data1_null.values / len(data1)
plt.bar(x_raw,null_rate)
plt.xticks(rotation=90)
plt.show()
Cabin 列空值比重最大,接近 80%,如此大的空值占比,可以直接删除。
4. 补全空值
Age 列和 Embarked 列也存在空值,空值一般用此列的平均值、中位数、众数等填充。
观察 Age 列的取值分布直方图和箱型图:
plt.figure(figsize=[10,8])
notnull_age_index = data1['Age'].notnull()
plt.subplot(221)
plt.hist(x = data1[notnull_age_index]['Age'], color = ['orange'])
plt.subplot(222)
plt.boxplot(x = data1[notnull_age_index]['Age'], showmeans = True, meanline = True)
plt.show()
集中在 20~40 岁,使用中位数填充空值:
data1['Age'].fillna(data1['Age'].median(), inplace = True)
Embarked 属于分类型变量,使用众数填充:
data1['Embarked'].fillna(data1['Embarked'].mode()[0], inplace = True)
填充完成后,检查这两列的空值是否全部填充成功。
data1.isnull().sum()
PassengerId 0
Survived 0
Pclass 0
Name 0
Sex 0
Age 0
SibSp 0
Parch 0
Ticket 0
Fare 0
Cabin 687
Embarked 0
dtype: int64
5. 特征工程
完成数据的基本填充后,下面开始使用 Pandas 做特征工程。
5.1 删除特征列
因为 Cabin 缺失率较大,所以直接删除此列。
使用 Pandas 删除列 Cabin,axis 参数设置为 1,表示轴为列方向,inplace 为 True 表示就地删除。
data1.drop('Cabin', axis=1, inplace = True)
另外两列,PassengerId、Ticket 都是 ID 类型的,对预测乘客能否逃离没有关系,也直接删除。
drop_column = ['PassengerId','Ticket']
data1.drop(drop_column, axis=1, inplace = True)
5.2 增加 3 个特征列
增加一列 FamilySize,计算公式如下:
data1['FamilySize'] = data1 ['SibSp'] + data1['Parch'] + 1
data1.head(3)
再创建一列 IsAlone,如果 FamilySize 为 0,则表示只有一个人,IsAlone 为 True。
应用前面介绍的 where 函数,非常简洁地实现 IsAlone 列的赋值。
data1['IsAlone'] = np.where(data1['FamilySize'] > 1,0,1)
再创建一列 Title,它是从 Name 列中提取出头衔或称谓。
Name 列的前三行,如下:
0 Braund, Mr. Owen Harris
1 Cumings, Mrs. John Bradley (Florence Briggs Th...
2 Heikkinen, Miss. Laina
Name: Name, dtype: object
Pandas 中使用 str 属性,直接拿到整个此列的字符串值,然后使用前面介绍的字符串分隔方法 split:
data1['Title'] = data1['Name'].str.split(", ", expand=True)[1].str.split(".", expand=True)[0]
data1
数据前三行使用上面代码,提取后结果如下:
0 Mr
1 Mrs
2 Miss
Name: 0, dtype: object
5.3 分箱
Pandas 提供两种数据分箱方法:qcut、cut。
qcut 方法是基于分位数的分箱技术,cut 基于区间长度切分为若干。使用方法如下:
a = [3,1,5, 7,6, 5, 4, 6, 3]
pd.qcut(a,3)
结果如下,共划分为 3 个分类:
[(0.999, 3.667], (0.999, 3.667], (3.667, 5.333], (5.333, 7.0], (5.333, 7.0], (3.667, 5.333], (3.667, 5.333], (5.333, 7.0], (0.999, 3.667]]
Categories (3, interval[float64]): [(0.999, 3.667] < (3.667, 5.333] < (5.333, 7.0]]
a 元素这 3 个分类中的个数相等:
dfa = pd.DataFrame(a)
len1 = dfa[(0.999 < dfa[0]) & (dfa[0] <= 3.667)].shape
len2 = dfa[(3.667 < dfa[0]) & (dfa[0] <= 5.333)].shape
len3 = dfa[(5.333 < dfa[0]) & (dfa[0] <= 7.0)].shape
len1,len2,len3
结果如下,每个区间内都有 3 个元素:
((3, 1), (3, 1), (3, 1))
cut
方法:
a = [3,1,5, 7,6, 5, 4, 6, 3]
pd.cut(a,3)
得到结果,与 qcut 划分出的 3 个区间不同,cut 根据 a 列表中最大与最小值间隔,均分,第一个左区间做一定偏移。
[(0.994, 3.0], (0.994, 3.0], (3.0, 5.0], (5.0, 7.0], (5.0, 7.0], (3.0, 5.0], (3.0, 5.0], (5.0, 7.0], (0.994, 3.0]]
Categories (3, interval[float64]): [(0.994, 3.0] < (3.0, 5.0] < (5.0, 7.0]]
除此之外,1992 年 Kerber 在论文中提出 ChiMerge 算法,自底向上的先分割再合并的分箱思想,具体算法步骤:
- 设置 step 初始值
- while 相邻区间的 merge 操作:
- 计算相邻区间的卡方值
- 合并卡方值最小的相邻区间
- 判断:是否所有相邻区间的卡方值都大于阈值,若是 break,否则继续 merge
论文中 m 取值为 2,即计算 2 个相邻区间的卡方值,计算方法如下:
- k:类别个数
- Ri:第 i 个分箱内样本总数
- Cj:第 j 类别的样本总数
分别对 Fare 和 Age 列使用 qcut、cut 完成分箱,分箱数分别为 4 份、6 份。
data1['FareCut'] = pd.qcut(data1['Fare'], 4)
data1['AgeCut'] = pd.cut(data1['Age'].astype(int), 6)
data1.head(3)
结果:
6. 编码
本节介绍 2 种常用的分类型变量编码方法,一种是分类变量直接编码 LabelEncoder,另一种对分类变量创建哑变量(dummy variables)。
6.1 LabelEncoder 方法
使用 Sklearn 的 LabelEncoder 方法,对分类型变量完成编码。
from sklearn.preprocessing import LabelEncoder
泰坦尼克预测数据集中涉及的分类型变量有:Sex、Embarked、Title,还有我们新创建的 2 个分箱列:AgeCut、FareCut。
label = LabelEncoder()
data1['Sex_Code'] = label.fit_transform(data1['Sex'])
data1['Embarked_Code'] = label.fit_transform(data1['Embarked'])
data1['Title_Code'] = label.fit_transform(data1['Title'])
data1['AgeBin_Code'] = label.fit_transform(data1['AgeCut'])
data1['FareBin_Code'] = label.fit_transform(data1['FareCut'])
data1.head(3)
使用 LabelEncoder 完成编码后,数据的前三行打印显示:
6.2 get_dummies 方法
Pandas 的 get_dummies 方法,也能实现对分类型变量实现哑编码,将长 DataFrame 变为宽 DataFrame。
数据集中 Sex 分类型列取值有 2 种:female、male。
DataFrame:
pd.get_dummies(data1['Sex'])
使用 get_dummies,返回 2 列,分别为 female、male 列,结果如下:
female male
0 0 1
1 1 0
2 1 0
3 1 0
4 0 1
... ... ...
886 0 1
887 1 0
888 1 0
889 0 1
890 0 1
891 rows × 2 columns
而 LabelEncoder 编码后,仅仅是把 Female 编码为 0,male 编码为 1。
label.fit_transform(data1['Sex'])
0 1
1 0
2 0
3 0
4 1
..
886 1
887 0
888 0
889 1
890 1
Name: Sex_Code, Length: 891, dtype: int64
对以下变量实现哑编码:
data1_dummy = pd.get_dummies(data1[['Sex', 'Embarked', 'Title','AgeCut','FareCut']])
data1_dummy
结果:
7. 再次检查
data1.info()
print('-'*10)
data1_dummy.info()
8. 小结
今天与大家一起实践泰坦尼克预测数据集,数据清洗任务。主要使用 Pandas,任务分为 7 个步骤:
- 读入数据
- 数据预览,info、describe 方法
- isnull() 检查空值
- fillna() 填充空值
- 特征工程,删除和增加特征,数据分箱:qcut、cut、chimerge 算法
- 2 种常见的分类型变量编码方法:LabelEncoder、get_dummies 方法
Day34 数据集下载链接: