有几个优秀的notebook来研究数据科学竞赛参赛作品。然而,许多人会跳过一些关于如何开发解决方案的解释,因为这些notebook是由专家为专家开发的。本笔记本的目标是遵循分步工作流程,解释我们在解决方案开发过程中做出的每个决策的每个步骤和基本原理。
工作流步骤- 1.问题的定义
- 2.获得训练和测试数据
- 3.整理、准备和清洗数据
- 4.分析、识别模式并探索数据
- 5.建模、预测和解决问题。
- 6.可视化、报告和呈现问题解决步骤和最终解决方案
- 7.提供或提交结果。
工作流指示每个阶段如何跟随另一个阶段的一般顺序。但是,也有例外的用例。
- 我们可能会将多个工作流程阶段结合起来。我们可以通过可视化数据进行分析。
- 在指定的阶段之前执行。我们可能会在整理数据之前和之后分析数据。
- 在我们的工作流程中多次执行一个阶段。可视化阶段可多次使用。
像Kaggle这样的竞争网站定义要解决的问题或要问的问题,同时提供用于训练数据科学模型的数据集,并根据测试数据集测试模型结果。泰坦尼克号生存竞赛的问题或问题定义在Kaggle中进行了描述。
从列出在泰坦尼克号灾难中幸存下来或没有幸存下来的乘客的训练样本中,我们的模型是否可以根据不包含生存信息的给定测试数据集来确定测试数据集中的这些乘客是否幸存下来。
我们可能还想对问题的领域有一些早期的了解。这在这里的Kaggle竞争描述页面上进行了描述。以下是需要注意的亮点。
- 1912 年 4 月 15 日,泰坦尼克号在处女航中与冰山相撞后沉没,2224 名乘客和船员中有 1502 人死亡,存活率为32%。
- 沉船导致这种生命损失的原因之一是没有足够的救生艇供乘客和船员使用。
- 虽然在沉没中幸存下来有一些运气因素,但有些人群比其他人更有可能生存下来,例如妇女,儿童和上层阶级。
数据科学解决方案工作流解决了七个主要目标。
- 分类。我们可能希望对样本进行分类或分类。我们可能还希望了解不同类与我们的解决方案目标的含义或相关性。
- 相关性。人们可以根据训练数据集中的可用特征来解决问题。数据集中的哪些功能对我们的解决方案目标有重大贡献?从统计学上讲,功能和解决方案目标之间是否存在相关性?随着功能值的变化,解决方案状态是否也会改变,反之亦然?这既可以针对给定数据集中的数值特征和分类特征进行测试。我们可能还希望确定后续目标和工作流阶段的生存以外的特征之间的相关性。关联某些要素可能有助于创建、完成或更正要素。
- 转换。 对于建模阶段,需要准备数据。根据模型算法的选择,可能需要将所有特征转换为数值。例如,将文本分类值转换为数值。
- 填充。数据准备可能还需要我们估计要素中的任何缺失值。当没有缺失值时,模型算法可能效果最佳。
- 纠正。我们还可能分析给定的训练数据集中的错误或可能不确定的特征值,并尝试更正这些值或排除包含错误的样本。执行此操作的一种方法是检测我们的样本或特征中的任何异常值。如果某个特征没有对分析有贡献,或者可能显着扭曲结果,我们也可能会完全丢弃该特征。
- 创建。我们是否可以基于现有特征或一组特征创建新特征,以便新特征遵循相关性,转换,完整性目标。
- 制图。如何根据数据的性质和解决方案目标选择正确的可视化图和图表。
import pandas as pd import numpy as np import random as rnd import seaborn as sns import matplotlib.pyplot as plt from sklearn.linear_model import LogisticRegression from sklearn.svm import SVC,LinearSVC from sklearn.ensemble import RandomForestClassifier from sklearn.neighbors import KNeighborsClassifier from sklearn.naive_bayes import GaussianNB from sklearn.linear_model import SGDClassifier from sklearn.tree import DecisionTreeClassifier获取数据
train_df=pd.read_csv('titanic_train.csv')
test_df=pd.read_csv('test.csv')
combine=[train_df,test_df]
分析数据
#获取特征名 print(train_df.columns.values)
['PassengerId' 'Survived' 'Pclass' 'Name' 'Sex' 'Age' 'SibSp' 'Parch' 'Ticket' 'Fare' 'Cabin' 'Embarked']
- 类别型特征:survived,sex,embarked
- 序号:pclass
- 连续型数值型特征:age,fare
- 离散型数值型特征:sibsp,parch
train_df.head()
| PassengerId | Survived | Pclass | Name | Sex | Age | SibSp | Parch | Ticket | Fare | Cabin | Embarked | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 0 | 3 | Braund, Mr. Owen Harris | male | 22.0 | 1 | 0 | A/5 21171 | 7.2500 | NaN | S |
| 1 | 2 | 1 | 1 | Cumings, Mrs. John Bradley (Florence Briggs Th... | female | 38.0 | 1 | 0 | PC 17599 | 71.2833 | C85 | C |
| 2 | 3 | 1 | 3 | Heikkinen, Miss. Laina | female | 26.0 | 0 | 0 | STON/O2. 3101282 | 7.9250 | NaN | S |
| 3 | 4 | 1 | 1 | Futrelle, Mrs. Jacques Heath (Lily May Peel) | female | 35.0 | 1 | 0 | 113803 | 53.1000 | C123 | S |
| 4 | 5 | 0 | 3 | Allen, Mr. William Henry | male | 35.0 | 0 | 0 | 373450 | 8.0500 | NaN | S |
混合型数据:字母、数字混合,数据中的ticket和cabin
train_df.info()
print('-'*50)
test_df.info()
RangeIndex: 891 entries, 0 to 890 Data columns (total 12 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 PassengerId 891 non-null int64 1 Survived 891 non-null int64 2 Pclass 891 non-null int64 3 Name 891 non-null object 4 Sex 891 non-null object 5 Age 714 non-null float64 6 SibSp 891 non-null int64 7 Parch 891 non-null int64 8 Ticket 891 non-null object 9 Fare 891 non-null float64 10 Cabin 204 non-null object 11 Embarked 889 non-null object dtypes: float64(2), int64(5), object(5) memory usage: 83.7+ KB -------------------------------------------------- RangeIndex: 418 entries, 0 to 417 Data columns (total 11 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 PassengerId 418 non-null int64 1 Pclass 418 non-null int64 2 Name 418 non-null object 3 Sex 418 non-null object 4 Age 332 non-null float64 5 SibSp 418 non-null int64 6 Parch 418 non-null int64 7 Ticket 418 non-null object 8 Fare 417 non-null float64 9 Cabin 91 non-null object 10 Embarked 418 non-null object dtypes: float64(2), int64(4), object(5) memory usage: 36.0+ KB
- 对于train来说,cabin、age、embarked存在null
- test数据集:cabin和age不完整
train_df.describe()
| PassengerId | Survived | Pclass | Age | SibSp | Parch | Fare | |
|---|---|---|---|---|---|---|---|
| count | 891.000000 | 891.000000 | 891.000000 | 714.000000 | 891.000000 | 891.000000 | 891.000000 |
| mean | 446.000000 | 0.383838 | 2.308642 | 29.699118 | 0.523008 | 0.381594 | 32.204208 |
| std | 257.353842 | 0.486592 | 0.836071 | 14.526497 | 1.102743 | 0.806057 | 49.693429 |
| min | 1.000000 | 0.000000 | 1.000000 | 0.420000 | 0.000000 | 0.000000 | 0.000000 |
| 25% | 223.500000 | 0.000000 | 2.000000 | 20.125000 | 0.000000 | 0.000000 | 7.910400 |
| 50% | 446.000000 | 0.000000 | 3.000000 | 28.000000 | 0.000000 | 0.000000 | 14.454200 |
| 75% | 668.500000 | 1.000000 | 3.000000 | 38.000000 | 1.000000 | 0.000000 | 31.000000 |
| max | 891.000000 | 1.000000 | 3.000000 | 80.000000 | 8.000000 | 6.000000 | 512.329200 |
- 存活率是38%
- 总乘客数是891
- 高于75%的乘客没有带孩子或者父母
- 25%的人有兄弟或者姐妹在一起
- 很少有老年人乘坐
分类特征的分布情况:
- 名称在整个数据集中是唯一的
- 性别变量为两个值,男性占了65%
- cabin在样本之间具有多个二重。或者,几名乘客共用一间客舱
- embarked有三个值,大部分乘客由S登船
- ticket有高的重复值比率
#获得字符串的信息 train_df.describe(include=['O'])
| Name | Sex | Ticket | Cabin | Embarked | |
|---|---|---|---|---|---|
| count | 891 | 891 | 891 | 204 | 889 |
| unique | 891 | 2 | 681 | 147 | 3 |
| top | Braund, Mr. Owen Harris | male | 347082 | B96 B98 | S |
| freq | 1 | 577 | 7 | 4 | 644 |
相关性
我们想知道每个特征与生存的相关性如何。我们希望在项目的早期就做到这一点,并将这些快速相关性与项目后期的建模相关性相匹配。
填充
- 填充从age特征,因为它一定与存活有关
- 可能会填充embarked特征,因为它可能会与存活或者其他重要的特征有关
更正
- ticket可能会从我们的分析中移除,因为包含高的重复率(22%),可能survival和ticket没有关联
- cabin特征可能会被移除,由于它高度不相关并且含有很多空值在train和test数据集
- passengerld会从training数据集移除,因为它不会对survival产生影响
- name特征是完全不标准的,对survival没有直接贡献,也被移除
创造特征
- 可能创造一个family特征,依据parch和sibsp特征,这个特征包含船上的所有的家庭成员
- 处理name特征提取title作为新的特征
- 创造新的特征作为age 区间,这将连续的数值型特征转为有序的类别特征
- 创造新的fale 范围特征帮助分析
分类
我们还可以根据前面提到的问题描述来增加我们的假设。
- 女人更可能存活
- 儿童更可能存活
- pcalss=1的人更可能存活
为了证实我们的一些观察和假设,我们可以通过相互旋转特征来快速分析我们的特征相关性。在此阶段,我们只能对没有任何空值的特征执行此操作。仅对categorical(Sex),ordinal ( Pclass )或discrete( SibSp , Parch )类型的特征这样做也是有意义的。
- Pcalss。我们观察到Pclass=1和Survived(分类)之间存在显着相关性(>0.5)。我们决定将此功能包含在我们的模型中。
- Sex。我们证实了问题定义过程中的观察结果,即性别=女性的存活率为74%(分类)。
- SibSp and Parch.这些特征对于某些值的相关性为零。最好从这些单独的特征派生一个特征或一组特征(创建 #1)。
train_df[['Pclass', 'Survived']].groupby(['Pclass'], as_index=False).mean().sort_values(by='Survived', ascending=False)
| Pclass | Survived | |
|---|---|---|
| 0 | 1 | 0.629630 |
| 1 | 2 | 0.472826 |
| 2 | 3 | 0.242363 |
train_df[['Sex','Survived']].groupby(['Sex'],as_index=False). mean().sort_values(by='Survived',ascending=False)
| Sex | Survived | |
|---|---|---|
| 0 | female | 0.742038 |
| 1 | male | 0.188908 |
train_df[['SibSp','Survived']].groupby(['SibSp'],as_index=False). mean().sort_values(by='Survived',ascending=False)
| SibSp | Survived | |
|---|---|---|
| 1 | 1 | 0.535885 |
| 2 | 2 | 0.464286 |
| 0 | 0 | 0.345395 |
| 3 | 3 | 0.250000 |
| 4 | 4 | 0.166667 |
| 5 | 5 | 0.000000 |
| 6 | 8 | 0.000000 |
train_df[["Parch", "Survived"]].groupby(['Parch'], as_index=False).mean().sort_values(by='Survived', ascending=False)
| Parch | Survived | |
|---|---|---|
| 3 | 3 | 0.600000 |
| 1 | 1 | 0.550847 |
| 2 | 2 | 0.500000 |
| 0 | 0 | 0.343658 |
| 5 | 5 | 0.200000 |
| 4 | 4 | 0.000000 |
| 6 | 6 | 0.000000 |
现在,我们可以继续使用可视化来分析数据来确认我们的一些假设。
关联数值型特征
开始理解数值型特征与问题目标的联系
直方图对于分析连续的数值变量(如 Age)非常有用,其中区间或范围将有助于识别有用的模式。直方图可以使用自动定义的bins或等距bands指示样本的分布。这有助于我们回答与特定bands有关的问题(婴儿的存活率更高吗?)
请注意,组图可视化中的 x 轴表示样本或乘客的计数。
观察
- 婴儿(age小于等于4)有更高的存活率
- 最老的乘客(age=80)存活
- 15-25的大量人没有活下来
- 大部分乘客在15-35的年龄范围
这个简单的分析证实了我们作为后续工作流程阶段决策的假设。
- 在模型中要考虑age
- 填充age特征中的null值
- 扩大age的组别
g=sns.FacetGrid(train_df,col='Survived') g.map(plt.hist,'Age',bins=20)
关联数值型和序数特征
我们可以组合多个特征,以使用单个图来识别相关性。这可以通过具有数值的数值型和分类特征来完成。
观察
- 大部分乘客属于pcalss=3,然而大部分没有存户,证明了分类假设
- 在pclass=2和pclss=3的婴儿大部分存活
- pclass=1的乘客大部分存活
- pclass变量在乘客年龄分布有所不同
决定
考虑pclass在模型训练方面
grid=sns.FacetGrid(train_df,col='Survived',row='Pclass',
size=2.2,aspect=1.6)
grid.map(plt.hist,'Age',alpha=0.5,bins=20)
grid.add_legend()
E:Anacondalibsite-packagesseabornaxisgrid.py:337: UserWarning: The `size` parameter has been renamed to `height`; please update your code. warnings.warn(msg, UserWarning)关联分类特征
grid=sns.FacetGrid(train_df,row='Embarked',size=2.2,aspect=1.6) grid.map(sns.pointplot,'Pclass','Survived','Sex') grid.add_legend()
E:Anacondalibsite-packagesseabornaxisgrid.py:337: UserWarning: The `size` parameter has been renamed to `height`; please update your code. warnings.warn(msg, UserWarning) E:Anacondalibsite-packagesseabornaxisgrid.py:670: UserWarning: Using the pointplot function without specifying `order` is likely to produce an incorrect plot. warnings.warn(warning) E:Anacondalibsite-packagesseabornaxisgrid.py:675: UserWarning: Using the pointplot function without specifying `hue_order` is likely to produce an incorrect plot. warnings.warn(warning)
- 女性乘客比男性乘客有更多的存活率
- 在Embarked=C例外,男性存活率比女性高
- 在pclass=3男性存活率更高
decision
- 在model training中添加sex特征
- 填充并添加embarked特征到模型中
grid=sns.FacetGrid(train_df,row='Embarked',col='Survived',
size=2.2,aspect=1.6)
grid.map(sns.barplot,'Sex','Fare',alpha=0.5,ci=None)
grid.add_legend()
E:Anacondalibsite-packagesseabornaxisgrid.py:337: UserWarning: The `size` parameter has been renamed to `height`; please update your code. warnings.warn(msg, UserWarning) E:Anacondalibsite-packagesseabornaxisgrid.py:670: UserWarning: Using the barplot function without specifying `order` is likely to produce an incorrect plot. warnings.warn(warning)数据处理
通过删除特征进行校正
这是一个很好的起始目标。通过删除特征,我们正在处理更少的数据点。加快了我们的notebook速度并简化了分析。
删除cabin特征
请注意,在适用的情况下,我们同时对训练和测试数据集执行操作,以保持一致性。
print("Before", train_df.shape, test_df.shape, combine[0].shape, combine[1].shape)
Before (891, 12) (418, 11) (891, 12) (418, 11)
train_df=train_df.drop(['Ticket','Cabin'],axis=1) test_df=test_df.drop(['Ticket','Cabin'],axis=1) combine = [train_df, test_df]
print("After", train_df.shape, test_df.shape, combine[0].shape, combine[1].shape)
After (891, 10) (418, 9) (891, 10) (418, 9)
创造新的特征
分析name特征是否可以可以设计为titles并且检测titles和survival的相关性,在移除name和passengerid之前
for dataset in combine:#combine为含两个元素列表[train,test]
dataset['Title']=dataset.Name.str.extract('([A-Za-z]+).',expand=False)
pd.crosstab(train_df['Title'], train_df['Sex'])
| Sex | female | male |
|---|---|---|
| Title | ||
| Capt | 0 | 1 |
| Col | 0 | 2 |
| Countess | 1 | 0 |
| Don | 0 | 1 |
| Dr | 1 | 6 |
| Jonkheer | 0 | 1 |
| Lady | 1 | 0 |
| Major | 0 | 2 |
| Master | 0 | 40 |
| Miss | 182 | 0 |
| Mlle | 2 | 0 |
| Mme | 1 | 0 |
| Mr | 0 | 517 |
| Mrs | 125 | 0 |
| Ms | 1 | 0 |
| Rev | 0 | 6 |
| Sir | 0 | 1 |
可以代替许多titles用常见的称谓或者分为rare一类
for dataset in combine:
dataset['Title']=dataset['Title'].replace(['Lady', 'Countess','Capt', 'Col',
'Don', 'Dr', 'Major', 'Rev', 'Sir', 'Jonkheer', 'Dona'], 'Rare')
dataset['Title']=dataset['Title'].replace('Mile','Miss')
dataset['Title']=dataset['Title'].replace('MS','Miss')
dataset['Title']=dataset['Title'].replace('Mme','Mrs')
train_df[['Title','Survived']].groupby(['Title'],as_index=False).mean()
| Title | Survived | |
|---|---|---|
| 0 | Master | 0.575000 |
| 1 | Miss | 0.697802 |
| 2 | Mlle | 1.000000 |
| 3 | Mr | 0.156673 |
| 4 | Mrs | 0.793651 |
| 5 | Ms | 1.000000 |
| 6 | Rare | 0.347826 |
将类别型的title转为顺序性
title_mapping = {"Mr": 1, "Miss": 2, "Mrs": 3, "Master": 4, "Rare": 5}
for dataset in combine:
dataset['Title']=dataset['Title'].map(title_mapping)
dataset['Title']=dataset['Title'].fillna(0)
train_df.head()
| PassengerId | Survived | Pclass | Name | Sex | Age | SibSp | Parch | Fare | Embarked | Title | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 0 | 3 | Braund, Mr. Owen Harris | male | 22.0 | 1 | 0 | 7.2500 | S | 1.0 |
| 1 | 2 | 1 | 1 | Cumings, Mrs. John Bradley (Florence Briggs Th... | female | 38.0 | 1 | 0 | 71.2833 | C | 3.0 |
| 2 | 3 | 1 | 3 | Heikkinen, Miss. Laina | female | 26.0 | 0 | 0 | 7.9250 | S | 2.0 |
| 3 | 4 | 1 | 1 | Futrelle, Mrs. Jacques Heath (Lily May Peel) | female | 35.0 | 1 | 0 | 53.1000 | S | 3.0 |
| 4 | 5 | 0 | 3 | Allen, Mr. William Henry | male | 35.0 | 0 | 0 | 8.0500 | S | 1.0 |
现在可以丢弃name特征从train和test数据集,也不需要passengerld特征在训练集中
train_df=train_df.drop(['Name','PassengerId'],axis=1) test_df=test_df.drop(['Name'],axis=1) combine = [train_df, test_df] train_df.shape, test_df.shape
((891, 9), (418, 9))
转换分类特征
可以将含strings的特征转为数值型,对于大部分算法是需要的。
把sex特征转为新的特征叫做gender,female=1,male=0
for dataset in combine:
dataset['Sex']=dataset['Sex'].map({'female':1,'male':0})
train_df.head()
| Survived | Pclass | Sex | Age | SibSp | Parch | Fare | Embarked | Title | |
|---|---|---|---|---|---|---|---|---|---|
| 0 | 0 | 3 | 0 | 22.0 | 1 | 0 | 7.2500 | S | 1.0 |
| 1 | 1 | 1 | 1 | 38.0 | 1 | 0 | 71.2833 | C | 3.0 |
| 2 | 1 | 3 | 1 | 26.0 | 0 | 0 | 7.9250 | S | 2.0 |
| 3 | 1 | 1 | 1 | 35.0 | 1 | 0 | 53.1000 | S | 3.0 |
| 4 | 0 | 3 | 0 | 35.0 | 0 | 0 | 8.0500 | S | 1.0 |
转换数值连续性特征
现在,我们应该开始估计和完成具有缺失值或空值的特征。我们将首先为年龄特征执行此操作
我们可以考虑三种方法来完成一个数值连续特征。
- 一种简单的方法是在平均值和标准差之间生成随机数。
- 更准确地猜测缺失值的方法是使用其他相关特征。在我们的例子中,我们注意到年龄,性别和Pclass的相关性。在 Pcalss和gender特征组合集中使用年龄的中位数来猜测年龄值。所以对于pclss=1 和gender=0有个中位数,对于pclass=1和gender=1有个年龄中位数
- 合并方法 1 和 2。因此,不要根据中位数猜测年龄值,而是根据 Pclass和性别组合的集合,在平均值和标准差之间使用随机数。
grid = sns.FacetGrid(train_df, row='Pclass', col='Sex', size=2.2, aspect=1.6) grid.map(plt.hist, 'Age', alpha=.5, bins=20) grid.add_legend()
E:Anacondalibsite-packagesseabornaxisgrid.py:337: UserWarning: The `size` parameter has been renamed to `height`; please update your code. warnings.warn(msg, UserWarning)
准备一个空的array,来包含年龄的值根据pclass x gender 组合
guess_ages = np.zeros((2,3)) guess_ages
array([[0., 0., 0.],
[0., 0., 0.]])
迭代sex(0or1)和pclass(1,2,3)来计算6个组合的年龄猜测值
for dataset in combine:
for i in range(0,2):
for j in range(0,3):
guess_df=dataset[(dataset['Sex']==i)&(dataset['Pclass']==j+1)]['Age'].dropna()
age_guess=guess_df.median()
#将random 浮点型age转为接近0.5age
guess_ages[i,j] = int( age_guess/0.5 + 0.5 ) * 0.5
for i in range(0,2):
for j in range(0,3):
dataset.loc[(dataset.Age.isnull())&(dataset.Sex==i)&(dataset.Pclass==j+1),
'Age']=guess_ages[i,j]
dataset['Age']=dataset['Age'].astype(int)
train_df.head()
| Survived | Pclass | Sex | Age | SibSp | Parch | Fare | Embarked | Title | |
|---|---|---|---|---|---|---|---|---|---|
| 0 | 0 | 3 | 0 | 22 | 1 | 0 | 7.2500 | S | 1.0 |
| 1 | 1 | 1 | 1 | 38 | 1 | 0 | 71.2833 | C | 3.0 |
| 2 | 1 | 3 | 1 | 26 | 0 | 0 | 7.9250 | S | 2.0 |
| 3 | 1 | 1 | 1 | 35 | 1 | 0 | 53.1000 | S | 3.0 |
| 4 | 0 | 3 | 0 | 35 | 0 | 0 | 8.0500 | S | 1.0 |
确定age区间并确定与survived的关联性
train_df['AgeBand']=pd.cut(train_df['Age'],5)
train_df[['AgeBand','Survived']].groupby(['AgeBand'],
as_index=False).mean().sort_values(by='AgeBand',ascending=True)
| AgeBand | Survived | |
|---|---|---|
| 0 | (-0.08, 16.0] | 0.550000 |
| 1 | (16.0, 32.0] | 0.337374 |
| 2 | (32.0, 48.0] | 0.412037 |
| 3 | (48.0, 64.0] | 0.434783 |
| 4 | (64.0, 80.0] | 0.090909 |
安装顺序依照bands替代age
for dataset in combine:
dataset.loc[dataset['Age']<=16,'Age']=0
dataset.loc[(dataset['Age']>16)&(dataset['Age']<=32),'Age']=1
dataset.loc[(dataset['Age']>32)&(dataset['Age']<=48),'Age']=2
dataset.loc[(dataset['Age']>48)&(dataset['Age']<=64),'Age']=3
dataset.loc[dataset['Age']>64,'Age']=4
train_df.head()
| Survived | Pclass | Sex | Age | SibSp | Parch | Fare | Embarked | Title | AgeBand | |
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0 | 3 | 0 | 1 | 1 | 0 | 7.2500 | S | 1.0 | (16.0, 32.0] |
| 1 | 1 | 1 | 1 | 2 | 1 | 0 | 71.2833 | C | 3.0 | (32.0, 48.0] |
| 2 | 1 | 3 | 1 | 1 | 0 | 0 | 7.9250 | S | 2.0 | (16.0, 32.0] |
| 3 | 1 | 1 | 1 | 2 | 1 | 0 | 53.1000 | S | 3.0 | (32.0, 48.0] |
| 4 | 0 | 3 | 0 | 2 | 0 | 0 | 8.0500 | S | 1.0 | (32.0, 48.0] |
移除ageband特征
train_df=train_df.drop(['AgeBand'],axis=1) combine=[train_df,test_df] train_df.head()
| Survived | Pclass | Sex | Age | SibSp | Parch | Fare | Embarked | Title | |
|---|---|---|---|---|---|---|---|---|---|
| 0 | 0 | 3 | 0 | 1 | 1 | 0 | 7.2500 | S | 1.0 |
| 1 | 1 | 1 | 1 | 2 | 1 | 0 | 71.2833 | C | 3.0 |
| 2 | 1 | 3 | 1 | 1 | 0 | 0 | 7.9250 | S | 2.0 |
| 3 | 1 | 1 | 1 | 2 | 1 | 0 | 53.1000 | S | 3.0 |
| 4 | 0 | 3 | 0 | 2 | 0 | 0 | 8.0500 | S | 1.0 |
组合存在特征创造新特征
创造名为familysize的新的特征,包含parch和sibsp。将能够使我们丢掉parch和sibsp特征
for dataset in combine:
dataset['FamilySize']=dataset['SibSp']+dataset['Parch']+1
train_df[['FamilySize','Survived']].groupby(['FamilySize'],as_index=False).mean().sort_values(by='Survived',ascending=False)
| FamilySize | Survived | |
|---|---|---|
| 3 | 4 | 0.724138 |
| 2 | 3 | 0.578431 |
| 1 | 2 | 0.552795 |
| 6 | 7 | 0.333333 |
| 0 | 1 | 0.303538 |
| 4 | 5 | 0.200000 |
| 5 | 6 | 0.136364 |
| 7 | 8 | 0.000000 |
| 8 | 11 | 0.000000 |
创建叫做IsAlone的另一个特征
for dataset in combine:
dataset['IsAlone']=0
dataset.loc[dataset['FamilySize']==1,'IsAlone']=1
train_df[['IsAlone', 'Survived']].groupby(['IsAlone'], as_index=False).mean()
| IsAlone | Survived | |
|---|---|---|
| 0 | 0 | 0.505650 |
| 1 | 1 | 0.303538 |
丢掉parch、sibsp、familysize特征
train_df=train_df.drop(['Parch','SibSp','FamilySize'],axis=1)
test_df=test_df.drop(['Parch','SibSp','FamilySize'],axis=1) combine = [train_df, test_df] train_df.head()
| Survived | Pclass | Sex | Age | Fare | Embarked | Title | IsAlone | |
|---|---|---|---|---|---|---|---|---|
| 0 | 0 | 3 | 0 | 1 | 7.2500 | S | 1.0 | 0 |
| 1 | 1 | 1 | 1 | 2 | 71.2833 | C | 3.0 | 0 |
| 2 | 1 | 3 | 1 | 1 | 7.9250 | S | 2.0 | 1 |
| 3 | 1 | 1 | 1 | 2 | 53.1000 | S | 3.0 | 0 |
| 4 | 0 | 3 | 0 | 2 | 8.0500 | S | 1.0 | 1 |
创建一个组合pcalss和age的特征
for dataset in combine:
dataset['Age*Class'] = dataset.Age * dataset.Pclass
train_df.loc[:, ['Age*Class', 'Age', 'Pclass']].head(10)
| Age*Class | Age | Pclass | |
|---|---|---|---|
| 0 | 3 | 1 | 3 |
| 1 | 2 | 2 | 1 |
| 2 | 3 | 1 | 3 |
| 3 | 2 | 2 | 1 |
| 4 | 6 | 2 | 3 |
| 5 | 3 | 1 | 3 |
| 6 | 3 | 3 | 1 |
| 7 | 0 | 0 | 3 |
| 8 | 3 | 1 | 3 |
| 9 | 0 | 0 | 2 |
创造分类特征
embarked特征包含S,Q,C。训练集有两个遗失的值,使用最常见的值填充
freq_port=train_df.Embarked.dropna().mode()[0] freq_port
'S'
for dataset in combine:
dataset['Embarked']=dataset['Embarked'].fillna(freq_port)
train_df[['Embarked', 'Survived']].groupby(['Embarked'], as_index=False).mean().sort_values(by='Survived', ascending=False)
| Embarked | Survived | |
|---|---|---|
| 0 | C | 0.553571 |
| 1 | Q | 0.389610 |
| 2 | S | 0.339009 |
将类别型特征转为数值型
for dataset in combine:
dataset['Embarked'] = dataset['Embarked'].map( {'S': 0, 'C': 1, 'Q': 2} ).astype(int)
train_df.head()
| Survived | Pclass | Sex | Age | Fare | Embarked | Title | IsAlone | Age*Class | |
|---|---|---|---|---|---|---|---|---|---|
| 0 | 0 | 3 | 0 | 1 | 7.2500 | 0 | 1.0 | 0 | 3 |
| 1 | 1 | 1 | 1 | 2 | 71.2833 | 1 | 3.0 | 0 | 2 |
| 2 | 1 | 3 | 1 | 1 | 7.9250 | 0 | 2.0 | 1 | 3 |
| 3 | 1 | 1 | 1 | 2 | 53.1000 | 0 | 3.0 | 0 | 2 |
| 4 | 0 | 3 | 0 | 2 | 8.0500 | 0 | 1.0 | 1 | 6 |
填充和转换数值型特征
现在,我们可以使用mode完成测试数据集中单个缺失值的 Fare 特征,以获取此特征最常出现的值。我们在一行代码中完成此操作。
请注意,我们不是在创建中间新功能或进行任何进一步的分析,以便与猜测缺失特征的相关性,因为我们只替换单个值。完成实现了模型算法对非空值进行操作的所需要求。
我们可能还希望将票价四舍五入到小数点后两位,因为它代表货币。
test_df['Fare'].fillna(test_df['Fare'].dropna().median(), inplace=True) test_df.head()
| PassengerId | Pclass | Sex | Age | Fare | Embarked | Title | IsAlone | Age*Class | |
|---|---|---|---|---|---|---|---|---|---|
| 0 | 892 | 3 | 0 | 2 | 7.8292 | 2 | 1.0 | 1 | 6 |
| 1 | 893 | 3 | 1 | 2 | 7.0000 | 0 | 3.0 | 0 | 6 |
| 2 | 894 | 2 | 0 | 3 | 9.6875 | 2 | 1.0 | 1 | 6 |
| 3 | 895 | 3 | 0 | 1 | 8.6625 | 0 | 1.0 | 1 | 3 |
| 4 | 896 | 3 | 1 | 1 | 12.2875 | 0 | 3.0 | 0 | 3 |
#创建fareband train_df['FareBand']=pd.qcut(train_df['Fare'],4) train_df[['FareBand', 'Survived']].groupby(['FareBand'], as_index=False).mean().sort_values(by='FareBand', ascending=True)
| FareBand | Survived | |
|---|---|---|
| 0 | (-0.001, 7.91] | 0.197309 |
| 1 | (7.91, 14.454] | 0.303571 |
| 2 | (14.454, 31.0] | 0.454955 |
| 3 | (31.0, 512.329] | 0.581081 |
根据fareband将fare特征转为ordinal值
for dataset in combine:
dataset.loc[ dataset['Fare'] <= 7.91, 'Fare'] = 0
dataset.loc[(dataset['Fare'] > 7.91) & (dataset['Fare'] <= 14.454), 'Fare'] = 1
dataset.loc[(dataset['Fare'] > 14.454) & (dataset['Fare'] <= 31), 'Fare'] = 2
dataset.loc[ dataset['Fare'] > 31, 'Fare'] = 3
dataset['Fare'] = dataset['Fare'].astype(int)
train_df = train_df.drop(['FareBand'], axis=1)
combine = [train_df, test_df]
train_df.head(10)
| Survived | Pclass | Sex | Age | Fare | Embarked | Title | IsAlone | Age*Class | |
|---|---|---|---|---|---|---|---|---|---|
| 0 | 0 | 3 | 0 | 1 | 0 | 0 | 1.0 | 0 | 3 |
| 1 | 1 | 1 | 1 | 2 | 3 | 1 | 3.0 | 0 | 2 |
| 2 | 1 | 3 | 1 | 1 | 1 | 0 | 2.0 | 1 | 3 |
| 3 | 1 | 1 | 1 | 2 | 3 | 0 | 3.0 | 0 | 2 |
| 4 | 0 | 3 | 0 | 2 | 1 | 0 | 1.0 | 1 | 6 |
| 5 | 0 | 3 | 0 | 1 | 1 | 2 | 1.0 | 1 | 3 |
| 6 | 0 | 1 | 0 | 3 | 3 | 0 | 1.0 | 1 | 3 |
| 7 | 0 | 3 | 0 | 0 | 2 | 0 | 4.0 | 0 | 0 |
| 8 | 1 | 3 | 1 | 1 | 1 | 0 | 3.0 | 0 | 3 |
| 9 | 1 | 2 | 1 | 0 | 2 | 1 | 3.0 | 0 | 0 |
test_df.head(10)
| PassengerId | Pclass | Sex | Age | Fare | Embarked | Title | IsAlone | Age*Class | |
|---|---|---|---|---|---|---|---|---|---|
| 0 | 892 | 3 | 0 | 2 | 0 | 2 | 1.0 | 1 | 6 |
| 1 | 893 | 3 | 1 | 2 | 0 | 0 | 3.0 | 0 | 6 |
| 2 | 894 | 2 | 0 | 3 | 1 | 2 | 1.0 | 1 | 6 |
| 3 | 895 | 3 | 0 | 1 | 1 | 0 | 1.0 | 1 | 3 |
| 4 | 896 | 3 | 1 | 1 | 1 | 0 | 3.0 | 0 | 3 |
| 5 | 897 | 3 | 0 | 0 | 1 | 0 | 1.0 | 1 | 0 |
| 6 | 898 | 3 | 1 | 1 | 0 | 2 | 2.0 | 1 | 3 |
| 7 | 899 | 2 | 0 | 1 | 2 | 0 | 1.0 | 0 | 2 |
| 8 | 900 | 3 | 1 | 1 | 0 | 1 | 3.0 | 1 | 3 |
| 9 | 901 | 3 | 0 | 1 | 2 | 0 | 1.0 | 0 | 3 |
现在,我们已准备好训练模型并预测所需的解决方案。有60多种预测建模算法可供选择。我们必须了解问题的类型和解决方案要求,以缩小到我们可以评估的少数几个模型。我们的问题是一个分类和回归问题。我们想要确定输出(存活或未存活)与其他变量或特征(性别,年龄,端口等)之间的关系。我们还在实践一类机器学习,称为监督学习,因为我们使用给定的数据集训练模型。有了这两个标准 - 监督学习加上分类和回归,我们可以将模型的选择范围缩小到几个。这些包括:
- Logistic Regression
- KNN or k-Nearest Neighbors
- Support Vector Machines
- Naive Bayes classifier
- Decision Tree
- Random Forrest
- Perceptron
- Artificial neural network
- RVM or Relevance Vector Machine
X_train = train_df.drop("Survived", axis=1)
Y_train = train_df["Survived"]
X_test = test_df.drop("PassengerId", axis=1).copy()
X_train.shape, Y_train.shape, X_test.shape
((891, 8), (891,), (418, 8))
logreg = LogisticRegression() logreg.fit(X_train, Y_train) Y_pred = logreg.predict(X_test) acc_log = round(logreg.score(X_train, Y_train) * 100, 2) acc_log
81.48
coeff_df = pd.DataFrame(train_df.columns.delete(0)) coeff_df.columns = ['Feature'] coeff_df["Correlation"] = pd.Series(logreg.coef_[0]) coeff_df.sort_values(by='Correlation', ascending=False)
| Feature | Correlation | |
|---|---|---|
| 1 | Sex | 2.214822 |
| 5 | Title | 0.396525 |
| 4 | Embarked | 0.276812 |
| 6 | IsAlone | 0.188501 |
| 7 | Age*Class | -0.049482 |
| 3 | Fare | -0.069380 |
| 2 | Age | -0.474486 |
| 0 | Pclass | -1.204318 |
我们可以使用 Logistic 回归来验证我们对特征创建和完成目标的假设和决策。这可以通过计算决策函数中特征的系数来完成。
正系数增加响应的对数赔率(从而增加概率),负系数降低响应的对数赔率(从而降低概率)。
- 性别是最高的正向系数,这意味着随着sex值的增加(男性:0到女性:1),存活=1的概率增加最大。
- paclass增加,survived=1概率下降最大
使用支持矢量机进行建模,支持矢量机是监督学习模型,具有相关的学习算法,用于分析用于分类和回归分析的数据。给定一组训练样本,每个样本都标记为属于两个类别中的一个或另一个类别,SVM 训练算法构建一个模型,将新测试样本分配给一个类别或另一个类别,使其成为非概率二元线性分类器。
svc = SVC() svc.fit(X_train, Y_train) Y_pred = svc.predict(X_test) acc_svc = round(svc.score(X_train, Y_train) * 100, 2) acc_svc
82.83
在模式识别中,k-最近邻算法(简称k-NN)是一种用于分类和回归的非参数方法。样本由其邻居的多数票进行分类,样本被分配到其 k 个最近邻居中最常见的类(k 是正整数,通常很小)。如果 k = 1,则对象只是分配给该单个最近邻的类。
knn = KNeighborsClassifier(n_neighbors = 3) knn.fit(X_train, Y_train) Y_pred = knn.predict(X_test) acc_knn = round(knn.score(X_train, Y_train) * 100, 2) acc_knn
75.87



