# kaggle-Titanic

#### 一 经典又兼具备趣味性的Kaggle案例[泰坦尼克号问题

``````import os
os.chdir("D:/kaggle/daima/lecture01/Feature_engineering_and_model_tuning/Kaggle_Titanic")
data_train.columns#字段名
data_train.info() #字段类型 以及缺失情况
data_train.describe() #数值型
``````

## 画多图 数据探索

``````import matplotlib.pyplot as plt
fig = plt.figure()
fig.set(alpha=0.2)  # 设定图表颜色alpha参数

plt.subplot2grid((2,3),(0,0))             # 在一张大图里分列几个小图
data_train.Survived.value_counts().plot(kind='bar')       # 0 /549 1  /342  x轴为第一列  多列的列名为lengend
plt.title(u"获救情况 (1为获救)") # puts a title on our graph
plt.ylabel(u"人数")

plt.subplot2grid((2,3),(1,0), colspan=2)
data_train[data_train.Pclass == 1].Age.plot(kind='kde')   # plots a kernel desnsity estimate of the subset of the 1st class passanges's age
data_train[data_train.Pclass == 2].Age.plot(kind='kde')
data_train[data_train.Pclass == 3].Age.plot(kind='kde')  #条件是legend
plt.xlabel(u"年龄")# plots an axis lable
plt.ylabel(u"密度")
plt.title(u"各等级的乘客年龄分布")
plt.legend((u'头等舱', u'2等舱',u'3等舱'),loc='best') # sets our legend for our graph.

#看看各乘客等级的获救情况
fig = plt.figure()
fig.set(alpha=0.2)  # 设定图表颜色alpha参数

Survived_0 = data_train.Pclass[data_train.Survived == 0].value_counts()
Survived_1 = data_train.Pclass[data_train.Survived == 1].value_counts()
df=pd.DataFrame({u'获救':Survived_1, u'未获救':Survived_0})
df.plot(kind='bar', stacked=True)   #df一行一个bar
plt.title(u"各乘客等级的获救情况")
plt.xlabel(u"乘客等级")
plt.ylabel(u"人数")

plt.show()

#多因素交互影响
data_train.Survived[data_train.Sex == 'female'][data_train.Pclass != 3].value_counts().plot(kind='bar', label="female highclass", color='#FA2479')
ax1.set_xticklabels([u"获救", u"未获救"], rotation=0)
ax1.legend([u"女性/高级舱"], loc='best')
``````
``````g = data_train.groupby(['SibSp','Survived'])
g.count()
df = pd.DataFrame(g.count()['PassengerId'])
df
``````
``````#cabin的值计数太分散了，**绝大多数Cabin值只出现一次。感觉上作为类目，加入特征未必会有效
#那我们一起看看这个值的有无**，对于survival的分布状况，影响如何吧
fig = plt.figure()
fig.set(alpha=0.2)  # 设定图表颜色alpha参数

Survived_cabin = data_train.Survived[pd.notnull(data_train.Cabin)].value_counts()

Survived_nocabin = data_train.Survived[pd.isnull(data_train.Cabin)].value_counts()
df=pd.DataFrame({u'有':Survived_cabin, u'无':Survived_nocabin}).transpose()
df.plot(kind='bar', stacked=True)
plt.title(u"按Cabin有无看获救情况")
plt.xlabel(u"Cabin有无")
plt.ylabel(u"人数")
plt.show()

#似乎有cabin记录的乘客survival比例稍高，那先试试把这个值分为两类，有cabin值/无cabin值，一会儿加到类别特征好了
``````

``````#标准化
import sklearn.preprocessing as preprocessing
scaler = preprocessing.StandardScaler()
#age_scale_param = scaler.fit(df['Age'])
df[['Age_scaled','Fare_scaled']] = scaler.fit_transform(df[['Age','Fare']])
``````

• 如果缺值的样本占总数比例极高，我们可能就直接舍弃了，作为特征加入的话，可能反倒带入noise，影响最后的结果了
• 如果缺值的样本适中，而该属性非连续值特征属性(比如说类目属性)，那就把NaN作为一个新类别，加到类别特征中
• 如果缺值的样本适中，而该属性为连续值特征属性，有时候我们会考虑给定一个step(比如这里的age，我们可以考虑每隔2/3岁为一个步长)，然后把它离散化，之后把NaN作为一个type加到属性类目中。
• 有些情况下，缺失的值个数并不是特别多，那我们也可以试着根据已有的值，拟合一下数据，补充上。
本例中，后两种处理方式应该都是可行的，我们先试试拟合补全吧(虽然说没有特别多的背景可供我们拟合，这不一定是一个多么好的选择)

