200字范文,内容丰富有趣,生活中的好帮手!
200字范文 > 【Kaggle】Titanic - Machine Learning from Disaster(二)

【Kaggle】Titanic - Machine Learning from Disaster(二)

时间:2021-07-09 07:14:34

相关推荐

【Kaggle】Titanic - Machine Learning from Disaster(二)

文章目录

1. 前言2. 预备-环境配置3. 数据集处理3.1 读取数据集3.2 查看pandas数据信息3.2.1 查看总体信息3.2.2 数据集空值统计3.3. 相关性分析3.3.1 可以对Survived字段进行简单统计分析,观察其其大致的分布规律3.3.2 训练集和测试集的单变量分析3.4 相关系数分析3.5 定义模型

1. 前言

在上篇文章:【Kaggle】Titanic - Machine Learning from Disaster中简单实现了比较粗暴的做法,直接堆叠了几层神经网络。但是,观察大家在Kaggle发布的代码来看,仅仅将这个问题看做简单的机器学习模型问题即可。将该问题归纳为回归问题,可以直接使用经典的模型来解决,比如逻辑回归。当然上述问题也仅是其一。最重要的是,大家在分析问题和处理数据的时候,充分考虑了各个因素和目标变量之间的关系,通过简单的统计分析可以排除不相关因素,进而更有利于模型的拟合。在这篇文章中,将对这个题目进行较为正规和形式化的处理。

2. 预备-环境配置

由于通过kaggle命令行的方式更加方便于提交结果和下载数据,所以在本地需要安装kaggle。使用pip安装即可:

pip install kaggle

或者到对应的虚拟环境中进行安装:

(base) C:\Users\w>conda install kaggle

然后到Kaggle个人主页:

点击Account,进入个人账户主页。点击Create New API Token

然后就回自动下载一个kaggle.json文件:

打开文件可以发现,其实也就是用户登录信息。然后需要将改文件放入用户目录下的.kaggle隐藏文件夹内:

然后修改一下Kaggle数据集下载的时候默认下载路径(默认下载路径就是上图路径),通过命令:

C:\Users\w>kaggle config set -n path -v d://Kaggle_Dataset- path is now set to: d://Kaggle_Dataset

比如下载来测试一下:

kaggle competitions download -c titanic

结果可以得到一个压缩包:

3. 数据集处理

3.1 读取数据集

from zipfile import ZipFileimport pandas as pd# 1. 解压压缩文件zipfiles = ZipFile("./competitions/titanic/titanic.zip")zipfiles.extractall("competitions/titanic/")test_data = pd.read_csv(baseDir+"test.csv")train_data = pd.read_csv(baseDir+"train.csv")

3.2 查看pandas数据信息

3.2.1 查看总体信息

test_data.info()

结果:

<class 'pandas.core.frame.DataFrame'>RangeIndex: 418 entries, 0 to 417Data columns (total 11 columns):PassengerId 418 non-null int64Pclass 418 non-null int64Name 418 non-null objectSex 418 non-null objectAge 332 non-null float64SibSp418 non-null int64Parch418 non-null int64Ticket 418 non-null objectFare 417 non-null float64Cabin91 non-null objectEmbarked 418 non-null objectdtypes: float64(2), int64(4), object(5)memory usage: 36.0+ KB

3.2.2 数据集空值统计

test_data.isna().sum()

结果:

PassengerId0Pclass 0Name 0Sex 0Age 86SibSp 0Parch 0Ticket 0Fare 1Cabin327Embarked 0dtype: int64

由于测试数据集共418条数据,而缺失达到了327,故而对于Cabin可以直接丢弃。

# 删除训练集和测试集的Cabin字段train_data = train_data.drop(['Cabin'], axis=1)test_data = test_data.drop(['Cabin'], axis=1)

3.3. 相关性分析

由于根据题意需要分析的是最终的测试集的Survived字段,故而从两个角度来分析:

异常值检验,可以对Survived字段进行简单统计分析,观察其其大致的分布规律训练集和测试集的单变量分析,也就是对训练集和测试集中的对应特征,可以进行简单的单变量分布规律对比;相关性分析,也就是分析各个字段对Survived字段的相关性;

import seaborn as sns

3.3.1 可以对Survived字段进行简单统计分析,观察其其大致的分布规律

sns.set()sns.histplot(train_data['Survived'], kde=True)

观察上图可知,绘制该图没有意义,因为可取值只有1和0。只能反映一个问题就是死亡人数超过存活人数。

3.3.2 训练集和测试集的单变量分析

# 样本总数train_count = train_data.shape[0]test_count = test_data.shape[0]

# 不同取值水平汇总后排序,再除以样本总数train_data['Pclass'].value_counts().sort_index()/train_count

# 绘制分布图(train_data['Pclass'].value_counts().sort_index()/train_count).plot()

更加直接的来说,可以绘制左右的因素在训练集和测集上的分布规律:

import matplotlib.pyplot as plt

features = ['Pclass', 'Name', 'Sex', 'Age', 'SibSp', 'Parch', 'Ticket', 'Fare', 'Embarked']for feature in features:(train_data[feature].value_counts().sort_index()/train_count).plot()(test_data[feature].value_counts().sort_index()/test_count).plot()plt.legend(['train', 'test'])plt.xlabel(feature)plt.ylabel('ratio')plt.show()

等等。这里不再完全贴出。很明显,从上述图中可以发现训练集和测试集数据分布不一致的字段有:Name、Ticket,故而可以这里可以直接将这两个字段进行删除。

# 删除训练集和测试集的Cabin字段train_data = train_data.drop(['Name', 'Ticket'], axis=1)test_data = test_data.drop(['Name', 'Ticket'], axis=1)

