开始Kaggle练习,最先进行的当然是Kaggle的“Hello World”---“Titanic: Machine Learning from Disaster",即预测哪些泰坦尼克的旅客幸存。自己最开始写的很乱,包括数据处理、分析、建模等。参考了Kaggle的一篇[1]再整理一遍,清晰很多。实验并没有得到一个很好的结果,但是规范了整个流程,因此写下笔记 。
本文约6.2k字,预计阅读15分钟
竞赛解决方案的流程主要分为以下7个步骤:
-
问题的定义;
-
获取训练集和测试集;
-
整理、准备、清洗数据;
-
分析、探索数据;
-
建模、预测和解决问题;
-
可视化、报告和呈现问题解决步骤和最终解决方案;
-
提交结果;
当然这个只是一般的步骤,3、4可以进行交叉交换,可视化也可以应用到多个阶段。
泰坦尼克数据集的机器学习研究可以说是Kaggle的“Hello world”。问题的直观定义很简单:使用机器学习创建一个模型,预测哪些乘客在泰坦尼克号沉船中幸存。
其他的信息条件:
1912年4月15日,被广泛认为“永不沉没”的皇家邮轮“泰坦尼克号”在处女航中撞上一座冰山后沉没。不幸的是,船上没有足够的救生艇,导致2224名乘客和船员中有1502人死亡。(存活率为:32.46%)
虽然在生存中有一些运气因素,但似乎有些群体的人比其他人更有可能生存下来。
获取数据集
数据集的获取很简单,使用pandas包即可。
import pandas as pd
train_df = pd.read_csv('../input/titanic/train.csv')
test_df = pd.read_csv('../input/titanic/test.csv')
数据的描述(即特征)
赛题中Data部分给出了数据特征,也可以通过pandas进行查看:
train_df.columns.values
array(['PassengerId', 'Survived', 'Pclass', 'Name', 'Sex', 'Age', 'SibSp',
'Parch', 'Ticket', 'Fare', 'Cabin', 'Embarked'], dtype=object)
结合赛题描述,我们可以对上述特征进行归类:
分类特征:这里指的是可以对数据集按照该特征可以明确的划分为一系列相似的样本。上述属于分类特征的有:
数值型特征:值会随着样本的变化而变化,可以是连续的、离散的或基于时间序列的,这里有:
-
其他特征:很难找到有效的的规律,这里还剩下:
-
在对训练集的首尾数据进行查看:
train_df.head()
train_df.tail()
通过数据中的信息,可以进行得到以下结论:
Name特征中,虽然是字符串类型,但包含了一些性别特征,如(Mr、Mrs、Miss);
Ticket特征,包含了数字和字母的组合,我们很难从中找出一些规律;
我们发现,Cabin特征中存在缺失值,我们需要进一步进行判断,并查看其他特征是否也有缺失;
Passengerld特征为序号,对模型建立应该并无影响;
首先最为关键的是数据缺失问题,Pandas可以通过很多种方式进行判断每个特征是否存在缺失值。最简单的是直接查看数据集的全局信息。
train_df.info()
print('-' * 40)
test_df.info()
<class 'pandas.core.frame.DataFrame'>
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
________________________________________
<class 'pandas.core.frame.DataFrame'>
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
通过上述数据集的信息我们可以分析:
数据集中有7个为数值型,5个为object类型;
训练集共891个样本,Age特征缺失177(即19.87%),Cabin特征缺失687(即77.10%),Embarked特征缺失2(即0.22%);
测试集共418个样本,Age特征缺失86(即20.57%),Cabin特征缺失326(即67.78%),Fare特征缺失1(即0.21%);
数据的分布
可以通过Pandas包的describe方法快速查看整个数据的分布情况【这里只观察训练集】:
train_df.describe()
结果如图所示:
我们可以得到以下结论:
在训练集中,存活率为38.38%;
社会经济地位(SES)是低的人占的比例最大;
船上大多数没有和父母孩子一起(至少75%);
船上有兄弟姐妹的关系的旅客为25%~50%;
年老的乘客很少;
票价分布不均匀,差异很大,极少数人花费超过了500美元;
上述缺少了部分特征(数据类型不为数值),查看数据分布,可以添加参数include=['O']
,即包含object类型:
train_df.describe(include=['O'])
可以发现:
游客出发的港口有3个;
船舱有部分重复(147个不相同),某些游客可能共用一个船舱;
票据特征有一定的重复率(22%);
单个特征与标签的相关性
上述分析的是数据集整体的结构与分布,接下来我们将探索单个特征与是否存活的相关性,这是非常有意义的。这里我们指分析不含有缺失值的特征:Pclass、Sex、SibSp、Parch。
(1)Pclass:
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
结论:社会地位高的人存活率最高。
(2)Sex:
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
结论:女性比男性的存活率高。
(3)SibSP:
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
结论:有少数(1~3)或无兄弟姐妹或的旅客存活率较高。
(4)Parch:
rain_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
结论:与上述结论类似。
数据可视化
(1)首先我们可视化年龄与存活的关系:
import matplotlib.pyplot as plt
plt.figure(dpi=100)
plt.hist(train_df['Age'], label='All', bins=20)
plt.hist(train_df.loc[train_df.Survived == 1, 'Age'], label='Survived', bins=20)
plt.xlabel('Age')
plt.ylabel('People Number')
plt.legend()
如图所示:
结论:模型建模应该考虑年龄;0~8岁的小孩和75~80的老人存活率偏高;需要对年龄进行分段处理,并填充缺失值
(2)对上述直方图我们再加入Pclass特征:
plt.clf()
fig, axes = plt.subplots(1, 3, dpi=100)
plt.subplots_adjust(left=0, bottom=None, right=2.5, top=None, wspace=None, hspace=None)
def subplot(Pclass, index):
ax_i = axes[index]
ax_i.hist(train_df.loc[train_df.Pclass == Pclass, 'Age'], label='All', bins=20)
ax_i.hist(train_df.loc[(train_df.Survived == 1) & (train_df.Pclass == Pclass), 'Age'], label='Survived', bins=20)
ax_i.set_xlabel('age')
ax_i.set_title('Pclass=' + str(Pclass))
ax_i.set_ylabel('People Number')
for i in range(3):
subplot(i+1, i)
plt.legend()
结论:Pclass=1的旅客存活率最高,Pclass=2其次,Pclass=3最低;Pclass=2和3中年龄为0~10的旅客存活率较高;故Pclass是一个重要的特征,建模需要加入
(3)可视化出发地、性别、社会地位(Pclass)与存活率的关系:
import seaborn as sns
grid = sns.FacetGrid(train_df, row='Embarked', height=2.2, aspect=1.6)
grid.map(sns.pointplot, 'Pclass', 'Survived', 'Sex', palette='deep')
grid.add_legend()
如图【用了seaborn】:
结论:在三个出发港口中,港口C男性各个阶级的存活率远高于其他两个,且比女性高;对于社会地位高的男性在不同的港口出发,存活率也各不相同;故性别(Sex)与出发地(Embarked)都是重要的特征,建模需要加入
(4)可视化票价与存活率的关系:
plt.figure(dpi=100)
plt.hist(train_df['Fare'], label='All', bins=50)
plt.hist(train_df.loc[train_df.Survived == 1, 'Fare'], label='Survived', bins=50)
plt.xlabel('Fare')
plt.ylabel('People Number')
plt.legend()
结论:票价高的旅客存活率更高;由于票价分布差异较大,因此可以对该特征进行分段处理;故应将Fare加入进行建模
经过上述对11个特征(除去Survived作为标签)进行数据分析,结论如下:
PassengerId为ID,Ticket特征很难找到规律,Cabin缺失太多,因此都需要进行删除;
Name特征可以提取部分性别、已婚未婚信息、身份等【Name特征本身需要删除】;
Sex、Pclass、Age、Embarked、Fare是非常重要的特征,且特征之间存在着一定的关系;
SibSp、Parch特征关于存活率的分布类似,且两者相加能反应一个家族的人员情况。可以尝试相加;
Age、Embarked、Fare存在着缺失数据,需要对其进行填充;
Sex、Emabrked需要转化为分类的数值型特征;
Age、Fare根据之前的分析进行合理的分段;
清洗、整理数据
删除无效特征
经上述分析,删除Passengerld【可进行保存】、Ticket、Cabin特征:
data_id = []
train_df = train_df.drop(['Ticket', 'Cabin'], axis=1)
test_df = test_df.drop(['Ticket', 'Cabin'], axis=1)
data_id.append(train_df.pop('PassengerId'))
data_id.append(test_df.pop('PassengerId'))
train_df.shape, test_df.shape
# ((891, 9), (418, 8))
提取有效的特征
关于Name特征,一般称呼上"."前面表示一种身份,例如“Miss”、“Dr“等,可以将其用正则表达式进行提取:
train_df['Title'] = train_df.Name.str.extract('([A-Za-z]+)\.', expand=False)
test_df['Title'] = test_df.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
我们发现某些类别特别少,所占比例不均匀,且“Mlle”、“Ms”都是“Miss”,“Mme”应该为“Mrs”,可以对其进行替换,对于数量少的可以进行整合为一个类别“Rare”。
combine = [train_df, test_df]
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()
Title Survived
0 Master 0.575000
1 Miss 0.702703
2 Mr 0.156673
3 Mrs 0.793651
4 Rare 0.347826
再对所有的类别进行映射:
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)
删除Name特征:
train_df = train_df.drop('Name', axis=1)
test_df = test_df.drop('Name', axis=1)
combine = [train_df, test_df]
由于性别是字符串表示,我们可以将其用数值型代表:
for dataset in combine:
dataset['Sex'] = dataset['Sex'].map( {'female': 1, 'male': 0} ).astype(int)
缺失值填充
1、Age
最简单的填充方式就是取所有旅客的均值和标准差之间进行随机选择。但是,之前我们分析,Age和Pclass、Gender存在一定的关联。因此,我们可以选择取Pclass和Gender匹配下的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 = np.random.uniform(age_mean - age_std, age_mean + age_std)
dataset.loc[ (dataset.Age.isnull()) & (dataset.Sex == i) & (dataset.Pclass == j+1),\
'Age'] = age_guess
dataset['Age'] = dataset['Age'].astype(int)
由于Age为连续性数值,根据分析,我们可以将其进行分段【10段加以区分】:
train_df['AgeBand'] = pd.cut(train_df['Age'], 10)
train_df[['AgeBand', 'Survived']].groupby(['AgeBand'], as_index=False).mean().sort_values(by='AgeBand', ascending=True)
AgeBand Survived
0 (-0.08, 8.0] 0.666667
1 (8.0, 16.0] 0.413043
2 (16.0, 24.0] 0.264706
3 (24.0, 32.0] 0.429245
4 (32.0, 40.0] 0.463768
5 (40.0, 48.0] 0.325843
6 (48.0, 56.0] 0.466667
7 (56.0, 64.0] 0.375000
8 (64.0, 72.0] 0.000000
9 (72.0, 80.0] 0.500000
将其转化为分类数值型:
train_df['Age'] = pd.cut(train_df['Age'], bins=10, labels=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
test_df['Age'] = pd.cut(test_df['Age'], bins=10, labels=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
train_df['Age'] = train_df['Age'].astype('int64')
test_df['Age'] = test_df['Age'].astype('int64')
combine = [train_df, test_df]
2、Embarked
由于训练集中只有两个缺失值,因此我们采用最简单的最常用填充:
for dataset in combine:
dataset['Embarked'] = dataset['Embarked'].fillna(dataset.Embarked.dropna().mode()[0])
然后再将其转化为分类数值型特征:
for dataset in combine:
dataset['Embarked'] = dataset['Embarked'].map( {'S': 0, 'C': 1, 'Q': 2} ).astype(int)
3、Fare
测试集中有一个样本缺失Fare特征,我们简单的填充为中位数:
test_df['Fare'].fillna(test_df['Fare'].dropna().median(), inplace=True)
将不同的Fare进行分段处理,和Age处理方式不同的是,由于票价差距过大,我们不能采用等分,且票价基本和Pclass对应,因此这里使用pd.qcut
划分为3份:
train_df['Fare'] = pd.qcut(train_df['Fare'], 3, labels=[0, 1, 2])
test_df['Fare'] = pd.qcut(test_df['Fare'], 3, labels=[0, 1, 2])
train_df['Fare'] = train_df['Fare'].astype('int64')
test_df['Fare'] = test_df['Fare'].astype('int64')
combine = [train_df, test_df]
特征组合(特征工程)
1、将SibSp与Parch组合,得到Family特征
for dataset in combine:
dataset['FamilySize'] = dataset['SibSp'] + dataset['Parch'] + 1
模型完成的是分类问题,因此有很多个机器学习模型可供选择:
Logistic Regression;
KNN;
Naive Bayes Classifier;
Decision Tree;
Support Vector Machine;
MLP;
首先对数据进行处理:
X_train = np.array(train_df.drop("Survived", axis=1))
Y_train = np.array(train_df["Survived"])
X_test = np.array(test_df)
X_train.shape, Y_train.shape, X_test.shape
导入模型包:
from sklearn.model_selection import KFold
from sklearn.tree import DecisionTreeClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.naive_bayes import GaussianNB
from sklearn.neighbors import KNeighborsClassifier
from sklearn.svm import SVC
from sklearn.neural_network import MLPClassifier
模型训练,采用五折交叉验证:
def train(clf):
kf = KFold(n_splits=5)
score = list()
for train_index, test_index in kf.split(range(len(X_train))):
train_X, test_X = X_train[train_index], X_train[test_index]
train_y, test_y = Y_train[train_index], Y_train[test_index]
clf.fit(train_X, train_y)
score.append(clf.score(test_X, test_y))
avg_score = np.mean(score))
print(avg_score)
return avg_score
1、Logistic 回归
clf = LogisticRegression()
lr = train(clf)
0.8047078023978406
我们可以查看模型中各个特征的权重,权重的绝对值越大,说明对模型的影响也越大:
def correlation(clf):
coeff_df = pd.DataFrame(train_df.columns.delete(0), columns=['Feature'])
coeff_df["Correlation"] = pd.Series(clf.coef_[0])
print(coeff_df.sort_values(by='Correlation', ascending=False))
correlation(clf)
Feature Correlation
1 Sex 2.119560
7 Title 0.486584
5 Fare 0.318108
6 Embarked 0.118401
4 Parch -0.027359
3 SibSp -0.202700
8 FamilySize -0.228518
2 Age -0.291479
0 Pclass -0.958525
我们发现Sex与Pclass特征的影响最大,我们通过特征工程构造的FamilySize也比原来的特征作用更大;【这里我们可以调整特征,例如删除一些影响小的特征,如Parch等;
2、决策树(CART)
clf = DecisionTreeClassifier()
cart = train(clf)
0.8249199673592367
3、KNN
clf = KNeighborsClassifier(n_neighbors=3)
knn = train(clf)
0.8114368212918208
4、朴素贝叶斯
clf = GaussianNB()
nb = train(clf)
0.7834348126294646
5、SVM
clf = SVC(kernel='rbf')
svm = train(clf)
0.8271420500910175
6、MLP
clf = MLPClassifier(max_iter=1000, learning_rate='adaptive')
mlp = train(clf)
0.812591802146758
models = pd.DataFrame({
'Model': ['Logistic Regression', 'Decision Tree', 'KNN',
'Naive Bayes', 'Support Vector Machines', 'MLP',
'Score': [lr, cart, knn, nb, svm, mlp]})
models.sort_values(by='Score', ascending=False)
Model Score
4 Support Vector Machines 0.827142
1 Decision Tree 0.824920
5 MLP 0.812592
2 KNN 0.811437
0 Logistic Regression 0.806955
3 Naive Bayes 0.783435
我们使用SVM模型进行预测(这里简单考虑,不做模型融合,其他的特征工程暂不考虑)
clf = SVC(kernel='rbf')
svm = train(clf)
pred = clf.predict(X_test)
pred = np.c_[data_id[1], pred]
pred_df = pd.DataFrame(pred, columns=['PassengerId', 'Survived'])
pred_df.to_csv('/kaggle/working/Submission.csv', index=False)
最后预测的结果为:0.78947(5116名/结果并不好,还需继续进行调整)
[1] https://www.kaggle.com/startupsci/titanic-data-science-solutions
往期精彩回顾
通过比赛整理出的8条Numpy实用技巧【你知道如何频数统计和按某列进行排序么?】
Pandas笔记---深入Groupby,它的功能没有你想的这么简单
Pandas笔记---通过比赛整理出的10条Pandas实用技巧
机器学习笔记---从极大似然估计的角度看待Logistic回归
机器学习笔记---正则化为什么可以抑制过拟合?
机器学习笔记---给“过拟合”下一个准确且规范的定义
扫码关注更多精彩
前言开始Kaggle练习,最先进行的当然是Kaggle的“Hello World”---“Titanic: Machine Learning from Disaster",即预测...
机器学习系列(14)——Kaggle项目之Titanic
文章目录机器学习系列(14)——Kaggle项目之Titanic0x01、项目介绍0x02、学习过程简述0x03、数据探索与分析1、数据探索2、分析过程0x03、预处理0x04、第一个模型0x05、模型优化0x05、模型融合参考文献
0x01、项目介绍
学习了各种机器学习算法之后,可以找一个简单项目来练练手,感受一下完整的ML过程。Titanic是Kaggle的入门项目,网上可以找到很多资料,所以选择它作为第一个练手的项目。(记录一下哈哈哈,截止到2
kaggle链接:https://www.kaggle.com/c/titanic
泰坦尼克号案例可以说是kaggle的“hello world”,入门者的必看案例。
1.1 比赛描述
RMS泰坦尼克号沉没是历史上最臭名昭着的沉船之一。1912年4月15日,在她的处女航中,泰坦尼克号在与冰山相撞后沉没,在2224名乘客和机组人员中造成1502人死亡。这场耸人听闻的悲剧震惊了国际社会,并为...
JavaWeb-Servlet技术的监听器-解析与实例-网站在线用户信息与网页点击量
-----------------------------------
JavaWeb-Servlet技术的监听器-解析与实例-网站在线用户信息与网页点击量
-----------------------------------
JavaWeb-Servlet技术的监听器-解析与实例-网站在线用户信息与网页点击量
-----------------------------------
JavaWeb-Servlet技术的监听器-解析与实例-网站在线用户信息与网页点击量
-----------------------------------
JavaWeb-Servlet技术的监听器-解析与实例-网站在线用户信息与网页点击量
-----------------------------------
JavaWeb-Servlet技术的监听器-解析与实例-网站在线用户信息与网页点击量
-----------------------------------
JavaWeb-Servlet技术的监听器-解析与实
1.项目代码均经过功能验证ok,确保稳定可靠运行。欢迎下载体验!下载完使用问题请私信沟通。
2.主要针对各个计算机相关专业,包括计算机科学、信息安全、数据科学与大数据技术、人工智能、通信、物联网等领域的在校学生、专业教师、企业员工。
3.项目具有丰富的拓展空间,不仅可作为入门进阶,也可直接作为毕设、课程设计、大作业、初期项目立项演示等用途。
4.当然也鼓励大家基于此进行二次开发。在使用过程中,如有问题或建议,请及时沟通。
5.期待你能在项目中找到乐趣和灵感,也欢迎你的分享和反馈!
【资源说明】
作业要求:(略有修改)
考虑以下游戏场景:
每个游戏玩家都有一定数量的金币、宝物。有一个市场供玩家们买卖宝物。玩家可以将宝物放到市场上挂牌,自己确定价格。其他玩家支付足够的金币,可购买宝物。
宝物分为两类:一类为工具(tool),它决定持有玩家的工作效率;一类为配饰(ornament),它决定持有玩家的运气。
每位玩家可以通过消耗10金币寻宝获得一件宝物,宝物的价值由玩家的运气决定。
每位玩家每天可以通过劳动赚取金币,赚得多少由玩家的工作效率决定(100*工作效率)。
每个宝物都有一个自己的名
回答: 在kaggle房价预测的回归模型中,使用了Lasso回归模型进行预测。代码中首先使用了Lasso(alpha=0.0001)进行模型的训练,然后对测试集进行预测得到了lasso_predict。接着使用了np.expm1函数对预测结果进行了反向转换得到了y_lasso。这样可以使线性回归模型更符合要求。<span class="em">1</span><span class="em">2</span><span class="em">3</span>
#### 引用[.reference_title]
- *1* *2* *3* [kaggle房价预测-回归模型](https://blog.csdn.net/isla77/article/details/125900871)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 100%"]
[ .reference_list ]