泰坦热度最高分享
Titanic Data Science Solutions
Titanic Data Science Solutions (kaggle.com)
这个笔记是《Data Science Solutions》的配套资料,比较遵循固定流程。
此书将竞赛解决方案流程分为:1.问题定义;2.数据收集:获取train和test;3.数据处理:整理、准备、清洗数据;4.数据分析:分析、识别模式并且探索数据;5.数据分析:建模、预测并解决问题;6.数据展现和报告撰写:可视化、报告步骤和解决方案;7提交结果
上面的总结文字是我看hadoop的总结
例外:合并,提前或多次执行,跳过某个阶段
泰坦问题介绍: 1912年4月15日,泰坦尼克号在处女航期间撞上冰山沉没,造成2224名乘客和船员中的1502人死亡。生存率为32%。 导致船难造成如此大生命损失的原因之一是乘客和船员的救生艇不足。 某些群体的人比其他人更有可能幸存,例如妇女、儿童和上层阶级。
数据科学可分为以下几个目标:1.分类;2.相关性;3.转换(如将文本转换为数值);4.补全(缺失值);5.创建(新特征,且 符合相关性、转换、完整性目标 );7.图表化
附用户评论:1.将训练和测试数据合并再操作(如将数据集中标题转换为数值)——避免数据泄露,保持一致性,处理缺失值和异常值以及数据缩放和标准化,标题转化为数值是为了满足机器学习算法的输入需求,提高模型的性能,并进行更高级的特征工程(通过适当的编码方法,可以确保数据在转换后的数值形式下仍然保持其原始信息的含义);
2.接近30%的乘客有兄弟姐妹或配偶在船上;
3.正确解释逻辑回归系数
logit(p)=log(p/(1−p))=β0+β1x1+β2x2+⋯+βnxn 其中,p 是目标变量为正类的概率,𝛽0是截距项,𝛽𝑖是特征𝑥𝑖的系数。 解释单个系数 系数 𝛽𝑖 的解释是:当其他变量保持不变时,特征xi增加一个单位,log-odds 会增加 𝛽𝑖单位。 为了更直观,可以将其转换为概率变化: odds=𝑒的𝛽0+𝛽1𝑥1+⋯+𝛽𝑖𝑥𝑖+⋯+𝛽𝑛𝑥𝑛次方 其中,odds odds 表示事件发生的可能性与其不发生的可能性的比值。 示例 假设逻辑回归模型输出的系数如下: 截距(𝛽0) = -2 年龄(𝛽1) = 0.05 收入(𝛽2) = 0.1 解释这些系数: 截距 𝛽0=−2:表示当所有特征都为零时,log-odds 是 -2,odds 是 𝑒−2次方 年龄 𝛽1=0.05:表示年龄每增加一岁,log-odds 增加 0.05,对应的 odds 增加 𝑒0.05≈1.051,即增加约5.1%的可能性。 收入 𝛽2=0.1:表示收入每增加一个单位,log-odds 增加 0.1,对应的 odds 增加 𝑒0.1≈1.105,即增加约10.5%的可能性。 总结 正确解释逻辑回归系数有助于理解模型的行为、变量的影响、业务洞察以及模型的诊断和优化。这不仅提升了技术分析的准确性,还提高了与业务和非技术团队沟通的效率和效果。
移植问题:指定图表尺寸,将图例放入图表中 ——前者为了美观和图表的一致性,后者为了视觉集中和美观
最佳实践:1.在项目初期进行特征相关性分析;2.使用多个图而不是叠加图以提高可读性
1.前奏
数据分析与数据整理
代码1——全篇引用第三方库
# data analysis and wrangling import pandas as pd import numpy as np import random as rnd # visualization import seaborn as sns import matplotlib.pyplot as plt %matplotlib inline # machine learning 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 Perceptron from sklearn.linear_model import SGDClassifier from sklearn.tree import DecisionTreeClassifier
pandas,numpy和random——数据分析、数组计算、生成随机数
seaborn,matplotlib,%matplotlib inline——可视化,且确保图像直接显示在Notebook中
从sklearn的各种包中import的LogisticRegression,SVC, LinearSVC,RandomForestClassifier,KNeighborsClassifier,GaussianNB,Perceptron,SGDClassifier,DecisionTreeClassifier——逻辑回归(解决二分类问题),支持向量机(线性和非线性任务),SVM的线性版本(线性可分的数据集),随机森林分类器(集成学习方法,基于多颗决策树进行分类),K近邻分类器(基于实例的学习方法, 根据数据点在特征空间中的距离来进行分类,其对于非线性和复杂的决策边界较为有效 ),高斯朴素贝叶斯分类器( 基于贝叶斯定理和特征条件独立假设的分类算法 , 适用于连续特征的分类任务 ),感知机( 简单的线性分类器,适用于线性可分的数据集 ),随机梯度下降分类器( 基于随机梯度下降算法的线性分类器。它适用于大规模数据集和高维特征空间 ),决策树分类器( 基于树结构的分类器,通过从根节点到叶节点的序列决策进行分类,其适用于可解释性强和非线性可分的问题 )
2.获取数据
获取再合并,便于联合操作。这里和之前训练一样也有read_csv,这里合并用的combine,Python一如既往的简洁
代码2——获取数据并合并
train_df = pd.read_csv('../input/train.csv') test_df = pd.read_csv('../input/test.csv') combine = [train_df, test_df]
3.数据分析
代码3——获取可用特征名称
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——父母/子女数量
代码4——查看数据预览
# 查看数据预览 train_df.head()——查看前面5行 train_df.tail()——查看最后5行
看出点什么来了
混合数据类型: Ticket——票号(如 A/5 21171 ), Cabin——舱房号 (如 C85 )
可能出错的特征:name
包含空白,null或空值的特征
train中的空值数量: Cabin > Age > Embarked
test中 的空值数量:Cabin > Age
各特征的数据类型
七个特征是整数或浮点数(测试数据集为六个)。
五个特征是字符串(对象)。
代码5——数据信息
train_df.info() print('_'*40) test_df.info()
数值特征值在样本中的分布
train在多大程度上代表了实际问题领域。
总样本数为891,占泰坦尼克号实际乘客数量(2224)的40%。 Survived是一个具有0或1值的分类特征。 大约38%的样本幸存,代表实际生存率为32%。 大多数乘客(> 75%)没有与父母或孩子一起旅行。 近30%的乘客有兄弟姐妹和/或配偶在船上。 票价变化显著,少数乘客(<1%)支付高达512美元。 年龄在65-80岁的老年乘客很少(<1%)。
代码6——数据统计信息
train_df.describe() 通过percentiles=[.61, .62]审查生存率,知道问题描述中提到38%的生存率。 通过percentiles=[.75, .8]审查Parch分布。 通过percentiles=[.68, .69]审查SibSp分布。 通过percentiles=[.1, .2, .3, .4, .5, .6, .7, .8, .9, .99]审查Age和Fare分布。 这段话描述了在数据分析中,通过指定不同的百分位数(percentiles)来审查和了解特定特征(列)的分布情况。让我们逐句解释其含义: 通过percentiles=[.61, .62]审查生存率: 这句话意味着要查看生存率这一特征的分布情况。通过指定百分位数为0.61和0.62,可以具体了解生存率在这两个百分位数处的值,从而可能揭示出数据分布的一些细节。 通过percentiles=[.75, .8]审查Parch分布: 这句话指出要审查Parch(父母/子女数量)特征的分布情况。通过指定百分位数为0.75和0.8,可以了解Parch特征在这两个百分位数处的值,帮助分析Parch的分布及其集中趋势。 百分位数的作用 百分位数是描述数据分布的一种方式,可以帮助理解数据的集中趋势和离散程度。 例如,使用 [.61, .62] 这样的百分位数可以查看生存率在这两个具体位置的情况,可能揭示出特定生存率区间内的数据特征。 应用场景 在数据分析和探索阶段,审查不同特征的百分位数可以帮助: 发现数据的异常或不寻常的值。 确定数据的集中趋势和分布形状,例如是否有偏态或长尾分布。 支持数据预处理和特征工程的决策,例如处理异常值或进行特征缩放。 通过这种方法,分析人员可以更深入地理解数据的特征和行为,为进一步的建模和分析提供基础。
分类特征的分布是什么? 名称在整个数据集中是唯一的(count=unique=891)。 性别变量有两个可能的值,其中65%为男性(top=male, freq=577/count=891)。 舱位有多个样本重复。或者多个乘客共享一个舱位。 登船口岸有三个可能的值。大多数乘客使用S港(top=S)。 票据特征有较高的重复比例(22%)(unique=681)。
代码7——查询非空值数量,唯一值数量,频率最高的值及其频数
train_df.describe(include=['O']) 调用 describe(include=['O']) 方法可以生成关于DataFrame中对象类型列的统计描述,通常包括以下信息: count:非空值数量。 unique:唯一值数量。 top:出现频率最高的值。 freq:出现频率最高的值的频数。
基于数据分析的假设
相关性
了解每个特征与生存的相关性如何,在项目早期进行此操作,并在项目后期将这些快速相关性与建模后的相关性进行匹配。
补全数据
补全年龄特征,因为它肯定与生存相关,补全登船口岸特征,因为它也可能与生存或其他重要特征相关。
纠正数据
票据特征会从分析中删除,因为它包含高比例的重复(22%),并且票据与生存之间可能没有相关性。
舱位特征可能会删除,因为它在训练和测试数据集中都高度不完整或包含许多空值。
乘客ID可能会从训练数据集中删除,因为它对生存没有贡献。
名称特征相对不标准,可能不会直接贡献于生存,因此可能会删除。
创建新特征
基于Parch和SibSp创建一个名为Family的新特征,以获取船上家庭成员的总数。 对名称特征进行工程化以提取头衔作为新特征。
创建新的年龄段特征,将连续数值特征转换为有序分类特征。
如果有助于分析,还可能希望创建票价范围特征。
分类
还可以根据之前记录的问题描述添加假设。
-
女性(性别=female)更有可能生存。
-
儿童(年龄<?)更有可能生存。
-
上层舱位的乘客(Pclass=1)更有可能生存。
分析透视特征
为了确认观察和假设,可以通过透视特征来快速分析特征之间的相关性。仅对分类(Sex)、有序(Pclass)或离散(SibSp, Parch)类型的特征有意义。(均为无空值特征)
Pclass(舱位等级) Pclass=1与生还率之间有显著的相关性(>0.5)——模型保留该特征
Sex(性别)在问题定义中Sex=female(女性)的生还率非常高,为74%。
SibSp(兄弟姐妹/配偶数量)和Parch(父母/子女数量) 在某些值上没有相关性——从这些单独的特征中派生出一个或一组新的特征。
代码8—— 不同(Pclass)+(
Sex)+(
SibSp)+(
Parch )的(
Survived),并将结果按Survived排序
train_df[['Pclass', 'Survived']].groupby(['Pclass'], as_index=False).mean().sort_values(by='Survived', ascending=False) train_df[['Pclass', 'Survived']]: 从DataFrame train_df 中选择 Pclass 和 Survived 两列。 .groupby(['Pclass'], as_index=False): 按照 Pclass 列进行分组。参数 as_index=False 表示分组键(Pclass)不作为结果的索引,而是保留为列。 .mean(): 计算每个 Pclass 分组的平均值。在这里,主要关注的是 Survived 列的平均值,这代表了每个 Pclass 的平均生存率。 .sort_values(by='Survived', ascending=False): 按照 Survived 列的值进行降序排序,这样生存率高的 Pclass 会排在前面。 train_df[["Sex", "Survived"]].groupby(['Sex'], as_index=False).mean().sort_values(by='Survived', ascending=False) train_df[["SibSp", "Survived"]].groupby(['SibSp'], as_index=False).mean().sort_values(by='Survived', ascending=False) train_df[["Parch", "Survived"]].groupby(['Parch'], as_index=False).mean().sort_values(by='Survived', ascending=False)
可视化数据分析
通过可视化来确认假设,以分析数据。
数值特征的相关性
首先了解数值特征与我们的目标(生还情况)之间的相关性。
直方图对于分析像年龄这样连续数值变量是有用的,其中分段或范围可以帮助识别有用的模式。直方图可以使用自动定义的箱子或等距范围来表示样本分布。这有助于我们回答与特定分段有关的问题(婴儿的生还率是否更高?)
注:直方图与柱状图的区别 数据类型: 直方图:连续数据。 柱状图:离散数据或分类数据。 条形之间: 直方图:条形之间无间隙。 柱状图:条形之间有间隙。 用途: 直方图:用于展示数据的分布。 柱状图:用于比较不同类别的数据。
请注意,直方图可视化中的x轴表示样本或乘客的数量。
观察结果
-
婴儿(年龄<=4)生还率高。
-
年龄最大的乘客(80岁)生还。
-
大量15-25岁的乘客没有生还。
-
大多数乘客年龄在15-35岁之间。
决策
这个简单的分析确认了我们在后续工作流程阶段的假设和决策。
-
我们应该在模型训练中考虑年龄(假设分类#2)。
-
补全年龄特征的空值(补全#1)。
-
我们应该对年龄进行分段(创建#3)。
代码9—— Age
列在不同Survived
条件下的分布
g = sns.FacetGrid(train_df, col='Survived') g.map(plt.hist, 'Age', bins=20) g = sns.FacetGrid(train_df, col='Survived'): 创建一个Seaborn的FacetGrid对象g,它将数据train_df按照Survived列分成多个子图(facets)。col='Survived'表示每个子图对应一个Survived的取值。 例如,如果Survived列有两个值(0表示未生存,1表示生存),则会创建两个子图,一个对应Survived=0,另一个对应Survived=1。 g.map(plt.hist, 'Age', bins=20'): 使用map方法,将指定的绘图函数(这里是plt.hist,即Matplotlib的直方图函数)应用到每个子图上。 'Age'表示要绘制直方图的数据列。 bins=20表示将年龄数据分成20个区间。
数值和序数特征的相关性分析
结合多个特征,通过一个单一的图表来识别相关性。这可以通过具有数值值的数值和分类特征来完成。
观察结果
-
Pclass=3 的乘客最多,但大多数没有生还。这证实了我们的分类假设#2。
-
Pclass=2 和 Pclass=3 中的婴儿乘客大多生还。进一步验证了我们的分类假设#2。
-
大多数 Pclass=1 的乘客生还。这证实了我们的分类假设#3。
-
不同 Pclass 之间乘客的年龄分布不同。
决策
-
将 Pclass 纳入模型训练考虑范围。
代码10—— Age
列在不同Survived
和Pclass
条件下的分布
# grid = sns.FacetGrid(train_df, col='Pclass', hue='Survived') grid = sns.FacetGrid(train_df, col='Survived', row='Pclass', size=2.2, aspect=1.6) grid.map(plt.hist, 'Age', alpha=.5, bins=20) grid.add_legend(); 1.创建FacetGrid对象: grid = sns.FacetGrid(train_df, col='Survived', row='Pclass', size=2.2, aspect=1.6) train_df:数据集。 col='Survived':每个列(垂直方向的子图)对应一个Survived的取值。 row='Pclass':每个行(水平方向的子图)对应一个Pclass的取值。 size=2.2:每个子图的高度。 aspect=1.6:每个子图的宽高比(宽度/高度)。 2.绘制直方图: grid.map(plt.hist, 'Age', alpha=.5, bins=20) plt.hist:使用Matplotlib的直方图函数绘图。 'Age':绘制直方图的数据列。 alpha=.5:设置条形的透明度为0.5。 bins=20:将数据分成20个区间。 3.添加图例: grid.add_legend(); 为图表添加图例,帮助解释不同颜色或样式的含义。 效果 这段代码将生成多个子图,每个子图展示在特定Pclass(客舱等级)和Survived(生存情况)组合下的Age(年龄)分布情况。 每个子图对应一个特定的Pclass和Survived组合,比如Pclass=1且Survived=0,Pclass=1且Survived=1,依此类推。
分类特征的相关性
将分类特征与解决目标相关联
观察结果
-
女性乘客的生还率远高于男性。这证实了分类假设#1。
-
Embarked=C 的男性生还率较高,这是一个例外。这可能是 Pclass 与 Embarked 之间的相关性,以及 Pclass 与 Survived 之间的相关性,而不一定是 Embarked 与 Survived 之间的直接相关性。
-
在 Pclass=3 中,C 和 Q 港口的男性生还率比 Pclass=2 中的男性更高。补充假设#2。
-
登船港口对于 Pclass=3 和男性乘客的生还率有不同的影响。相关假设#1。
决策
-
将 Sex 特征加入模型训练。
-
补充并将 Embarked 特征加入模型训练。
代码11—— 不同Embarked
条件下的乘客生存情况
# grid = sns.FacetGrid(train_df, col='Pclass', hue='Survived') grid = sns.FacetGrid(train_df, col='Survived', row='Pclass', size=2.2, aspect=1.6) grid.map(plt.hist, 'Age', alpha=.5, bins=20) grid.add_legend(); 1.创建FacetGrid对象: grid = sns.FacetGrid(train_df, row='Embarked', height=2.2, aspect=1.6) train_df:数据集。 row='Embarked':按照Embarked列的不同取值(登船港口)分成多个行(水平方向的子图),每个行对应一个不同的登船港口。 height=2.2:每个子图的高度。 aspect=1.6:每个子图的宽高比(宽度/高度)。 2.绘制点图(Point Plot): grid.map(sns.pointplot, 'Pclass', 'Survived', 'Sex', palette='deep') sns.pointplot:Seaborn的点图函数,用于显示不同类别之间的关系。 'Pclass':X轴上的变量,表示客舱等级。 'Survived':Y轴上的变量,表示生存率。 'Sex':不同性别之间的比较。 palette='deep':调色板,用于设置点的颜色。 3.添加图例: grid.add_legend() 为图表添加图例,解释不同颜色或样式的含义。 效果 这段代码将生成多个子图,每个子图展示在特定Embarked(登船港口)条件下,不同客舱等级(Pclass)和性别(Sex)对生存率(Survived)的影响。 点图(Point Plot)通过在每个点上绘制平均值的线条来展示变量之间的关系,例如不同客舱等级和性别的生存率。
关联分类和数据特征
也可以考虑关联具有非数值值的分类特征和数值特征。我们可以考虑关联Embarked(分类非数值)、Sex(分类非数值)、Fare(数值连续)与Survived(分类数值)。
观察
-
支付更高票价的乘客生存率更高。 确认了我们对创建(#4)票价范围的假设。
-
登船港口与生存率相关联。 确认了我们的关联(#1)和完成(#2)假设。
决策
-
考虑对Fare特征进行分段。
代码12——不同条件下的乘客票价(Fare)
grid = sns.FacetGrid(train_df, row='Embarked', col='Survived', size=2.2, aspect=1.6) grid.map(sns.barplot, 'Sex', 'Fare', alpha=.5, ci=None) grid.add_legend() 解释 1.创建FacetGrid对象: grid = sns.FacetGrid(train_df, row='Embarked', col='Survived', size=2.2, aspect=1.6) train_df:数据集。 row='Embarked':按照Embarked列的不同取值(登船港口)分成多个行(水平方向的子图),每个行对应一个不同的登船港口。 col='Survived':按照Survived列的不同取值(生存情况)分成多个列(垂直方向的子图),每个列对应一个不同的生存情况。 size=2.2:每个子图的高度。 aspect=1.6:每个子图的宽高比(宽度/高度)。 2.绘制条形图(Bar Plot) grid.map(sns.barplot, 'Sex', 'Fare', alpha=.5, ci=None) sns.barplot:Seaborn的条形图函数,用于显示变量之间的关系。 'Sex':X轴上的变量,表示性别。 'Fare':Y轴上的变量,表示票价。 alpha=.5:设置条形的透明度为0.5。 ci=None:不显示误差棒(confidence interval)。 3.添加图例: grid.add_legend() 为图表添加图例,解释不同颜色或样式的含义。 效果 这段代码将生成一个多维度的图表,展示了在不同登船港口和生存情况条件下,性别对票价的影响。 每个子图显示了不同性别在特定条件下的平均票价。
4.数据处理
4.1 数据整理
上面 已经就数据集和解决方案要求收集了几个假设和决策,现在执行上面的决策和假设,以实现纠正、创建和完成的目标
删除特征
优点:加快了速度并简化了分析过程。
根据我们的假设和决策,我们希望删除Cabin(纠正#2)和Ticket(纠正#1)特征。
请注意,对训练和测试数据集一起执行操作,以保持一致性。
代码13——删除特征
print("Before", train_df.shape, #显示数据集形状 test_df.shape, combine[0].shape, combine[1].shape) #axis=1表示按列删除 train_df = train_df.drop(['Ticket', 'Cabin'], axis=1) test_df = test_df.drop(['Ticket', 'Cabin'], axis=1) combine = [train_df, test_df] "After", train_df.shape, test_df.shape, combine[0].shape, combine[1].shape ——这段不会输出,用于表示删除后形状的变化 输出: Before (891, 12) (418, 11) (891, 12) (418, 11) ('After', (891, 10), (418, 9), (891, 10), (418, 9))
创建新特征(从现有特征中提取)
分析下Name是否可以提取称号(title),测试称号和survival的相关性,然后删除Name和PassengerId
观察
绘制Title、Age和Survived时,注意到以下观察结果。
-
大多数称号正确地分组年龄段。例如:Master称号(小孩)的年龄平均值为5岁。
-
不同称号的生存率略有不同。
-
某些称号的乘客大多生还(Mme、Lady、Sir),而另一些则没有(Don、Rev、Jonkheer)。
决策
保留新的Title特征用于模型训练。
代码14——提取名字中的称号
使用正则表达式提取Title特征。正则表达式模式(\w+\.)匹配Name特征中以点字符结尾的第一个单词。expand=False标志返回一个DataFrame for dataset in combine: dataset['Title'] = dataset.Name.str.extract(' ([A-Za-z]+)\.', expand=False) #.str.extract(' ([A-Za-z]+)\.', expand=False):这是一个正则表达式,用于从 Name 列中提取称呼。 #' ([A-Za-z]+)\.':这个正则表达式匹配名字中的称呼部分,具体来说,它寻找一个空格后面跟着一串字母(A-Z 或 a-z),并以一个点(.)结尾的部分。 ():表示一个捕获组。 [A-Za-z]+:匹配一个或多个字母。 \.:匹配一个点(.),注意在正则表达式中点需要转义。 expand=False:使 extract 返回一个 Series 而不是 DataFrame。 pd.crosstab(train_df['Title'], train_df['Sex']) pd.crosstab:Pandas 提供的一个函数,用于计算交叉表(cross-tabulation),它显示频率分布。 train_df['Title']:称呼(Title)列。 train_df['Sex']:性别(Sex)列。 这个交叉表计算并显示每个称呼与性别的频率分布,即每个称呼有多少男性和女性。
将许多称号替换为更常见的名称,或分类为“Rare”。
代码15——替换原表中的称呼
replace,groupby
列表.replace(a,b)---在列表中用b代替a,前者可以是列表 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('Mlle', '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() 计算不同称呼的平均生存率 选择数据列:train_df[['Title', 'Survived']]选取训练数据集中的Title(称呼)和Survived(生存情况)列。 分组计算平均值:.groupby(['Title'], as_index=False).mean()根据Title进行分组,然后计算每组的平均生存率。as_index=False表示结果保持为DataFrame形式,Title作为普通列而非索引。
将分类的称谓转换为有序数值
代码16——将称号转换为有序数值
fillna
#1.title_mapping 是一个字典,用于将文本称呼映射为对应的数值。 title_mapping = {"Mr": 1, "Miss": 2, "Mrs": 3, "Master": 4, "Rare": 5} #2.遍历数据集:combine 包含 train_df 和 test_df,所以这个循环对两个数据集进行相同的处理。 应用映射:dataset['Title'] = dataset['Title'].map(title_mapping) 将 Title 列中的每个文本称呼替换为对应的数值。如果某个称呼没有在字典中找到,结果会是 NaN(缺失值)。 填补缺失值:dataset['Title'] = dataset['Title'].fillna(0) 将任何缺失值填补为 0。 for dataset in combine: dataset['Title'] = dataset['Title'].map(title_mapping) dataset['Title'] = dataset['Title'].fillna(0) #3.train_df.head() 返回训练数据集的前五行,允许你查看 Title 列经过处理后的结果。 train_df.head()
从训练和测试数据集中删除Name特征以及PassengerId特征
代码17——删除Name和passengerId
train_df = train_df.drop(['Name', 'PassengerId'], axis=1) test_df = test_df.drop(['Name'], axis=1) #axis=1表示按列删除(等于0是按行,axis指示pandas的操作方向) combine = [train_df, test_df] #更新合并后的数据集 train_df.shape, test_df.shape #查看形状
转换分类特征
将包含字符串的特征转换为数值。大多数模型算法都需要这样做。这样做还有助于实现完成特征的目标。(有适应了模型的需求,提高模型性能,进行有效的特征工程,减少噪音,便于计算和分析的好处 )
首先将Sex特征转换为一个名为Gender的新特征,其中female=1,male=0。
代码18——sex变gender的0和1
for dataset in combine: dataset['Sex'] = dataset['Sex'].map( {'female': 1, 'male': 0} ).astype(int) train_df.head()
完成数值连续特征的填充
现在开始估算并填充具有缺失或空值的特征。首先对Age(年龄)特征进行处理。
考虑三种方法来填充数值连续特征。
1.一种简单的方法是生成在平均值和标准差之间的随机数。
2.更准确的方法是使用其他相关特征来猜测缺失值。在我们的例子中,我们注意到Age(年龄)、Gender(性别)和Pclass(舱位等级)之间的相关性。我们可以通过Pclass和Gender特征组合的中位数值来猜测Age值。例如,Pclass=1且Gender=0的中位年龄,Pclass=1且Gender=1的中位年龄,等等。
3.结合方法1和2。也就是说,不是基于中位数猜测年龄值,而是使用在平均值和标准差之间的随机数,基于Pclass和Gender的组合。
方法1和3会在我们的模型中引入随机噪声。多次执行的结果可能会有所不同。我们更倾向于方法2。
代码19——中位数补齐缺失数值
sns.FacetGrid,map,plt.hist,add_legend()
# grid = sns.FacetGrid(train_df, col='Pclass', hue='Gender') 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()
先准备一个空数组,用于存储基于Pclass和Gender组合的猜测Age值。
代码20——空数组存储 基于Pclass和Gender组合的猜测Age值
np.zeros
guess_ages = np.zeros((2,3)) guess_ages
迭代Sex(0或1)和Pclass(1, 2, 3),计算六种组合的Age猜测值。
代码21——迭代sex和pclass,计算6中六种组合的Age猜测值
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_mean = guess_df.mean() # age_std = guess_df.std() # age_guess = rnd.uniform(age_mean - age_std, age_mean + age_std) age_guess = guess_df.median() # Convert random age float to nearest .5 age 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()
代码22—— 创建年龄段并确定与存活的相关性
pd.cut
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)
代码23—— 年龄段的序数替换年龄
dataset.loc
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'] train_df.head()
代码24—— 删除AgeBand特征
train_df = train_df.drop(['AgeBand'], axis=1) combine = [train_df, test_df] train_df.head()
创建新特征,结合现有特征
创建一个结合Parch和SibSp的新特征FamilySize。这将使我们能够从数据集中删除Parch和SibSp。
代码25——创建结合Parch和SibSp的新特征,FamilySize
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)
代码26——创建另一个称为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()
代码27—— 删除Parch、SibSp和FamilySize特征,而使用IsAlone
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()
代码28—— 创建一个结合Pclass和Age的人工特征
for dataset in combine: dataset['Age*Class'] = dataset.Age * dataset.Pclass train_df.loc[:, ['Age*Class', 'Age', 'Pclass']].head(10)
完成分类特征
Embarked 特征根据登船港口取值为 S
、Q
、C
。在我们的训练数据集中,有两个缺失值。我们将其简单地填充为最常见的值。
代码29—— 填充Embarked 特征
freq_port = train_df.Embarked.dropna().mode()[0] freq_port
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)
分类特征转换为数值
创建一个新的数值特征 Port
来转换 EmbarkedFill
特征
代码30——转换 EmbarkedFill
特征为port
for dataset in combine: dataset['Embarked'] = dataset['Embarked'].map( {'S': 0, 'C': 1, 'Q': 2} ).astype(int) train_df.head()
快速完成和转换数值特征
我们现在可以使用众数来完成测试数据集中单个缺失值的 Fare
特征。这可以通过一行代码来完成。
注意,我们没有创建一个中间的新特征,也没有进行任何进一步的相关分析来猜测缺失特征,因为我们只是在替换一个值。完成目标是满足模型算法对非空值的操作要求。
我们可能还想将票价四舍五入到两位小数,因为它表示货币。
代码31——众数表示缺失的Fare特征
test_df['Fare'].fillna(test_df['Fare'].dropna().median(), inplace=True) test_df.head()
代码32—— 创建 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)
代码33—— 将票价特征转换为基于 FareBand
的序数值
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)
代码34——测试数据集
test_df.head(10)
5.模型、预测和解决问题
现在我们准备训练模型并预测所需的解决方案。有超过60种预测建模算法可供选择。我们必须了解问题的类型和解决需求,以缩小到少数几种可以评估的模型。我们的问题是分类和回归问题。我们希望识别输出(是否存活)与其他变量或特征(性别、年龄、港口等)之间的关系。我们还在进行一种称为监督学习的机器学习,因为我们正在使用给定的数据集来训练模型。基于这两个标准——监督学习加上分类和回归,我们可以将模型的选择缩小到几个。这些包括:
-
逻辑回归
-
K近邻(KNN)
-
支持向量机(SVM)
-
朴素贝叶斯分类器
-
决策树
-
随机森林
-
感知器
-
人工神经网络
-
相关向量机(RVM)
代码35—— 准备训练和测试数据集,并进一步进行机器学习模型的训练和预测
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))
逻辑回归是一个在工作流程早期运行的有用模型。逻辑回归通过估计概率,使用逻辑函数(即累积逻辑分布)来测量分类因变量(特征)与一个或多个自变量(特征)之间的关系。【参考维基百科】。
请注意模型基于我们的训练数据集生成的置信度评分。
代码36——逻辑回归
# Logistic Regression 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 #结果:80.36
我们可以使用逻辑回归来验证我们的假设和特征创建及完成目标的决策。这可以通过计算决策函数中特征的系数来完成。
正系数增加响应的对数几率(从而增加概率),负系数降低响应的对数几率(从而降低概率)。
-
性别是最高的正系数,这意味着随着性别值的增加(男性:0到女性:1),Survived=1的概率增加最多。
-
反之,随着Pclass增加,Survived=1的概率减少最多。
-
因此,Age*Class是一个很好的人工特征,因为它与Survived有第二高的负相关性。
-
同样,Title有第二高的正相关性。
代码37—— 使用逻辑回归模型计算并展示各特征与目标变量之间的相关性
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.201527 |
5 | Title | 0.398234 |
2 | Age | 0.287163 |
4 | Embarked | 0.261762 |
6 | IsAlone | 0.129140 |
3 | Fare | -0.085150 |
7 | Age*Class | -0.311200 |
0 | Pclass | -0.749007 |
接下来我们使用支持向量机(SVM)建模,支持向量机是具有相关学习算法的监督学习模型,用于分类和回归分析。给定一组训练样本,每个样本标记为属于两个类别之一,SVM训练算法构建一个模型,将新测试样本分配给一个类别或另一个类别,使其成为一个非概率的二元线性分类器。【参考维基百科】。
注意模型生成的置信度评分高于逻辑回归模型。
代码38——支持向量机
# Support Vector Machines 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 #结果:83.84
在模式识别中,k-近邻算法(简称k-NN)是一种用于分类和回归的非参数方法。通过对样本的邻居进行多数投票来对其进行分类,样本被分配到其k个最近邻居中最常见的类别(k是一个正整数,通常较小)。如果k=1,那么对象就被分配给这个单一最近邻居的类别。参考维基百科。
KNN的置信度评分比逻辑回归更好,但比SVM更差
代码39——KNN
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 #结果:84.74
在机器学习中,朴素贝叶斯分类器是一类基于贝叶斯定理并具有强(朴素)独立假设的简单概率分类器。朴素贝叶斯分类器具有高度可扩展性,在学习问题中所需的参数数量与变量(特征)的数量成线性关系。参考维基百科。
该模型生成的置信度评分在目前评估的模型中最低。
代码40——高斯朴素贝叶斯
# 高斯朴素贝叶斯 gaussian = GaussianNB() gaussian.fit(X_train, Y_train) Y_pred = gaussian.predict(X_test) acc_gaussian = round(gaussian.score(X_train, Y_train) * 100, 2) acc_gaussian #结果:72.28
感知器是一种用于监督学习的二元分类器算法(即可以决定一个输入(用数字向量表示)是否属于某个特定类别的函数)。它是一种线性分类器,即基于线性预测函数结合一组权重与特征向量进行预测的分类算法。该算法允许在线学习,即一次处理训练集中的一个元素。参考维基百科。
# 感知器 perceptron = Perceptron() perceptron.fit(X_train, Y_train) Y_pred = perceptron.predict(X_test) acc_perceptron = round(perceptron.score(X_train, Y_train) * 100, 2) acc_perceptron #结果:78.0
# 线性SVC linear_svc = LinearSVC() linear_svc.fit(X_train, Y_train) Y_pred = linear_svc.predict(X_test) acc_linear_svc = round(linear_svc.score(X_train, Y_train) * 100, 2) acc_linear_svc #结果:79.12
# 随机梯度下降 sgd = SGDClassifier() sgd.fit(X_train, Y_train) Y_pred = sgd.predict(X_test) acc_sgd = round(sgd.score(X_train, Y_train) * 100, 2) acc_sgd #结果:78.56
该模型使用决策树作为预测模型,将特征(树枝)映射到关于目标值的结论(树叶)。目标变量可以取有限值的树模型称为分类树;在这些树结构中,叶子代表类标签,分支代表导致这些类标签的特征结合。当目标变量可以取连续值(通常为实数)时,称为回归树。参考维基百科。
该模型的置信度评分在目前评估的模型中最高。
代码41——决策树(置信度最高)
# 决策树 decision_tree = DecisionTreeClassifier() decision_tree.fit(X_train, Y_train) Y_pred = decision_tree.predict(X_test) acc_decision_tree = round(decision_tree.score(X_train, Y_train) * 100, 2) acc_decision_tree #结果:86.76
下一个模型随机森林是最受欢迎的模型之一。随机森林或随机决策森林是一种集成学习方法,用于分类、回归和其他任务,它通过在训练时构建大量决策树(n_estimators=100)并输出类的众数(分类)或个别树的平均预测(回归)。参考维基百科。
该模型的置信度评分在目前评估的模型中最高。我们决定使用该模型的输出(Y_pred)来创建竞赛提交结果。
代码42——随机森林
# 随机森林 random_forest = RandomForestClassifier(n_estimators=100) random_forest.fit(X_train, Y_train) Y_pred = random_forest.predict(X_test) random_forest.score(X_train, Y_train) acc_random_forest = round(random_forest.score(X_train, Y_train) * 100, 2) acc_random_forest #结果:86.76
模型评估
模型评估 我们现在可以对所有模型的评估进行排序,以选择最适合我们问题的模型。虽然决策树和随机森林的得分相同,但我们选择使用随机森林,因为它们可以纠正决策树对训练集过拟合的习惯。
代码43——根据准确性给模型评分
models = pd.DataFrame({ 'Model': ['Support Vector Machines', 'KNN', 'Logistic Regression', 'Random Forest', 'Naive Bayes', 'Perceptron', 'Stochastic Gradient Decent', 'Linear SVC', 'Decision Tree'], 'Score': [acc_svc, acc_knn, acc_log, acc_random_forest, acc_gaussian, acc_perceptron, acc_sgd, acc_linear_svc, acc_decision_tree]}) models.sort_values(by='Score', ascending=False)
Model | Score | |
---|---|---|
3 | Random Forest | 86.76 |
8 | Decision Tree | 86.76 |
1 | KNN | 84.74 |
0 | Support Vector Machines | 83.84 |
2 | Logistic Regression | 80.36 |
7 | Linear SVC | 79.12 |
6 | Stochastic Gradient Decent | 78.56 |
5 | Perceptron | 78.00 |
4 | Naive Bayes | 72.28 |
代码44—— 创建提交预测结果的数据框,并保存为CSV文件
submission = pd.DataFrame({ "PassengerId": test_df["PassengerId"], "Survived": Y_pred }) # submission.to_csv('../output/submission.csv', index=False)
向Kaggle竞赛网站提交的结果在6082个竞赛条目中得分为3883。这一结果表明,在竞赛进行中,该结果只考虑了部分提交数据集。对于我们的第一次尝试来说,这还不错。任何提高我们得分的建议都是非常欢迎的。
第三方库太多了,就到具体流程再记了
获取数据——read_csv,combine
数据分析——columns.values,head(),tail(), info() , describe() ,describe(include=['O']),
train_df[['某字段名', '某字段名']].groupby(['某字段名'], as_index=False).mean().sort_values(by='Survived', ascending=False)
g = sns.FacetGrid(train_df, col='Survived')
g.map(plt.hist, 'Age', bins=20)
grid = sns.FacetGrid(train_df, col='Survived', row='Pclass', size=2.2, aspect=1.6) grid.map(plt.hist, 'Age', alpha=.5, bins=20) grid.add_legend();
# grid = sns.FacetGrid(train_df, col='Embarked', hue='Survived', palette={0: 'k', 1: 'w'}) grid = sns.FacetGrid(train_df, row='Embarked', col='Survived', size=2.2, aspect=1.6) grid.map(sns.barplot, 'Sex', 'Fare', alpha=.5, ci=None) grid.add_legend()
数据处理——shape,drop,
.str.extract (' ([A-Za-z]+).', expand=False) ,
crosstab ,replace,groupby,fillna,sns.FacetGrid,map,plt.hist,add_legend()
, np.zeros,pd.cut,dataset.loc
【Hadoop】四、Hadoop生态综合案例 ——陌陌聊天数据分析_基于hadoop和hive的在线社交网络情感分析:使用hadoop和hive分析社交网络数据,以了-CSDN博客
-
正确解读业务需求,避免歧义
-
确定待查询的数据表–>from 表
-
找出分析的维度–>group by 分组的字段
-
找出计算的指标–>聚合的字段
-
其他细节点(过滤、排序等)