train_data.info()

注意到,SibSp, Parch字段的数据分布极为相似,所以这里可以对其进行合并处理,操作如下:

# 1. 将Parch和SibSp合并为Family# 训练集train_data['Family'] = train_data['Parch'] + train_data['SibSp']train_data['Family'].loc[train_data['Family'] > 0] = 1train_data['Family'].loc[train_data['Family'] == 0] = 0# 删除列Parch、SibSptrain_data = train_data.drop(['Parch', 'SibSp'], axis=1)# 测试集test_data['Family'] = test_data['Parch'] + test_data['SibSp']test_data['Family'].loc[test_data['Family'] > 0] = 1test_data['Family'].loc[test_data['Family'] == 0] = 0# 删除列Parch、SibSptest_data = test_data.drop(['Parch', 'SibSp'], axis=1)

注意到train_data和test_data中均有PassengerId,故而这里可以简单校验一下数据的PassengerId是否有重复:

train_data['PassengerId'].nunique() == train_counttest_data['PassengerId'].nunique() == test_count

也就是,满足唯一条件。由于PassengerId仅用于表示数据,故而可以在训练数据集中删除,由于测试集最后输出的预测结果需要和PassengerId对应,这里先不删除。

# 删除列PassengerIdtrain_data = train_data.drop(['PassengerId'], axis=1)

train_data.info()

<class 'pandas.core.frame.DataFrame'>RangeIndex: 891 entries, 0 to 890Data columns (total 7 columns):Survived 891 non-null int64Pclass891 non-null int64Sex 891 non-null objectAge 714 non-null float64Fare 891 non-null float64Embarked 889 non-null objectFamily891 non-null int64dtypes: float64(2), int64(3), object(2)memory usage: 48.8+ KB

注意到此时,Age和Embarked字段还没有对缺失值处理,这里需要继续处理。

# 使用(mean - std) & (mean + std) 之间的随机数来填充import numpy as npage_mean = train_data['Age'].mean()age_std = train_data['Age'].std()count_nan_age = train_data["Age"].isnull().sum()random_ages = np.random.randint(age_mean - age_std, age_mean + age_std, size=count_nan_age)train_data['Age'].loc[np.isnan(train_data['Age']) == True] = random_ages

test_data的Fare字段缺少部分值,

test_data['Fare'].isna().sum()

结果为1。由于只有一个,直接使用众数填充:

test_data['Fare'].loc[test_data['Fare'].isna() == True] = test_data['Fare'].median()

test_data.info()

<class 'pandas.core.frame.DataFrame'>RangeIndex: 418 entries, 0 to 417Data columns (total 7 columns):PassengerId 418 non-null int64Pclass 418 non-null int64Sex 418 non-null objectAge 418 non-null float64Fare 418 non-null float64Embarked 418 non-null objectFamily 418 non-null int64dtypes: float64(2), int64(3), object(2)memory usage: 22.9+ KB

然后可以进一步的来分析一下每个因素和Sruvived的关系。

plt.figure(figsize=(8,6))sns.countplot(x='Survived', hue='Sex', data=train_data)

可以看出,女性更容易存活。进一步的,统计一下每个年龄段的存活情况:

plt.figure(figsize=(20,6))train_data.Age = train_data.Age.astype(int)average_age = train_data[['Age', 'Survived']].groupby(['Age'], as_index=False).mean()sns.barplot(x='Age', y='Survived', data=average_age)

这里可以看到,年龄小和大均存活较高,可以结合年龄+性别,将用户分为:孩子、老人、男人、女人。

def get_person(person):age, sex = personif age<= 16:return 0 # 小孩elif age >= 63:return 1 # 老人else:return 2 if sex == 'male' else 3train_data['Person'] = train_data[['Age', 'Sex']].apply(get_person, axis=1)train_data.drop(['Age', 'Sex'], axis=1, inplace=True)

然后将Embarked字段同样处理为数字,查看下类别:

train_data.Embarked.value_counts()

def get_embarked(c):if c == 'S':return 0elif c == 'Q':return 1else:return 2train_data.Embarked = train_data['Embarked'].apply(get_embarked)

现在数据集:

3.4 相关系数分析

from sklearn.linear_model import LogisticRegression

reg = LogisticRegression()reg.fit(train_feature.to_numpy(), train_label.to_numpy())

pd.DataFrame(data=reg.coef_, columns=train_feature.columns)

这里可以知道,Fare字段相关性并不大,故而可以删除。

train_feature = train_feature[['Pclass', 'Embarked', 'Family', 'Person']]test_data = test_data[['Pclass', 'Embarked', 'Family', 'Person']]

3.5 定义模型

import tensorflow as tf

epochs = 500

model = tf.keras.Sequential()model.add(tf.keras.layers.Dense(64, input_shape=(train_feature.shape[1], ), activation='relu'))model.add(tf.keras.layers.Dense(1, activation='sigmoid'))pile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])model.summary()

history = model.fit(train_feature.to_numpy(), train_label.to_numpy(), epochs=epochs)

predict = model.predict(test_data)predict[predict < 0.5] = 0predict[predict >= 0.5] = 1predict = predict[:, 0].astype(int)predict

最后存储到csv文件:

submission = pd.DataFrame({"PassengerId": test.PassengerId,"Survived": predict})submission.to_csv('titanic.csv', index=False)

提交结果:

提高了一点点。当然,距离大佬的1还是很遥远。在这个过程中了解了数据的分析和处理手段,也挺好的。当然,完整地址:/weizu_cool/kaggle/blob/master/titanic.ipynb

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。