泰坦尼克之灾是kaggle的一个入门案例,本文是我关于这个比赛的一些记录
1、jupyter notebook的安装
相比我之前使用的pycharm,jupyter notebook的优点是允许把代码写入独立的cell中,然后单独执行。这样做意味着我们可以在测试项目时单独测试特定代码块,无需从头开始执行代码。
安装教程参考https://blog.csdn.net/dream_an/article/details/50464940
使用教程参考https://blog.csdn.net/lee_j_r/article/details/52791228
2、泰坦尼克之灾比赛
大致流程如下,接下来我会根据这个流程解释并贴出相应的代码:
1、数据准备和了解:下载数据并了解数据的属性
2、数据清洗:即数据预处理,对缺失值进行补充或者把机器学习不能处理的数值类型转化为可以处理的int型
3、特征工程:提炼出新特征并进行特征选择来提高模型准确率
4、基准模型:跑几个基础模型。我选择了线性回归、逻辑回归、随机森林这三个,并通过交叉验证查看准确率
5、融合模型:我选择融合随机森林和逻辑回归模型
2.1数据准备和了解
首先,在kaggle上下载数据:https://www.kaggle.com/c/titanic/data
各个属性的含义如下:
PassengerId:乘客ID
Survived:是否获救
Pclass:乘客票务舱,1表示最高级
Name:乘客姓名
Sex:性别
Age:年龄
SibSp:堂兄弟妹个数
Parch:父母与小孩个数
Ticket:船票信息
Fare:票价
Cabin:客舱
Embarked:登船港口
再者,导入数据并对各个属性进行大致统计
"""查看数据"""
import pandas as pd
titanic = pd.read_csv('train.csv')
# titanic.head(3)
print(titanic.describe())
print(titanic.info())
输出结果为
PassengerId Survived Pclass Age SibSp \
count 891.000000 891.000000 891.000000 714.000000 891.000000
mean 446.000000 0.383838 2.308642 29.699118 0.523008
std 257.353842 0.486592 0.836071 14.526497 1.102743
min 1.000000 0.000000 1.000000 0.420000 0.000000
25% 223.500000 0.000000 2.000000 20.125000 0.000000
50% 446.000000 0.000000 3.000000 28.000000 0.000000
75% 668.500000 1.000000 3.000000 38.000000 1.000000
max 891.000000 1.000000 3.000000 80.000000 8.000000
Parch Fare
count 891.000000 891.000000
mean 0.381594 32.204208
std 0.806057 49.693429
min 0.000000 0.000000
25% 0.000000 7.910400
50% 0.000000 14.454200
75% 0.000000 31.000000
max 6.000000 512.329200
<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.6+ KB
None
可以初步发现,Age这一列的count只有714,说明需要进行缺失值填充;Sex、Embarked、Name等属性都是object类型,要将其转化为机器学习能处理的类型。这都是数据预处理的内容,无论哪个案例都需要数据预处理。
2.2数据清洗
数据清洗即数据预处理,包括对缺失值进行填充和把机器学习不能处理的数值类型转化为可以处理的int型。
缺失值填充一般用到fillna()函数,分两种情况:
1.如果是数值类型,用平均值或中位数取代
2.如果是分类数据,用最常见的类别取代
具体应用如下:
Age这一列有缺失值,用中位数填充(或平均值)
"""数据预处理"""
# 用中值填补缺失值
titanic['Age'] = titanic['Age'].fillna(titanic['Age'].median())
Sex这一列的值male、female不能直接处理,分别将其转化为0、1
print(titanic['Sex'].unique())
# titanic.loc[0]表示第0行的样本
# titanic.loc[0, 'PassengerId']表示行为0,列为PassengerId的值
titanic.loc[titanic['Sex'] == 'male', 'Sex'] = 0
titanic.loc[titanic['Sex'] == 'female', 'Sex'] = 1
Embarked这一列有缺失值,用最常见的类别即‘S’填充,然后再将数据转化为int型
print(titanic['Embarked'].describe())
print(titanic['Embarked'].unique())
titanic['Embarked'] = titanic['Embarked'].fillna('S')
titanic.loc[titanic['Embarked'] == 'S', 'Embarked'] = 0
titanic.loc[titanic['Embarked'] == 'C', 'Embarked'] = 1
titanic.loc[titanic['Embarked'] == 'Q', 'Embarked'] = 2
2.3特征工程
“数据决定了机器学习的上限,而算法只是尽可能逼近这个上限”,这里的数据指的就是经过特征工程得到的数据。特征工程指的是把原始数据转变为模型的训练数据的过程,它的目的就是获取更好的训练数据特征,使得机器学习模型逼近这个上限。特征工程学习参考https://www.cnblogs.com/wxquare/p/5484636.html
案例中,通过提炼新特征并进行特征选择可以提高模型准确率。
提炼的3个新特征为FamilySize:SibSp和Parch的人数相加,看看是否家庭人数越多获救几率越大;NameLength:名字长度,外国名字越长地位越高;Title:在Name里提取的,类似Mr、Mrs、Dr表示性别职业
re.search():扫描整个字符串并返回第一个成功的匹配,没有就返回none
关于正则表达式:https://www.jb51.net/article/15707.htm
# 提炼新特征
titanic['FamilySize'] = titanic['SibSp'] + titanic['Parch']
titanic['NameLength'] = titanic['Name'].apply(lambda x: len(x))
import re
import pandas as pd
def get_title(name):
title_search = re.search(' ([A-Za-z]+)\.', name)
if title_search:
return title_search.group(1)
return ''
titles = titanic['Name'].apply(get_title)
title_mapping = {"Mr": 1, "Miss": 2, "Mrs": 3, "Master": 4, "Dr": 5, "Rev": 6, "Major": 7, "Col": 8, "Mlle": 9,
"Mme": 10, "Don": 11, "Lady": 12, "Countess": 13, "Jonkheer": 14, "Sir": 15, "Capt": 16, "Ms": 17
}
for k, v in title_mapping.items():
titles[titles == k] = v
print(pd.value_counts(titles))
titanic['Title'] = titles
SelectKBest():https://blog.csdn.net/sunshunli/article/details/82051138
# 特征选择
import numpy as np
from sklearn.feature_selection import SelectKBest, f_classif
import matplotlib.pyplot as plt
predictors = ["Pclass", "Sex", "Age", "SibSp", "Parch", "Fare", "Embarked",
"FamilySize", "NameLength", "Title"]
selector = SelectKBest(f_classif, k=5)# 方差分析,计算方差分析(ANOVA)的F值 (组间均方 / 组内均方),选取前5个特征
selector.fit(titanic[predictors], titanic['Survived'])
scores = -np.log10(selector.pvalues_)
plt.bar(range(len(predictors)), scores)
plt.xticks(range(len(predictors)), predictors, rotation='vertical')
plt.show()
可以发现“Pclass”、 "Sex"、“Fare”、"NameLength"和“Title”这5个特征比较重要
2.4基准模型
线性回归是机器学习最基础的算法,逻辑回归相比线性回归,代码更加简洁、而随机森林是集成学习,也不容易过拟合,所以我选择这三个模型,并通过交叉验证将初始样本分为3份,每次2份用作训练集,剩下1份作为测试集,这样可以有3次训练,得到3次训练结果,平均之后得到最后结果。
2.4.1线性回归
"""线性回归"""
from sklearn.linear_model import LinearRegression
from sklearn.cross_validation import KFold
from sklearn import metrics
# 选择特征
predictors = ['Pclass', 'Sex', 'Age', 'SibSp', 'Parch', 'Fare', 'Embarked']
# 导入线性回归
alg = LinearRegression()
# 将样本分为3份进行交叉验证
kf = KFold(titanic.shape[0], n_folds=3, random_state=1)
predictions = []
for train_index, test_index in kf:
# 用于训练的特征数据
train_predictors = titanic[predictors].iloc[train_index, :]
# 特征数据的label(即是否获救)
train_target = titanic['Survived'].iloc[train_index] # train_target = titanic['Survived'][train_index]
# 训练线性回归模型
alg.fit(train_predictors, train_target) test_predictions = alg.predict(titanic[predictors].iloc[test_index, :])
predictions.append(test_predictions)
# 线性回归得到的结果是在[0,1],转化为类别
import numpy as np
predictions = np.concatenate(predictions, axis=0)# predictions = np.hstack(predictions)
predictions[predictions > .5] = 1
predictions[predictions <= .5] = 0
# predictions = np.where(predictions > .5, 1, 0)
# 线性模型准确率
accuracy = sum(predictions == titanic['Survived']) / len(predictions)
print(accuracy)
输出线性回归准确率为
0.783389450056
得到的准确率有点低,我们尝试下逻辑回归模型
2.4.2逻辑回归
函数:cross_val_score(model_name, X,y, cv=k)
参数:1、模型函数名,如 LogisticRegression()2、训练集 3、测试属性 4、K折交叉验证
作用:验证某个模型在某个训练集上的稳定性,输出k个预测精度。
"""逻辑回归"""
from sklearn import cross_validation
from sklearn.linear_model import LogisticRegression
alg = LogisticRegression(random_state=1)
scores = cross_validation.cross_val_score(alg, titanic[predictors], titanic['Survived'], cv=3)
print(scores)
print(scores.mean())
输出逻辑回归准确率为
[ 0.78451178 0.78787879 0.79124579]
0.787878787879
准确率提高了一点
2.4.3随机森林
随机森林的随机体现在两点:1、取样本是随机的,且是有放回的 2、特征的选择是随机的,不一定所有的属性特征都要用到。森林表示生成多个决策树
函数:RandomForestClassifier()
参数解释:random_state = 1 表示此处代码多运行几次得到的随机值都是一样的,如果不设置,两次执行的随机值是不一样的;n_estimators=50 表示有50棵决策树;树的分裂的条件是: min_samples_split =4代表样本不停的分裂,某一个节点上的样本如果只有4个了 ,就不再继续分裂了;min_samples_leaf =2表示叶子节点的最小个数为2
"""随机森林"""
from sklearn import cross_validation
from sklearn.ensemble import RandomForestClassifier
alg = RandomForestClassifier(random_state=1, n_estimators=50, min_samples_split=4, min_samples_leaf=2)
kf = cross_validation.KFold(titanic.shape[0], n_folds=3, random_state=1)
scores = cross_validation.cross_val_score(alg, titanic[predictors], titanic['Survived'], cv=kf)
print(scores.mean())
输出随机森林准确率为
0.81593714927
准确率超过了81%。后续还可以通过调整随机森林模型的参数看是否能继续提高准确率,但不是越高越好,可能会导致过拟合
2.5混合模型
混合模型是在竞赛中常用的办法:集成多个模型,得出每个模型的结果,并赋予每个模型权重,求出最后的平均结果。上面跑基准模型发现逻辑回归和随机森林效果更好,所以我集成了这两种模型。如果发现某个模型更好,权重可以更高(案例中随机森林权重是2,逻辑回归的是1)
predict_proba():https://blog.csdn.net/m0_37870649/article/details/79549142
# 混合模型
from sklearn.ensemble import GradientBoostingClassifier
import numpy as np
algorithms = [
[RandomForestClassifier(random_state=1, n_estimators=20, min_samples_split=4, min_samples_leaf=2),
['Pclass', 'Sex', 'Age', 'SibSp', 'Parch', 'Fare', 'Embarked', 'FamilySize', 'NameLength', 'Title']],
[LogisticRegression(random_state=1),
['Pclass', 'Sex', 'Age', 'SibSp', 'Parch', 'Fare', 'Embarked', 'FamilySize', 'NameLength', 'Title']]
]
kf = KFold(titanic.shape[0], n_folds=11, random_state=1)
predictions = []
for train, test in kf:
train_target = titanic['Survived'].iloc[train]
full_test_prediction = []
for alg, predictors in algorithms:
alg.fit(titanic[predictors].iloc[train, :], train_target)
test_prediction = alg.predict_proba(titanic[predictors].iloc[test, :].astype(float))[:, 1]
full_test_prediction.append(test_prediction)
test_predictions = (full_test_prediction[0] * 2 + full_test_prediction[1]) / 3
test_predictions[test_predictions > .5] = 1
test_predictions[test_predictions <= .5] = 0
predictions.append(test_predictions)
predictions = np.concatenate(predictions, axis=0)
accuracy = sum(predictions == titanic['Survived']) / len(predictions)
print(accuracy)
输出混合模型结果为
0.832772166105
总结:对于一般的简单机器学习,先进行数据探索,了解属性;再将原始数据经过预处理之后得到完整可处理的数据即数据清洗;再进行特征工程,得到重要特征;然后跑基准模型看看效果;复杂的数据可以尝试混合模型集成学习,具体情况具体分析。