Age和Fare两个属性，乘客的数值幅度变化，也忒大了吧！！如果大家了解逻辑回归与梯度下降的话，会知道，各属性值之间scale差距太大，将对收敛速度造成几万点伤害值！甚至不收敛

## 把需要的feature字段取出来

``````# 我们把需要的feature字段取出来，转成numpy格式，使用scikit-learn中的LogisticRegression建模
from sklearn import linear_model

train_df = df.filter(regex='Survived|Age_.*|SibSp|Parch|Fare_.*|Cabin_.*|Embarked_.*|Sex_.*|Pclass_.*')
train_np = train_df.as_matrix()

# y即Survival结果
y = train_np[:, 0]

# X即特征属性值
X = train_np[:, 1:]
``````

## 模型训练

`````` fit到RandomForestRegressor之中
clf = linear_model.LogisticRegression(C=1.0, penalty='l1', tol=1e-6)
clf.fit(X, y)

clf
``````

## 对训练集和测试集做一样的操作

``````data_test = pd.read_csv("test.csv")
data_test.loc[ (data_test.Fare.isnull()), 'Fare' ] = 0
# 接着我们对test_data做和train_data中一致的特征变换
# 首先用同样的RandomForestRegressor模型填上丢失的年龄
tmp_df = data_test[['Age','Fare', 'Parch', 'SibSp', 'Pclass']]
null_age = tmp_df[data_test.Age.isnull()].as_matrix()
# 根据特征属性X预测年龄并补上
X = null_age[:, 1:]
predictedAges = rfr.predict(X)
data_test.loc[ (data_test.Age.isnull()), 'Age' ] = predictedAges

data_test = set_Cabin_type(data_test)
dummies_Cabin = pd.get_dummies(data_test['Cabin'], prefix= 'Cabin')
dummies_Embarked = pd.get_dummies(data_test['Embarked'], prefix= 'Embarked')
dummies_Sex = pd.get_dummies(data_test['Sex'], prefix= 'Sex')
dummies_Pclass = pd.get_dummies(data_test['Pclass'], prefix= 'Pclass')

df_test = pd.concat([data_test, dummies_Cabin, dummies_Embarked, dummies_Sex, dummies_Pclass], axis=1)
df_test.drop(['Pclass', 'Name', 'Sex', 'Ticket', 'Cabin', 'Embarked'], axis=1, inplace=True)
df_test['Age_scaled'] = scaler.fit_transform(df_test['Age'], age_scale_param)
df_test['Fare_scaled'] = scaler.fit_transform(df_test['Fare'], fare_scale_param)

test = df_test.filter(regex='Age_.*|SibSp|Parch|Fare_.*|Cabin_.*|Embarked_.*|Sex_.*|Pclass_.*')
predictions = clf.predict(test)
result = pd.DataFrame({'PassengerId':data_test['PassengerId'].as_matrix(), 'Survived':predictions.astype(np.int32)})
result.to_csv("logistic_regression_predictions.csv", index=False)
``````

## 要判定一下当前模型所处状态(欠拟合or过拟合)learning curve

``````对过拟合而言，通常以下策略对结果优化是有用的：

``````

## 优化baseline系统

1. 比如说Name和Ticket两个属性被我们完整舍弃了(好吧，其实是一开始我们对于这种，每一条记录都是一个完全不同的值的属性，并没有很直接的处理方式)
name中包含title？
ticket是否相同，相同为同一家人更容易幸存，不同幸存率低？
去掉关联特征（兄弟，父母），增加派生特征（title）？
2. 比如说，我们想想，年龄的拟合本身也未必是一件非常靠谱的事情
3. 另外，以我们的日常经验，小盆友和老人可能得到的照顾会多一些，这样看的话，年龄作为一个连续值，给一个固定的系数，应该和年龄是一个正相关或者负相关，似乎体现不出两头受照顾的实际情况，所以，说不定我们把年龄离散化，按区段分作类别属性会更合适一些。 年龄分段，老人小孩受照顾，5岁一个年龄段
##### 将model系数和feature关联

pd.DataFrame({"columns":list(train_df.columns)[1:], "coef":list(clf.coef_.T)})

