泰坦尼克号
1.前言
本文是学习数据挖掘和机器学习模型的运用的一点笔记。
2.数据阅读
2.1 背景
本题背景为泰坦尼克号,探索成功逃生的人和什么因素有关。
2.2 特征
数据分为:
- PassengerId: 编号 ID
- Survived: 标签:是否存活
- Pclass: 座位阶级
- Name: 姓名
- Sex, Age: 性别年龄
- SibSp, Parch: 兄妹/父母小孩数
- Ticket: 船票信息 (应该没用)
- Fare: 票价 (应该和Pclass的相关度很高)
- Cabin: 客舱
- Embarked: 登船港口
2.3 查询缺失值
data_train = pd.read_csv("Train.csv")
data_train.info()
发现共891条数据,有一堆缺失值,比如年龄有177个缺失值。
在基本统计分析数据时,重点关注标准差、最大值和最小值。标准差反应数据的离散程度,最值可以看出是否有异常值。
现在看一下票价的分析,标准差32.20, 最大值512.33, 最小值0.
2.4 获救分析
data_train['Survived'].value_counts()
有342个人获救,549人丧生。
data_train['Pclass'].value_counts().plot(kind='bar')
plt.ylabel(u"人数")
plt.xlabel(u'乘客等级')
plt.title(u'乘客等级分布')
# plt.hist() 画直方图
data_train['Fare'].hist()
# plt.hist(data_train.Age,bins=100)
# bins 横坐标
data_train['Fare'].plot(kind='box') # 箱线图
3.缺失值填充
一般对缺失数据的填充有删除、固定值填充、均值/众数/中位数填充等方法,对于数据量较小的数据集,固定值填充无法反应缺失数据特性,所以尝试用随机森林算法来预测缺失值。
3.1 年龄填充
data_train = set_missing_age(data_train)
# 存储本地,path, 格式
data_train.to_csv(path_or_buf="NewTrain.csv", float_format="%.0f")
3.2 港口填充
属性Embarked只有2个缺失值,影响不大,直接删除这两条记录。
data = data_train.drop(data_train[data_train['Embarked'].isnull()].index)
4.相关性探测
import seaborn
df = data[['Pclass', 'Sex', 'Age', 'SibSp', 'Parch', 'Fare', 'Survived']]
# 属性间相关系数
cor = df.corr()
print(cor)
# 属性间相关系数热力图
seaborn.heatmap(cor)
plt.show()
从结果看出,各属性和结果的相关性都不大,属性间相关度最高的是票价和等级、兄妹数和亲属数。相关性的分析适合分析数值型数据,针对分类型数据不太适合,所以我们单独分析每个属性和结果之间的关系。
4.1 性别
Survived_m = data.loc[data['Sex'] == 'male', 'Survived'].value_counts()
Survived_f = data.loc[data['Sex'] == 'female', 'Survived'].value_counts()
df_sex = pd.DataFrame({u'男性':Survived_m, u'女性':Survived_f})
df_sex.plot(kind='bar', stacked=True)
plt.title(u'不同性别乘客的获救情况')
plt.xticks([0,1],['Dead', 'Survived'])
plt.show()
4.2 等级
Survived_c0 = data.loc[data['Survived'] == 0, 'Pclass'].value_counts()
Survived_c1 = data.loc[data['Survived'] == 1, 'Pclass'].value_counts()
df_class = pd.DataFrame({u'获救': Survived_c1, u'死亡': Survived_c0})
df_class.plot(kind='bar', stacked=True) # stacked: 堆叠/并列
plt.title(u'不同等级乘客的获救情况')
plt.show()
4.3 其他
再分析其他的属性,如年龄段、登录港口,这里省略步骤。
- 对于类别较多的属性,如SibSp和Parch
方法1:直接统计各类的获救情况:
g1 = data.groupby(['SibSp', 'Survived'])
df_SibSp = pd.DataFrame(g1.count()['PassengerId'])
df_SibSp.rename(columns={'PassengerId':'count'}, inplace=True)
print(df_SibSp)
方法2:继续画图:
Survived_c0 = data.loc[data['Survived'] == 0, 'SibSp'].value_counts()
Survived_c1 = data.loc[data['Survived'] == 1, 'SibSp'].value_counts()
df_class = pd.DataFrame({u'获救': Survived_c1, u'死亡': Survived_c0})
df_class.plot(kind='bar', stacked=True)
plt.title(u'不同SibSp的获救情况')
plt.show()
从结果中看出,SibSp < 3时,获救率高。
- 数值型数据
Fare是票价,作为连续数据,采用密度分布图的方式,票价不能确定如何分段,所以不能像年龄那样分段转离散处理。
如果获救的曲线整体更偏向右边,说明票价越高的获救几率越大。
现在可以探查一下极端值的情况:
print(data.loc[data['Fare'] == 0, 'Survived'].value_counts())
print(data.loc[data['Fare'] == max(data['Fare']), 'Survived'].value_counts())
可以看出,票价为0的里面,有1个获救,票价最高的3个人都获救了,说明票价高低对是否获救存在影响,也说明这几个数值层面异常的值并不是真实异常值。
5. 特征工程
本项目,最终的预测是二分类问题,所以初步可以选择逻辑回归进行预测,对类别型的数据进行因子化处理,对票价属性进行归一化处理。
# 特征因子化
def set_numeralization(data):
# 针对定类性属性进行因子化,分别有Embarked,Sex,Pclass
dummies_Embarked = pd.get_dummies(data['Embarked'], prefix='Embarked')
dummies_Sex = pd.get_dummies(data['Sex'], prefix='Sex')
dummies_Pclass = pd.get_dummies(data['Pclass'], prefix='Pclass')
# 将新的属性拼合
df = pd.concat([data, dummies_Embarked, dummies_Sex, dummies_Pclass], axis=1)
# 将旧的属性剔除
df.drop(['Pclass', 'Sex', 'Embarked'], axis=1, inplace=True)
return df
用港口举例,取值范围:C/S/Q
以前我的做法:港口取值转化为0 1 2,然后归一化,相当于加了一个特征;
这个做法:港口取值转换为3个属性,用0/1作为取值,加了3个特征。
# 特征归一化
import sklearn.preprocessing as preprocessing
def set_normalization(df):
scaler = preprocessing.StandardScaler()
age_scale_param = scaler.fit(df['Age'].values.reshape(-1,1))
df['Age_scaled'] = scaler.fit_transform(df['Age'].values.reshape(-1,1),age_scale_param)
fare_scale_param = scaler.fit(df['Fare'].values.reshape(-1,1))
df['Fare_scaled'] = scaler.fit_transform(df['Fare'].values.reshape(-1,1),fare_scale_param)
return df
*注:测试集处理时,不建议删除缺失数据,而是用0填充。
5.5 测试集预处理
data_test.info()
- 年龄缺失值大概80,用随机森林算法填充;
- 随机森林用到的属性里,Fare有一条缺失值,用0填充:
data_test.loc[data_test['Fare'].isnull(), 'Fare'] = 0
-
Cabin缺失太多,且是字符类,舍弃。
-
Embarked、Sex带有0缺失值:
data_test.Embarked.value_counts()
data_test.Sex.value_counts()
用最多的来填充:
data_test.loc[data_test['Sex'] == 0, 'Sex'] = 'male'
data_test.loc[data_test['Embarked'] == 0, 'Embarked'] = 'S'
6. 模型构建
6.1 初步准备
# 利用正则表达式取出需要的属性
train_df = data.filter(regex='Survived|Age_.*|SibSp|Parch|Fare_.*|Embarked_.*|Sex_.*|Pclass_.*')
train_np = train_df.values
# 测试集
test_df = data_t.filter(regex='Survived|Age_.*|SibSp|Parch|Fare_.*|Embarked_.*|Sex_.*|Pclass_.*')
y = train_np[:, 0] # 第一列
x = train_np[:, 1:]
6.2 逻辑回归
# 逻辑回归模型
clf = linear_model.LogisticRegression(solver='liblinear', C=1.0, penalty='l2', tol=1e-6)
clf.fit(x, y)
# 对测试数据进行预测
predictions = clf.predict(test_df)
result = pd.DataFrame({'PassengerId': data_test['PassengerId'].values, 'Survived': predictions.astype(np.int32)})
print(result.head())# 逻辑回归模型
clf = linear_model.LogisticRegression(solver='liblinear', C=1.0, penalty='l2', tol=1e-6)clf.fit(x, y)# 对测试数据进行预测
predictions = clf.predict(test_df)result = pd.DataFrame({'PassengerId': data_test['PassengerId'].values, 'Survived': predictions.astype(np.int32)})
print(result.head())
未完待续