@作者:炼己者
本博客所有内容以学习、研究和分享为主,如需转载,请联系本人,标明作者和出处,并且是非商业用途,谢谢!
大家也可以看PDF版,用jupyter notebook写的,视觉效果上感觉会更棒
链接:https://pan.baidu.com/s/1a5ZCUm45f5T4HTjN8t6L5Q 密码:ki39
摘要
本文主要是带你入门kaggle最基础的比赛——泰坦尼克号之灾,里面有各种可视化为你展示做的过程,并非只有一大段代码,希望能带大家真正地去入门
这是我二月份参加的kaggle大赛,当时参考了很多大佬的代码,也算是完整的把这个流程走了一遍,取得了前%2的成绩。这个比赛对我很重要,因为排名靠前了,才让自己有信心一直前行。在这里呈现给大家,之前有发到CSDN博客,后来弃号了,现在正式地放到这里来,以后还会多多参加比赛。
排名现在如果还按这个代码去跑,排名估计会下降不少了,毕竟这么久了,大家也可以在这个基础上多多改善
正文
一. 导入数据包与数据集
%matplotlib inline
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
warnings.filterwarnings('ignore')
train=pd.read_csv(r'H:\kaggle\train.csv')
test=pd.read_csv(r'H:\kaggle\test.csv')
PassengerId=test['PassengerId']
all_data = pd.concat([train, test], ignore_index = True)
二. 数据分析
1.总体预览
train.head()
output
•PassengerID(ID)
•Survived(存活与否)
•Pclass(客舱等级,较为重要)
•Name(姓名,可提取出更多信息)
•Sex(性别,较为重要)
•Age(年龄,较为重要)
•Parch(直系亲友)
•SibSp(旁系)
•Ticket(票编号)
•Fare(票价)
•Cabin(客舱编号)
•Embarked(上船的港口编号)
[input]:
train.info()
[output]:
<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
从上面的数据我们可以发现有的特征是有空值的
2.数据初步分析(使用统计学与绘图)
- 目的:初步了解数据之间的相关性,为构造特征工程以及模型建立做准备
[input]:
train['Survived'].value_counts()
[output]:
0 549
1 342
Name: Survived, dtype: int64
1)Sex Feature:女性幸存率远高于男性
sns.barplot(x="Sex", y="Survived", data=train)
SEX Feature
2)Pclass Feature:乘客社会等级越高,幸存率越高
sns.barplot(x="Pclass", y="Survived", data=train)
Pclass Feature
3)SibSp Feature:配偶及兄弟姐妹数适中的乘客幸存率更高
sns.barplot(x="SibSp", y="Survived", data=train)
SibSp Feature
4)Parch Feature:父母与子女数适中的乘客幸存率更高
sns.barplot(x="Parch", y="Survived", data=train)![5.png](https://upload-
Parch Feature
5)从不同生还情况的密度图可以看出,在年龄15岁的左侧,生还率有明显差别,密度图非交叉区域面积非常大,但在其他年龄段,则差别不是很明显,认为是随机所致,因此可以考虑将此年龄偏小的区域分离出来。
facet = sns.FacetGrid(train, hue="Survived",aspect=2)
facet.map(sns.kdeplot,'Age',shade= True)
facet.set(xlim=(0, train['Age'].max()))
facet.add_legend()
plt.xlabel('Age')
plt.ylabel('density')
密度图
6)Embarked登港港口与生存情况的分析
结果分析:C地的生存率更高,这个也应该保留为模型特征.
sns.countplot('Embarked',hue='Survived',data=train)
Embarked
7)Title Feature(New):不同称呼的乘客幸存率不同
新增Title特征,从姓名中提取乘客的称呼,归纳为六类。
all_data['Title'] = all_data['Name'].apply(lambda x:x.split(',')[1].split('.')[0].strip())
Title_Dict = {}
Title_Dict.update(dict.fromkeys(['Capt', 'Col', 'Major', 'Dr', 'Rev'], 'Officer'))
Title_Dict.update(dict.fromkeys(['Don', 'Sir', 'the Countess', 'Dona', 'Lady'], 'Royalty'))
Title_Dict.update(dict.fromkeys(['Mme', 'Ms', 'Mrs'], 'Mrs'))
Title_Dict.update(dict.fromkeys(['Mlle', 'Miss'], 'Miss'))
Title_Dict.update(dict.fromkeys(['Mr'], 'Mr'))
Title_Dict.update(dict.fromkeys(['Master','Jonkheer'], 'Master'))
all_data['Title'] = all_data['Title'].map(Title_Dict)
sns.barplot(x="Title", y="Survived", data=all_data)
Title Feature
8)FamilyLabel Feature(New):家庭人数为2到4的乘客幸存率较高
新增FamilyLabel特征,先计算FamilySize=Parch+SibSp+1,然后把FamilySize分为三类。
all_data['FamilySize']=all_data['SibSp']+all_data['Parch']+1
sns.barplot(x="FamilySize", y="Survived", data=all_data)
FamilyLabel Feature
按生存率把FamilySize分为三类,构成FamilyLabel特征。
def Fam_label(s):
if (s >= 2) & (s <= 4):
return 2
elif ((s > 4) & (s <= 7)) | (s == 1):
return 1
elif (s > 7):
return 0
all_data['FamilyLabel']=all_data['FamilySize'].apply(Fam_label)
sns.barplot(x="FamilyLabel", y="Survived", data=all_data)
FamilyLabel Feature
9)Deck Feature(New):不同甲板的乘客幸存率不同
新增Deck特征,先把Cabin空缺值填充为'Unknown',再提取Cabin中的首字母构成乘客的甲板号。
all_data['Cabin'] = all_data['Cabin'].fillna('Unknown')
all_data['Deck']=all_data['Cabin'].str.get(0)
sns.barplot(x="Deck", y="Survived", data=all_data)
Deck Feature
10)TicketGroup Feature(New):与2至4人共票号的乘客幸存率较高
新增TicketGroup特征,统计每个乘客的共票号数。
Ticket_Count = dict(all_data['Ticket'].value_counts())
all_data['TicketGroup'] = all_data['Ticket'].apply(lambda x:Ticket_Count[x])
sns.barplot(x='TicketGroup', y='Survived', data=all_data)
TicketGroup Feature
按生存率把TicketGroup分为三类。
def Ticket_Label(s):
if (s >= 2) & (s <= 4):
return 2
elif ((s > 4) & (s <= 8)) | (s == 1):
return 1
elif (s > 8):
return 0
all_data['TicketGroup'] = all_data['TicketGroup'].apply(Ticket_Label)
sns.barplot(x='TicketGroup', y='Survived', data=all_data)
TicketGroup Feature
3.数据清洗
1)缺失值填充
Age Feature:Age缺失量为263,缺失量较大,用Sex, Title, Pclass三个特征构建随机森林模型,填充年龄缺失值。
from sklearn.ensemble import RandomForestRegressor
age_df = all_data[['Age', 'Pclass','Sex','Title']]
age_df=pd.get_dummies(age_df)
known_age = age_df[age_df.Age.notnull()].as_matrix()
unknown_age = age_df[age_df.Age.isnull()].as_matrix()
y = known_age[:, 0]
X = known_age[:, 1:]
rfr = RandomForestRegressor(random_state=0, n_estimators=100, n_jobs=-1)
rfr.fit(X, y)
predictedAges = rfr.predict(unknown_age[:, 1::])
all_data.loc[ (all_data.Age.isnull()), 'Age' ] = predictedAges
Embarked Feature:Embarked缺失量为2,缺失Embarked信息的乘客的Pclass均为1,且Fare均为80,因为Embarked为C且Pclass为1的乘客的Fare中位数为80,所以缺失值填充为C。
all_data[all_data['Embarked'].isnull()]
NaN
[input]:
all_data.groupby(by=["Pclass","Embarked"]).Fare.median()
[Output]:
Pclass Embarked
1 C 78.2667
Q 90.0000
S 52.0000
2 C 15.3146
Q 12.3500
S 15.3750
3 C 7.8958
Q 7.7500
S 8.0500
Name: Fare, dtype: float64
all_data['Embarked'] = all_data['Embarked'].fillna('C')
Fare Feature:Fare缺失量为1,缺失Fare信息的乘客的Embarked为S,Pclass为3,所以用Embarked为S,Pclass为3的乘客的Fare中位数填充。
all_data[all_data['Fare'].isnull()]
NaN
fare=all_data[(all_data['Embarked'] == "S") & (all_data['Pclass'] == 3)].Fare.median()
all_data['Fare']=all_data['Fare'].fillna(fare)
2)同组识别
把姓氏相同的乘客划分为同一组,从人数大于一的组中分别提取出每组的妇女儿童和成年男性。
all_data['Surname']=all_data['Name'].apply(lambda x:x.split(',')[0].strip())
Surname_Count = dict(all_data['Surname'].value_counts())
all_data['FamilyGroup'] = all_data['Surname'].apply(lambda x:Surname_Count[x])
Female_Child_Group=all_data.loc[(all_data['FamilyGroup']>=2) & ((all_data['Age']<=12) | (all_data['Sex']=='female'))]
Male_Adult_Group=all_data.loc[(all_data['FamilyGroup']>=2) & (all_data['Age']>12) & (all_data['Sex']=='male')]
发现绝大部分女性和儿童组的平均存活率都为1或0,即同组的女性和儿童要么全部幸存,要么全部遇难。
Female_Child=pd.DataFrame(Female_Child_Group.groupby('Surname')['Survived'].mean().value_counts())
Female_Child.columns=['GroupCount']
Female_Child
GroupCount
sns.barplot(x=Female_Child.index, y=Female_Child["GroupCount"]).set_xlabel('AverageSurvived')
AverageSurvived
绝大部分成年男性组的平均存活率也为1或0。
Male_Adult=pd.DataFrame(Male_Adult_Group.groupby('Surname')['Survived'].mean().value_counts())
Male_Adult.columns=['GroupCount']
Male_Adult
GroupCount
因为普遍规律是女性和儿童幸存率高,成年男性幸存较低,所以我们把不符合普遍规律的反常组选出来单独处理。把女性和儿童组中幸存率为0的组设置为遇难组,把成年男性组中存活率为1的设置为幸存组,推测处于遇难组的女性和儿童幸存的可能性较低,处于幸存组的成年男性幸存的可能性较高。
[Input]:
Female_Child_Group=Female_Child_Group.groupby('Surname')['Survived'].mean()
Dead_List=set(Female_Child_Group[Female_Child_Group.apply(lambda x:x==0)].index)
print(Dead_List)
Male_Adult_List=Male_Adult_Group.groupby('Surname')['Survived'].mean()
Survived_List=set(Male_Adult_List[Male_Adult_List.apply(lambda x:x==1)].index)
print(Survived_List)
[Output]:
{'Panula', 'Lefebre', 'Lobb', 'Johnston', 'Robins', 'Ilmakangas', 'Turpin', 'Arnold-Franchi', 'Lahtinen', 'Barbara', 'Goodwin', 'Oreskovic', 'Van Impe', 'Strom', 'Rosblom', 'Cacic', 'Attalah', 'Caram', 'Vander Planke', 'Palsson', 'Skoog', 'Danbom', 'Rice', 'Canavan', 'Bourke', 'Jussila', 'Olsson', 'Boulos', 'Zabour', 'Sage', 'Ford'}
{'Beane', 'Frauenthal', 'Harder', 'Nakid', 'Bishop', 'Beckwith', 'Bradley', 'Chambers', 'Cardeza', 'Daly', 'Goldenberg', 'Kimball', 'McCoy', 'Jussila', 'Frolicher-Stehli', 'Duff Gordon', 'Greenfield', 'Dick', 'Jonsson', 'Taylor'}
为了使处于这两种反常组中的样本能够被正确分类,对测试集中处于反常组中的样本的Age,Title,Sex进行惩罚修改。
train=all_data.loc[all_data['Survived'].notnull()]
test=all_data.loc[all_data['Survived'].isnull()]
test.loc[(test['Surname'].apply(lambda x:x in Dead_List)),'Sex'] = 'male'
test.loc[(test['Surname'].apply(lambda x:x in Dead_List)),'Age'] = 60
test.loc[(test['Surname'].apply(lambda x:x in Dead_List)),'Title'] = 'Mr'
test.loc[(test['Surname'].apply(lambda x:x in Survived_List)),'Sex'] = 'female'
test.loc[(test['Surname'].apply(lambda x:x in Survived_List)),'Age'] = 5
test.loc[(test['Surname'].apply(lambda x:x in Survived_List)),'Title'] = 'Miss'
3)特征转换
选取特征,转换为数值变量,划分训练集和测试集。
all_data=pd.concat([train, test])
all_data=all_data[['Survived','Pclass','Sex','Age','Fare','Embarked','Title','FamilyLabel','Deck','TicketGroup']]
all_data=pd.get_dummies(all_data)
train=all_data[all_data['Survived'].notnull()]
test=all_data[all_data['Survived'].isnull()].drop('Survived',axis=1)
X = train.as_matrix()[:,1:]
y = train.as_matrix()[:,0]
4.建模和优化
1)参数优化
用网格搜索自动化选取最优参数,事实上我用网格搜索得到的最优参数是n_estimators = 28,max_depth = 6。但是参考另一篇Kernel把参数改为n_estimators = 26,max_depth = 6之后交叉验证分数和kaggle评分都有略微提升。
[Input]:
from sklearn.pipeline import Pipeline
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import GridSearchCV
from sklearn.feature_selection import SelectKBest
pipe=Pipeline([('select',SelectKBest(k=20)),
('classify', RandomForestClassifier(random_state = 10, max_features = 'sqrt'))])
param_test = {'classify__n_estimators':list(range(20,50,2)),
'classify__max_depth':list(range(3,60,3))}
gsearch = GridSearchCV(estimator = pipe, param_grid = param_test, scoring='roc_auc', cv=10)
gsearch.fit(X,y)
print(gsearch.best_params_, gsearch.best_score_)
[Output]:
{'classify__max_depth': 6, 'classify__n_estimators': 42} 0.88109635084
2)训练模型
[Input]:
from sklearn.pipeline import make_pipeline
select = SelectKBest(k = 20)
clf = RandomForestClassifier(random_state = 10, warm_start = True,
n_estimators = 26,
max_depth = 6,
max_features = 'sqrt')
pipeline = make_pipeline(select, clf)
pipeline.fit(X, y)
[Output]:
Out[40]:
Pipeline(memory=None,
steps=[('selectkbest', SelectKBest(k=20, score_func=<function f_classif at 0x000000000C8AE048>)), ('randomforestclassifier', RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',
max_depth=6, max_features='sqrt', max_leaf_nodes=None,
min_impurity_decreas...estimators=26, n_jobs=1,
oob_score=False, random_state=10, verbose=0, warm_start=True))])
3)交叉验证
[input]:
from sklearn import cross_validation, metrics
cv_score = cross_validation.cross_val_score(pipeline, X, y, cv= 10)
print("CV Score : Mean - %.7g | Std - %.7g " % (np.mean(cv_score), np.std(cv_score)))
[Output]:
CV Score : Mean - 0.8451402 | Std - 0.03276752
5.预测
predictions = pipeline.predict(test)
submission = pd.DataFrame({"PassengerId": PassengerId, "Survived": predictions.astype(np.int32)})
submission.to_csv(r"h:\kaggle\submission1.csv", index=False)
以下是我所有文章的目录,大家如果感兴趣,也可以前往查看
👉戳右边:打开它,也许会看到很多对你有帮助的文章
网友评论