Titanic: Machine Learning from Disaster

比赛页面

数据

载入数据

train_set=pd.read_csv('./train.csv')
test_set=pd.read_csv('./test.csv')
total_dataset=[train_set,test_set]

初步观察

train_set.sample(5)

test_set.sample(5)

train_set.info()

test_set.info()

train_set.describe()    #数值列统计信息

train_set.describe(include=['O'])    #非数值列统计信息

通过以上数据观察,不难得出以下信息:
1. 在train_set中,Age、Cabin、Embarked列存在缺失值
2. 在test_set中,Age、Fare、Cabin列存在缺失值
3. Cabin列的缺失值过多
4. test_set中缺少Survived列,此列为需要预测的列
5. 在train_set中,Survived列的均值表示乘客的生还率,为0.38
6. Pclass为负斜分布,Age、SibSp、Parch与Fare均是正斜分布
7. Name列里没有重复的值

数据清洗

丢弃无用值

PassengerId是一个显而易见的无用属性,选择丢弃。需要注意test_set中的PassengerId不能丢,因为需要对预测结果进行标号。

而Cabin列由于缺失值太多,无法起到有效作用,选择丢弃。

train_set.drop(['PassengerId','Cabin'],axis=1,inplace=True)
test_set.drop(['Cabin'],axis=1,inplace=True)

Ticket(船票编号)暂时认为是无用属性,选择丢弃。

扫描二维码关注公众号,回复: 1926201 查看本文章
train_set.drop(['Ticket'],axis=1,inplace=True)
test_set.drop(['Ticket'],axis=1,inplace=True)

填充缺失值

使用中位数来填充数值型缺失值,使用众数来填充非数值型缺失值。

for dataset in total_dataset:
    dataset['Age'].fillna(dataset['Age'].median(),inplace=True)
    dataset['Fare'].fillna(dataset['Fare'].median(),inplace=True)
    dataset['Embarked'].fillna(dataset['Embarked'].mode()[0],inplace=True)

特征分析

train_set[['Pclass', 'Survived']].groupby(['Pclass'], as_index=False).mean()

train_set[["Sex", "Survived"]].groupby(['Sex'], as_index=False).mean()

train_set[["SibSp", "Survived"]].groupby(['SibSp'], as_index=False).mean()

train_set[["Parch", "Survived"]].groupby(['Parch'], as_index=False).mean()

train_set[["Embarked", "Survived"]].groupby(['Embarked'], as_index=False).mean()

#以Survived属性来创建坐标图(Survived属性有两个取值,所以创建两列坐标图)
g = sns.FacetGrid(train_df, col='Survived')    
#在创建好的坐标图上绘制直方图,横轴为Age,纵轴为样本数
g.map(plt.hist, 'Age',bins=20)

#以Survived属性来创建坐标图(Survived属性有两个取值,所以创建两列坐标图)
g = sns.FacetGrid(train_set, col='Survived')    
#在创建好的坐标图上绘制直方图,横轴为Fare,纵轴为样本数
g.map(plt.hist, 'Fare',bins=20)

Name列没有重复值,需要特殊处理,提取出Name中的头衔:

for dataset in total_dataset:
    dataset['Title'] = dataset.Name.str.extract('([A-Za-z]+)\.', expand=False)    #匹配多个字符后跟小数点

查看头衔的取值范围:

pd.crosstab(train_set['Title'], train_set['Sex'])

pd.crosstab(test_set['Title'], test_set['Sex'])


整合头衔:

for dataset in total_dataset:
    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_set[['Title', 'Survived']].groupby(['Title'], as_index=False).mean()

特征工程

对于连续性数值类型的数据,可以将其划分成有限的几个区间;对于非连续性的类别数据,将其转换成数字编码。

观察到SibSp与Parch均是亲属关系,将这两个属性合并为Family_size属性:

for dataset in total_dataset:
    dataset['Family_size']=dataset['SibSp']+dataset['Parch']

g = sns.FacetGrid(train_set, col='Survived')    
#在创建好的坐标图上绘制直方图,横轴为Age,纵轴为样本数
g.map(plt.hist, 'Family_size')


注意到Family_size为0时的生存率要比Family_size>0时的生存率要低,所以再将Family_size转化为新特征IsAlone:

for dataset in total_dataset:
    dataset['IsAlone']=0
    dataset.loc[dataset['Family_size']==0,'IsAlone']=1

train_set[['IsAlone','Survived']].groupby(['IsAlone'],as_index=False).mean()

将剩下的特征划分成有限区间,由于Fare属性的分布非常不均匀,对这一列使用qcut()方法,即按百分位点来分割:

for dataset in total_dataset:
    dataset['AgeBand']=pd.cut(dataset['Age'],5)
    dataset['FareBand']=pd.qcut(dataset['Fare'],4)

转换数据格式

现在所有的特征都化为了离散属性,接下来需要把离散属性编码成数字的形式便于输入模型,并且丢弃那些不输入模型的列:

from sklearn.preprocessing import LabelEncoder
label=LabelEncoder()

for dataset in total_dataset:
    dataset['SexCode']=label.fit_transform(dataset['Sex'])
    dataset['EmbarkedCode']=label.fit_transform(dataset['Embarked'])
    dataset['TitleCode']=label.fit_transform(dataset['Title'])
    dataset['AgeCode']=label.fit_transform(dataset['AgeBand'])
    dataset['FareCode']=label.fit_transform(dataset['FareBand'])

drop_column=['Sex','Embarked','Title','AgeBand','FareBand']
for dataset in total_dataset:
    dataset.drop(drop_column,axis=1,inplace=True)
Y_train=train_data['Survived']
X_train=train_data.drop(['Survived'],axis=1)

X_test=test_data.drop(['PassengerId'],axis=1)

最终输入ML模型的数据长这样:

X_train.sample(5)

模型

模型筛选

from sklearn import svm, tree, linear_model, neighbors, naive_bayes, ensemble, discriminant_analysis, gaussian_process
from xgboost import XGBClassifier

from sklearn.model_selection import cross_val_score
Models=[
    #Ensemble Methods
    ensemble.AdaBoostClassifier(),
    ensemble.BaggingClassifier(),
    ensemble.RandomForestClassifier(),

    #Nearest Neighbor
    neighbors.KNeighborsClassifier(),

    #SVM
    svm.SVC(),

    #xgboost
    XGBClassifier()
]

columns=['Model_name','Parameters','CV Acc']
Model_compare=pd.DataFrame(columns=columns)

row_index=0

for Model in Models:
    Model_compare.loc[row_index,'Model_name']=Model.__class__.__name__
    Model_compare.loc[row_index,'Parameters']=str(Model.get_params())
    Model_compare.loc[row_index,'CV Acc']=cross_val_score(Model,X_train,Y_train,cv=10,scoring='accuracy').mean()
    row_index+=1

Model_compare.sort_values(by='CV Acc',ascending=False)

参数调优

(待补充)

提交结果

svc.fit(X_train,Y_train)
Y_pred=svc.predict(X_test)

submission=pd.DataFrame({
    'PassengerId':test_df['PassengerId'],
    'Survived':Y_pred
})

submission.to_csv('./submission.csv',index=False)

提交成绩为0.79904,rank为16%。

提升成绩

(待补充)

猜你喜欢

转载自blog.csdn.net/qq_31823267/article/details/79687117