数据
载入数据
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(船票编号)暂时认为是无用属性,选择丢弃。
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%。
提升成绩
(待补充)