• Sex属性，如果是female会极大提高最后获救的概率，而male会很大程度拉低这个概率。
• Pclass属性，1等舱乘客最后获救的概率会上升，而乘客等级为3会极大地拉低这个概率。
• 有Cabin值会很大程度拉升最后获救概率(这里似乎能看到了一点端倪，事实上从最上面的有无Cabin记录的Survived分布图上看出，即使有Cabin记录的乘客也有一部分遇难了，估计这个属性上我们挖掘还不够)
• Age是一个负相关，意味着在我们的模型里，年龄越小，越有获救的优先权(还得回原数据看看这个是否合理）
• 有一个登船港口S会很大程度拉低获救的概率，另外俩港口压根就没啥作用(这个实际上非常奇怪，因为我们从之前的统计图上并没有看到S港口的获救率非常低，所以也许可以考虑把登船港口这个feature去掉试试)。
• 船票Fare有小幅度的正相关(并不意味着这个feature作用不大，有可能是我们细化的程度还不够，举个例子，说不定我们得对它离散化，再分至各个乘客等级上？)

#### 交叉验证

from sklearn import cross_validation

clf = linear_model.LogisticRegression(C=1.0, penalty='l1', tol=1e-6)
all_data=df.filter(regex='Survived|Age_.|SibSp|Parch|Fare_.|Cabin_.|Embarked_.|Sex_.|Pclass_.')
X = all_data.as_matrix()[:,1:]
y = all_data.as_matrix()[:,0]
print cross_validation.cross_val_score(clf, X, y, cv=5)

split_train, split_cv = cross_validation.train_test_split(df, test_size=0.3, random_state=0)
train_df = split_train.filter(regex='Survived|Age_.|SibSp|Parch|Fare_.|Cabin_.|Embarked_.|Sex_.|Pclass_.')

clf = linear_model.LogisticRegression(C=1.0, penalty='l1', tol=1e-6)
clf.fit(train_df.as_matrix()[:,1:], train_df.as_matrix()[:,0])

cv_df = split_cv.filter(regex='Survived|Age_.|SibSp|Parch|Fare_.|Cabin_.|Embarked_.|Sex_.|Pclass_.')
predictions = clf.predict(cv_df.as_matrix()[:,1:])

Age属性不使用现在的拟合方式，而是根据名称中的『Mr』『Mrs』『Miss』等的平均值进行填充。
Age不做成一个连续值属性，而是使用一个步长进行离散化，变成离散的类目feature。
Cabin再细化一些，对于有记录的Cabin属性，我们将其分为前面的字母部分(我猜是位置和船层之类的信息) 和 后面的数字部分(应该是房间号，有意思的事情是，如果你仔细看看原始数据，你会发现，这个值大的情况下，似乎获救的可能性高一些)。
Pclass和Sex俩太重要了，我们试着用它们去组出一个组合属性来试试，这也是另外一种程度的细化。

Name是一个我们一直没有触碰的属性，我们可以做一些简单的处理，比如说男性中带某些字眼的(‘Capt’, ‘Don’, ‘Major’, ‘Sir’)可以统一到一个Title，女性也一样。

## 模型融合(model ensemble)

Bagging 1 数据 2模型算法

from sklearn.ensemble import BaggingRegressor
train_df = df.filter(regex='Survived|Age_.|SibSp|Parch|Fare_.|Cabin_.|Embarked_.|Sex_.|Pclass.|Mother|Child|Family|Title')
train_np = train_df.as_matrix()
y即Survival结果
y = train_np[:, 0]
X即特征属性值
X = train_np[:, 1:]
fit到BaggingRegressor之中
clf = linear_model.LogisticRegression(C=1.0, penalty='l1', tol=1e-6)
bagging_clf = BaggingRegressor(clf, n_estimators=20, max_samples=0.8, max_features=1.0, bootstrap=True, bootstrap_features=False, n_jobs=-1)
bagging_clf.fit(X, y)
test = df_test.filter(regex='Age_.|SibSp|Parch|Fare_.|Cabin_.|Embarked_.|Sex_.|Pclass.|Mother|Child|Family|Title')
predictions = bagging_clf.predict(test)

Bagging & cross validation
cross validation用来验证
Bagging用来提高模型精度
https://www.ncbi.nlm.nih.gov/pmc/articles/PMC2367370/
I understand the ins and outs of the processes of both cross validation (partition the data set evenly, train on k-1 partitions, blah blah blah) and bagging (train M models composed of n observations picked at random with replacement, blah blah blah).
It seems to me that at the most basic level they're just sampling the same training set (albeit by different methods), but cross validation is used to get a more accurate estimate of model performance on unseen test data, and bagging is used to get a more accurate fit of the training data.
If this true (someone may have to straighten me out if I have the ideas confused), does that mean you may want to use cross validation and bagging together - to find an accurate model that more accurately evaluates model performance on unseen data? It seems a little over kill, but I'm not sure.
https://www.cnblogs.com/sddai/p/5696834.html

Sklearn-GridSearchCV网格搜索
http://blog.csdn.net/cherdw/article/details/54970366（参数说明）

## 重要

Scikit-learn使用总结
http://python.jobbole.com/86910/