Kaggle的比赛入门,通过机器学习模型对泰坦尼克号上幸存情况进行预测,这里主要针对预测前的特征工程处理,对缺失数据进行分析和补全。
加载数据
加载csv文件数据
1 | def load_data(path): |
测试代码
1 | train_header, train_data = load_data(TRAIN_PATH) |
Output:
1 | ['PassengerId', 'Survived', 'Pclass', 'Name', 'Sex', 'Age', 'SibSp', 'Parch', 'Ticket', 'Fare', 'Cabin', 'Embarked'] |
检查缺失数据
遍历每一行,记下空字符串元素所在的位置
1 | def check_empty(header, data): |
测试代码
1 | train_header, train_data = load_data(TRAIN_PATH) |
Output:
1 | Age: 177 |
可以看到训练数据中Age
特征有177条缺失数据,另外两个以此类推。
上面是训练集中缺失数据的特征,而我们要得到还有测试集的缺失信息,所以写一个merge函数,将训练集和测试集合并起来(由于现在是缺失值分析阶段,所以不区分训练集和测试集,接下来会一直沿用合并后的数据),然后再检查缺失信息。
1 | def merge_data(train_data, test_data): |
Output:
1 | Fare: 1 |
于是能够得到所有缺失的特征,分别是Fare
、Age
、Cabin
、Embarked
,接下来开始对缺失项一一进行分析、补全。
缺失数据分析
Fare
表明乘客的票价,有1个缺失值,我们首先看一下该数据的范围,均值,均方差这些信息
1 | fare = merged[:, test_header.index('Fare')] |
Output:
1 | Range: 0.00 - 512.33 |
通过这三项数据(以下简称RMM
)我们能对票价信息有个大致的了解,范围在0 - 512.33波动,均值是33.3而均方差只有51.74,这表明大多数票价都是偏低的(也能从一定程度上分析出乘客的经济状况,这里就不继续延伸了)。
RMM
信息获取很方便,但是不便于直观、确切的观察数据的分布情况,这时考虑通过matplot
画出票价的密度分布图。
1 | import matplotlib.pyplot as plt |
分布图如下
从图中可以很直观的看出绝大部分数据都是部分在50以下的,鉴于这种情况,我们很直观的选择是把均值作为补全值。
1 | print np.mean(fare_with_data) |
Output:
1 | 33.2954792813 |
这时33.2954792813便做为Fare
补全值了。
为了确保万一,我们要查出该条数据索引
1 | empty = check_empty(test_header, merged) |
Output:
1 | ['1044'] |
接下来我们根据PassengerId
找到该条数据
1 | 1044,3,"Storey, Mr. Thomas",male,60.5,0,0,3701,,,S |
对比着特征名来分析数据
1 | PassengerId,Pclass,Name,Sex,Age,SibSp,Parch,Ticket,Fare,Cabin,Embarked |
可以逐一分析,我们发现Pclass
对应N等票,可能会影响到票价Fare
特征,因此我们要取出所有跟该名乘客相同Pclass
(从数据可以看出是3)的票价分布。
1 | fare = merged[:, [test_header.index('Fare'), test_header.index('Pclass')]] |
分布图如下
对比和上一张图的区别,我们能更加确切的了解到,三等票的票价没有高于70的,因此如果按照上面的结论直接把所有数据的票价均值作为补全值,在一定程度上会使得补全值的误差变大,取而代之的是用Pclass
为3的乘客的票价均值作为补全值(这里还是有一定的优化空间,我们可以分析Pclass
为3的乘客中的年龄、家属情况、船舱等对票价的影响,这里就不继续展开了)。
有了上面的分析,我们就可以重新计算补全值
1 | print np.mean(fare_with_pclass_3) |
Output:
1 | 13.3028887006 |
和上面输出的33.3还是有一定差距的
经过上面的一系列的分析,可以写出Fare
特征的补全逻辑
1 | def compute_fare_data(all_data, pclass, fare_index, pclass_index): |
此时我们的主函数应该是这样子
1 | train_header, train_data = load_data(TRAIN_PATH) |
Age
表明乘客年龄,有263个缺失值,同上,我们先看一下该特征的RMM
信息
1 | age = merged[:, test_header.index('Age')] |
Output:
1 | Range: 0.17 - 80.00 |
均值29.9,均方差14.4,可见整体年龄层都分布在青壮年阶段,接下来直接看看密度分布图
从该图中我们只能观察到老人(50岁以上)和小孩(16岁以下)占比较小,年龄大多集中在17-40左右,我们必须试图在数据中寻找更好的估值标准。
我们尝试寻找Age
与Pclass
的关系,先来画出分布图
1 | age_pclass = merged[:, [test_header.index('Age'), test_header.index('Pclass')]] |
分布图如下
从上图上中可以知道很难直接根据Pclass
估值出Age
的值。