Kaggle:Titanic问题
相关库函数操作
1.pandas的read_csv函数
读取csv文件为DataFrame格式
from pandas
import DataFrame
data_train = pd.read_csv(
"Titanic/train.csv")
data_train
输出结果:会自动将第一行处理为label
2.DataFrame.info()函数
DataFrame.info()可以发现一些数据信息,计算特征非空值的个数,以及数据类型·
data_train.info()
输出结果:
<
class 'pandas.core.frame.DataFrame'>
RangeIndex: 891 entries,
0 to
890
Data columns (total
12 columns):
PassengerId
891 non-null int64
Survived
891 non-null int64
Pclass
891 non-null int64
Name
891 non-null object
Sex
891 non-null object
Age
714 non-null float64
SibSp
891 non-null int64
Parch
891 non-null int64
Ticket
891 non-null object
Fare
891 non-null float64
Cabin
204 non-null object
Embarked
889 non-null object
dtypes: float64(
2), int64(
5), object(
5)
memory usage:
66.2+ KB
3.DataFrame.describe()函数
得到数值型数据的一些信息,数值数,平均值,极值,标准差
data_train.describe()
输出结果:
4.value_counts()离散型变量计数函数
对于DataFrame里的特定label可以通过value_counts()函数来统计每个种类的个数
data_train.Cabin.value_counts()
输出结果:
C23 C25 C27
4
G6
4
B96 B98
4
D 3
C22 C26
3
E101
3
F2
3
F33
3
B57 B59 B63 B66
2
C68
2
B58 B60
2
E121
2
..
E67
2
D35
2
D36
2
C52
2
F4
2
C125
2
C124
2
..
F G63
1
A6
1
D45
1
D6
1
D56
1
C101
1
C54
1
D28
1
D37
1
Name: Cabin,
Length:
147, dtype: int64
也可以用图表输出
fig = plt.figure()
data_train.Survived.value_counts().plot(kind=
'bar')
plt.title(
'Survived situation')
plt.show()
data_train.Pclass.value_counts().plot(kind=
'bar')
plt.title(
'Passenger class')
plt.show()
输出结果:
示例:
femalehigh = data_train.Survived[data_train.Sex ==
'female'][data_train.Pclass !=
3].value_counts()
femalehigh.plot(kind=
'bar', label=
'female highclass', color=
'#FA2479')
plt.legend([
"female/highclass"],loc=
'best')
plt.show()
输出结果:
5.pyplot.subplot2grid()绘制子图函数
控制总的size与当前图的方位
plt
.subplot2grid((
2,
3),(
0,
0))
#设置2*3的子图,该图位置在(0,0)处
plt
.subplot2grid((
2,
3),(
0,
1))
plt
.subplot2grid((
2,
3),(
0,
2))
plt
.subplot2grid((
2,
3),(
1,
0), colspan=
2)
#设置所占列宽为2
pil
.subplot2grid((
2,
3),(
1,
2))
plt
.show()
大致形状如下
6.连续型变量计数函数
data_train.Age.plot(kind=
'kde')
plt.show()
输出结果:
同样根据DataFrame的特性,可以继续对特定类别计数
输出‘kde’密度曲线图
data_train.Age[data_train.Pclass ==
1].plot(kind=
'kde')
data_train.Age[data_train.Pclass ==
2].plot(kind=
'kde')
data_train.Age[data_train.Pclass ==
3].plot(kind=
'kde')
plt.xlabel(
"Age")
plt.ylabel(
"Density")
plt.title(
"Passenger's age for class")
plt.legend((
'First',
'Second',
'Third'),loc=
'best')
plt.show()
输出结果:
7.计数两个离散变量个数,并用DataFrame的’构造函数’
Survived_0 = data_train.Pclass[data_train.Survived ==
0].value_counts()
Survived_1 = data_train.Pclass[data_train.Survived ==
1].value_counts()
Survived_0
3 372
2 97
1 80
Name: Pclass, dtype: int64
df = pd.DataFrame({
'Survived':Survived_1,
'Unsurvived':Survived_0})
Survived Unsurvived
1 136 80
2 87 97
3 119 372
df.plot(kind =
'bar', stacked =
True)
输出结果:
8.DataFrame.groupby()函数
具体每个特征每个属性计数:
g = data_train.groupby([
'SibSp',
'Survived'])
df = pd.DataFrame(g.count())
g = data_train.groupby([
'SibSp',
'Survived',
'Pclass'])
df = pd.DataFrame(g.count()[
'PassengerId'])
df
9.从DataFrame中提取部分数据
sub_df = data_train[[
'Age',
'Fare',
'Parch',
'SibSp',
'Pclass']]
输出结果:
Age Fare Parch SibSp Pclass
0 22.000000 7.2500 0 1 3
1 38.000000 71.2833 0 1 1
2 26.000000 7.9250 0 0 3
3 35.000000 53.1000 0 1 1
4 35.000000 8.0500 0 0 3
5 23.828953 8.4583 0 0 3
6 54.000000 51.8625 0 0 1
7 2.000000 21.0750 1 3 3
8 27.000000 11.1333 2 0 3
9 14.000000 30.0708 0 1 2
10 4.000000 16.7000 1 1 3
11 58.000000 26.5500 0 0 1
12 20.000000 8.0500 0 0 3
13 39.000000 31.2750 5 1 3
14 14.000000 7.8542 0 0 3
15 55.000000 16.0000 0 0 2
16 2.000000 29.1250 1 4 3
17 32.066493 13.0000 0 0 2
18 31.000000 18.0000 0 1 3
19 29.518205 7.2250 0 0 3
20 35.000000 26.0000 0 0 2
10.DataFrame.as_matrix()
将DataFrame类型转换为matrix类型以便用于模型fit
known_age = age_df[age_df.Age.notnull()].as_matrix()
unknown_age = age_df[age_df.Age.isnull()].as_matrix()
y = known_age[:,
0]
X = known_age[:,
1:]
11.DataFrame.loc用于替换属性值
用法如下
df.loc[ (df.Age.isnull()),
'Age' ] = predictedAges
df.loc[ (df.Cabin.notnull()),
'Cabin' ] =
"Yes"
12.pandas.get_dummies()归一化函数
DataFrame类型的属性每个特征分出来命名,归一化
prefix即表示命名新属性的前缀
形成一个新的DataFrame
dummies_Cabin = pd.get_dummies(data_train[
'Cabin'], prefix=
'Cabin')
dummies_Cabin
输出结果:
13.pandas.concat()函数合并DataFrame
把几个DataFrame按照axis=0(index)axis =1(columns)合并形成新的df
df = pd.concat([data_train, dummies_Cabin, dummies_Embarked, dummies_Sex, dummies_Pclass], axis=
1)
输出结果:
14.DataFrame.drop()删去DataFrame某些属性
参数:
labels : single label or list-like
axis : int or axis name
level : int or level name, default None,For MultiIndex
inplace : bool, default False,If True, do operation inplace and return None
df.drop([
'Pclass',
'Name',
'Sex',
'Ticket',
'Cabin',
'Embarked'], axis=
1, inplace=
True)
15.利用sklearn中的preprocessing对连续型数据特征化scaling
各属性值之间scale差距太大,将对收敛速度造成很大影响!甚至不收敛!
所以我们将一些变化幅度较大的特征化到[-1,1]之内。
DataFrame添加属性列的操作直接写就好,eg:df[‘Age’]
import sklearn.preprocessing
as preprocessing
scaler = preprocessing.StandardScaler()
age_scale_param = scaler.fit(df[
'Age'])
df[
'Age_scaled'] = scaler.fit_transform(df[
'Age'], age_scale_param)
fare_scale_param = scaler.fit(df[
'Fare'])
df[
'Fare_scaled'] = scaler.fit_transform(df[
'Fare'], fare_scale_param)
df
16.利用filter()与正则表达式,从DataFrame中取出需要的属性值形成新的DataFrame
train_df = df.filter(regex=
'Survived|Age_.*|SibSp|Parch|Fare_.*|Cabin_.*|Embarked_.*|Sex_.*|Pclass_.*')
17.利用as_matrix()将DataFrame转换成可供numpy操作的list(矩阵)类型
train_np = train_df.as_matrix()
并完成切片化操作,形成特征矩阵X,y,用于下一步fit撸模型
y = train_np[:,
0]
X = train_np[:,
1:]
18.DataFrame的构造函数创建DataFrame
result = pd.DataFrame({
'PassengerId':data_test[
'PassengerId'].as_matrix(),
'Survived':predictions.astype(np.int32)})
输出结果:
19.DataFrame.to_csv()函数导出csv文件
result.to_csv(
"Titanic/logistic_regression_predictions.csv", index=
False)
index表示文件是否显示index
20.sklearn的cross_validation模块
利用模块中的cross_val_score()对分类器评分
from sklearn
import cross_validation
cross_vallidation.cross_val_score(clf, X, y,cv=
5)
输出结果:
[ 0.81564246 0.81564246 0.78651685 0.78651685 0.81355932]
21.cross_validation分割数据
按照7:3的比例将训练数据分成train数据,cv数据
split_train, split_cv = cross_validation.train_test_split(df, test_size=
0.3, random_state=
0)
进行预测
1.LogisticRegression
导入数据,相关模块(略去可视化分析过程)
import pandas
as pd
import numpy
as np
from pandas
import Series,DataFrame
data_train = pd.read_csv(
"Titanic/train.csv")
数据预处理
from sklearn.ensemble
import RandomForestRegressor
def set_missing_ages(df):
age_df = df[[
'Age',
'Fare',
'Parch',
'SibSp',
'Pclass']]
known_age = age_df[age_df.Age.notnull()].as_matrix()
unknown_age = age_df[age_df.Age.isnull()].as_matrix()
y = known_age[:,
0]
X = known_age[:,
1:]
rfr = RandomForestRegressor(random_state=
0, n_estimators=
2000, n_jobs=-
1)
rfr.fit(X, y)
predictedAges = rfr.predict(unknown_age[:,
1::])
df.loc[ (df.Age.isnull()),
'Age' ] = predictedAges
return df, rfr
def set_Cabin_type(df):
df.loc[ (df.Cabin.notnull()),
'Cabin' ] =
"Yes"
df.loc[ (df.Cabin.isnull()),
'Cabin' ] =
"No"
return df
data_train, rfr = set_missing_ages(data_train)
data_train = set_Cabin_type(data_train)
dummies_Cabin = pd.get_dummies(data_train[
'Cabin'], prefix=
'Cabin')
dummies_Embarked = pd.get_dummies(data_train[
'Embarked'], prefix=
'Embarked')
dummies_Sex = pd.get_dummies(data_train[
'Sex'], prefix=
'Sex')
dummies_Pclass = pd.get_dummies(data_train[
'Pclass'], prefix=
'Pclass')
df = pd.concat([data_train, dummies_Cabin, dummies_Embarked, dummies_Sex, dummies_Pclass], axis=
1)
df.drop([
'Pclass',
'Name',
'Sex',
'Ticket',
'Cabin',
'Embarked'], axis=
1, inplace=
True)
import sklearn.preprocessing
as preprocessing
scaler = preprocessing.StandardScaler()
age_scale_param = scaler.fit(df[
'Age'])
df[
'Age_scaled'] = scaler.fit_transform(df[
'Age'], age_scale_param)
fare_scale_param = scaler.fit(df[
'Fare'])
df[
'Fare_scaled'] = scaler.fit_transform(df[
'Fare'], fare_scale_param)
逻辑回归建模
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 = train_np[:,
0]
X = train_np[:,
1:]
clf = linear_model.LogisticRegression(C=
1.0, penalty=
'l1', tol=
1e-6)
clf.fit(X, y)
预处理测试数据
data_test = pd.read_csv(
"Titanic/test.csv")
data_test.loc[ (data_test.Fare.isnull()),
'Fare' ] =
0
tmp_df = data_test[[
'Age',
'Fare',
'Parch',
'SibSp',
'Pclass']]
null_age = tmp_df[data_test.Age.isnull()].as_matrix()
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(
"Titanic/logistic_regression_predictions.csv", index=
False)
查看拟合情况,判定一下当前模型所处状态(欠拟合or过拟合)
from sklearn.learning_curve
import learning_curve
def plot_learning_curve(estimator, title, X, y, ylim=None, cv=None, n_jobs=1,
train_sizes=np.linspace(.05, 1., 20), verbose=0, plot=True):
"""
画出data在某模型上的learning curve.
参数解释
----------
estimator : 你用的分类器。
title : 表格的标题。
X : 输入的feature,numpy类型
y : 输入的target vector
ylim : tuple格式的(ymin, ymax), 设定图像中纵坐标的最低点和最高点
cv : 做cross-validation的时候,数据分成的份数,其中一份作为cv集,其余n-1份作为training(默认为3份)
n_jobs : 并行的的任务数(默认1)
"""
train_sizes, train_scores, test_scores = learning_curve(
estimator, X, y, cv=cv, n_jobs=n_jobs, train_sizes=train_sizes, verbose=verbose)
train_scores_mean = np.mean(train_scores, axis=
1)
train_scores_std = np.std(train_scores, axis=
1)
test_scores_mean = np.mean(test_scores, axis=
1)
test_scores_std = np.std(test_scores, axis=
1)
if plot:
plt.figure()
plt.title(title)
if ylim
is not None:
plt.ylim(*ylim)
plt.xlabel(
'The number of training samples')
plt.ylabel(
'score')
plt.gca().invert_yaxis()
plt.grid()
plt.fill_between(train_sizes, train_scores_mean - train_scores_std, train_scores_mean + train_scores_std,
alpha=
0.1, color=
"b")
plt.fill_between(train_sizes, test_scores_mean - test_scores_std, test_scores_mean + test_scores_std,
alpha=
0.1, color=
"r")
plt.plot(train_sizes, train_scores_mean,
'o-', color=
"b", label=
'training score')
plt.plot(train_sizes, test_scores_mean,
'o-', color=
"r", label=
'CV score')
plt.legend(loc=
"best")
plt.draw()
plt.gca().invert_yaxis()
plt.show()
midpoint = ((train_scores_mean[-
1] + train_scores_std[-
1]) + (test_scores_mean[-
1] - test_scores_std[-
1])) /
2
diff = (train_scores_mean[-
1] + train_scores_std[-
1]) - (test_scores_mean[-
1] - test_scores_std[-
1])
return midpoint, diff
plot_learning_curve(clf,
'learning curves', X, y)
在实际数据上看,我们得到的learning curve没有理论推导的那么光滑哈,但是可以大致看出来,训练集和交叉验证集上的得分曲线走势还是符合预期的。
目前的曲线看来,我们的model并不处于overfitting的状态(overfitting的表现一般是训练集上得分高,
而交叉验证集上要低很多,中间的gap比较大)。因此我们可以再做些feature engineering的工作,添加一些新产出的特征或者组合特征到模型中。
看看相关程度
pd.DataFrame({
"columns":list(train_df.columns)[
1:],
"coef":list(clf.coef_.T)})
上面的系数和最后的结果是一个正相关的关系
我们先看看那些权重绝对值非常大的feature,在我们的模型上:
•Sex属性,如果是female会极大提高最后获救的概率,而male会很大程度拉低这个概率。
•Pclass属性,1等舱乘客最后获救的概率会上升,而乘客等级为3会极大地拉低这个概率。
•有Cabin值会很大程度拉升最后获救概率(这里似乎能看到了一点端倪,事实上从最上面的有无Cabin记录的Survived分布图上看出,即使有Cabin记录的乘客也有一部分遇难了,估计这个属性上我们挖掘还不够)
•Age是一个负相关,意味着在我们的模型里,年龄越小,越有获救的优先权(还得回原数据看看这个是否合理)
•有一个登船港口S会很大程度拉低获救的概率,另外俩港口压根就没啥作用(这个实际上非常奇怪,因为我们从之前的统计图上并没有看到S港口的获救率非常低,所以也许可以考虑把登船港口这个feature去掉试试)。
•船票Fare有小幅度的正相关(并不意味着这个feature作用不大,有可能是我们细化的程度还不够,举个例子,说不定我们得对它离散化,再分至各个乘客等级上?)
怎么样才知道,哪些优化的方法是promising的呢?
进行交叉验证
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:])
origin_data_train = pd.read_csv(
"Titanic/Train.csv")
bad_cases=origin_data_train.loc[origin_data_train[
'PassengerId'].isin(split_cv[predictions != cv_df.as_matrix()[:,
0]][
'PassengerId'].values)]
bad_cases
对比bad case,我们仔细看看我们预测错的样本,到底是哪些特征有问题,咱们处理得还不够细?
我们随便列一些可能可以做的优化操作:
•Age属性不使用现在的拟合方式,而是根据名称中的『Mr』『Mrs』『Miss』等的平均值进行填充。
•Age不做成一个连续值属性,而是使用一个步长进行离散化,变成离散的类目feature。
•Cabin再细化一些,对于有记录的Cabin属性,我们将其分为前面的字母部分(我猜是位置和船层之类的信息) 和 后面的数字部分(应该是房间号,有意思的事情是,如果你仔细看看原始数据,你会发现,这个值大的情况下,似乎获救的可能性高一些)。
•Pclass和Sex俩太重要了,我们试着用它们去组出一个组合属性来试试,这也是另外一种程度的细化。
•单加一个Child字段,Age<=12的,设为1,其余为0(你去看看数据,确实小盆友优先程度很高啊)
•如果名字里面有『Mrs』,而Parch>1的,我们猜测她可能是一个母亲,应该获救的概率也会提高,因此可以多加一个Mother字段,此种情况下设为1,其余情况下设为0
•登船港口可以考虑先去掉试试(Q和C本来就没权重,S有点诡异)
•把堂兄弟/兄妹 和 Parch 还有自己 个数加在一起组一个Family_size字段(考虑到大家族可能对最后的结果有影响)
•Name是一个我们一直没有触碰的属性,我们可以做一些简单的处理,比如说男性中带某些字眼的(‘Capt’, ‘Don’, ‘Major’, ‘Sir’)可以统一到一个Title,女性也一样。
大家接着往下挖掘,可能还可以想到更多可以细挖的部分。我这里先列这些了,然后我们可以使用手头上的”train_df”和”cv_df”开始试验这些feature engineering的tricks是否有效了。
分析后优化代码
ata_train = pd.read_csv(
"Titanic/Train.csv")
data_train[
'Sex_Pclass'] = data_train.Sex +
"_" + data_train.Pclass.map(str)
from sklearn.ensemble
import RandomForestRegressor
def set_missing_ages(df):
age_df = df[[
'Age',
'Fare',
'Parch',
'SibSp',
'Pclass']]
known_age = age_df[age_df.Age.notnull()].as_matrix()
unknown_age = age_df[age_df.Age.isnull()].as_matrix()
y = known_age[:,
0]
X = known_age[:,
1:]
rfr = RandomForestRegressor(random_state=
0, n_estimators=
2000, n_jobs=-
1)
rfr.fit(X, y)
predictedAges = rfr.predict(unknown_age[:,
1::])
df.loc[ (df.Age.isnull()),
'Age' ] = predictedAges
return df, rfr
def set_Cabin_type(df):
df.loc[ (df.Cabin.notnull()),
'Cabin' ] =
"Yes"
df.loc[ (df.Cabin.isnull()),
'Cabin' ] =
"No"
return df
data_train, rfr = set_missing_ages(data_train)
data_train = set_Cabin_type(data_train)
dummies_Cabin = pd.get_dummies(data_train[
'Cabin'], prefix=
'Cabin')
dummies_Embarked = pd.get_dummies(data_train[
'Embarked'], prefix=
'Embarked')
dummies_Sex = pd.get_dummies(data_train[
'Sex'], prefix=
'Sex')
dummies_Pclass = pd.get_dummies(data_train[
'Pclass'], prefix=
'Pclass')
dummies_Sex_Pclass = pd.get_dummies(data_train[
'Sex_Pclass'], prefix=
'Sex_Pclass')
df = pd.concat([data_train, dummies_Cabin, dummies_Embarked, dummies_Sex, dummies_Pclass, dummies_Sex_Pclass], axis=
1)
df.drop([
'Pclass',
'Name',
'Sex',
'Ticket',
'Cabin',
'Embarked',
'Sex_Pclass'], axis=
1, inplace=
True)
import sklearn.preprocessing
as preprocessing
scaler = preprocessing.StandardScaler()
age_scale_param = scaler.fit(df[
'Age'])
df[
'Age_scaled'] = scaler.fit_transform(df[
'Age'], age_scale_param)
fare_scale_param = scaler.fit(df[
'Fare'])
df[
'Fare_scaled'] = scaler.fit_transform(df[
'Fare'], fare_scale_param)
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 = train_np[:,
0]
X = train_np[:,
1:]
clf = linear_model.LogisticRegression(C=
1.0, penalty=
'l1', tol=
1e-6)
clf.fit(X, y)
data_test = pd.read_csv(
"Titanic/test.csv")
data_test.loc[ (data_test.Fare.isnull()),
'Fare' ] =
0
data_test[
'Sex_Pclass'] = data_test.Sex +
"_" + data_test.Pclass.map(str)
tmp_df = data_test[[
'Age',
'Fare',
'Parch',
'SibSp',
'Pclass']]
null_age = tmp_df[data_test.Age.isnull()].as_matrix()
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')
dummies_Sex_Pclass = pd.get_dummies(data_test[
'Sex_Pclass'], prefix=
'Sex_Pclass')
df_test = pd.concat([data_test, dummies_Cabin, dummies_Embarked, dummies_Sex, dummies_Pclass, dummies_Sex_Pclass], axis=
1)
df_test.drop([
'Pclass',
'Name',
'Sex',
'Ticket',
'Cabin',
'Embarked',
'Sex_Pclass'], 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_predictions2.csv", index=
False)
Bagging算法优化模型
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 = train_np[:,
0]
X = train_np[:,
1:]
clf = linear_model.LogisticRegression(C=
1.0, penalty=
'l1', tol=
1e-6)
bagging_clf = BaggingRegressor(clf, n_estimators=
10, 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)
result = pd.DataFrame({
'PassengerId':data_test[
'PassengerId'].as_matrix(),
'Survived':predictions.astype(np.int32)})
result.to_csv(
"Titanic/logistic_regression_predictions2.csv", index=
False)
提交效果:
问题经验总结
EDA过程中了解属性,以及数据可视化是很重要的
1.数据探索导入数据为DataFrame格式
df.info()
查看数据属性,非空数据个数,数据类型
df.describe()
查看连续型数据均值四分位值,中值,标准差
2.对数据的认识非常重要,利用自己的一些先验知识,可以大致确定一下属性的影响程度
3.绘制每个属性与待预测属性的数量条形图,来分析数据相关程度
数据预处理
4.处理missing value
如果missing value占总体的比例非常小,那么直接填入平均值或者众数
如果missing value所占比例不算小也不算大,那么可以考虑它跟其他特征的关系,如果关系明显,那么直接根据其他特征填入;也可以建立简单的模型,比如线性回归,随机森林等。
如果missing value所占比例大,那么直接将miss value当做一种特殊的情况,另取一个值填入
如果missing value占总数比例极高,我们可能就直接舍弃了,作为特征加入的话,可能反倒带入noise,影响最后的结果了
5.处理categorical feature
一般就是通过dummy variable的方式解决
如果特征中包含大量需要做dummy variable处理的,那么很可能导致得到一个稀疏的dataframe,这时候最好用下PCA做降维处理。
如果某个特征有好几万个取值,那么用dummy variable就并不现实了,这时候可以用Count-Based Learning.
在kaggle案例中发现,对于类别特征,在模型中加入tf-idf总是有效果的。
还有个方法叫“Leave-one-out” encoding,也可以处理类别特征种类过多的问题,实测效果不错。
6.特征工程
可以说最后结果的好坏,大部分就是由特征工程决定的,剩下部分应该是调参和Ensemble决定。
特征工程的好坏主要是由domain knowledge决定的
feature selection有很多方法,比如backward,forward selection,random forest的feature importance.
7.选择模型
最常用的模型是Ensemble Model,比如 Random Forest,Gradient Boosting。当然在开始的时候,可以用点简单的模型,一方面是可以作为底线threshold,另一方面也可以在最后作为Ensemble Model。
也可以使用xgboost
8.调参
每种模型都有自己最关键的几个参数
sklearn中GridSearchCV可以设置需要比较的几种参数组合,然后用cross validation来选出最优秀的参数组合。
大致用法如下
from sklearn.grid_search
import GridSearchCV
from pprint
import pprint
clf=RandomForestClassifier(random_state=seed)
parameters = {
'n_estimators': [
300,
500],
'max_features':[
4,
5,
'auto']}
grid_search = GridSearchCV(estimator=clf,param_grid=parameters, cv=
10, scoring=
'accuracy')
print(
"parameters:")
pprint(parameters)
grid_search.fit(train_x,train_y)
print(
"Best score: %0.3f" % grid_search.best_score_)
print(
"Best parameters set:")
best_parameters=grid_search.best_estimator_.get_params()
for param_name
in sorted(parameters.keys()):
print(
"\t%s: %r" % (param_name, best_parameters[param_name]))
9.Model ensemble
Model Ensemble有Bagging,Boosting,Stacking,其中Bagging和Boosting都算是Bootstraping的应用。Bootstraping的概念是对样本每次有放回的抽样,抽样K个,一共抽N次。
Bagging:每次从总体样本中随机抽取K个样本来训练模型,重复N次,得到N个模型,然后将各个模型结果合并,分类问题投票方式结合,回归则是取平均值,e.g.Random Forest。
Boosting:一开始给每个样本取同样的权重,然后迭代训练,每次对训练失败的样本调高其权重。最后对多个模型用加权平均来结合,e.g. GBDT。
Bagging与Boosting的比较:在深入理解Bagging和Boosting后发现,bagging其实是用相同的模型来训练随机抽样的数据,这样的结果是各个模型之间的bias差不多,variance也差不多,通过平均,使得variance降低(由算平均方差的公式可知),从而提高ensemble model的表现。而Boosting其实是一种贪心算法,不断降低bias。
Stacking: 训练一个模型来组合其他各个模型。首先先训练多个不同的模型,然后再以之前训练的各个模型的输出为输入来训练一个模型,以得到一个最终的输出。使用过stacking之后,发现其实stacking很像神经网络,通过很多模型的输出,构建中间层,最后用逻辑回归讲中间层训练得到最后的结果。
10.模型系数关联分析
做完baseline模型后,把得到的model系数和feature关联起来看看。
pd.DataFrame({
"columns":list(train_df.columns)[
1:],
"coef":list(clf.coef_.T)})
这些系数为正的特征,和最后结果是一个正相关,反之为负相关。
11.交叉验证
对模型进行评分
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)
输出每个fold的评分结果
12.交叉验证之后,分析bad case很关键
可能会得到一些结论,来进行下一步数据特征探索
可能的想法:
Age属性不使用现在的拟合方式,而是根据名称中的『Mr』『Mrs』『Miss』等的平均值进行填充。 Age不做成一个连续值属性,而是使用一个步长进行离散化,变成离散的类目feature。 Cabin再细化一些,对于有记录的Cabin属性,我们将其分为前面的字母部分(我猜是位置和船层之类的信息) 和 后面的数字部分(应该是房间号,有意思的事情是,如果你仔细看看原始数据,你会发现,这个值大的情况下,似乎获救的可能性高一些)。 Pclass和Sex俩太重要了,我们试着用它们去组出一个组合属性来试试,这也是另外一种程度的细化。 单加一个Child字段,Age<=12的,设为1,其余为0(你去看看数据,确实小盆友优先程度很高啊) 如果名字里面有『Mrs』,而Parch>1的,我们猜测她可能是一个母亲,应该获救的概率也会提高,因此可以多加一个Mother字段,此种情况下设为1,其余情况下设为0 登船港口可以考虑先去掉试试(Q和C本来就没权重,S有点诡异) 把堂兄弟/兄妹 和 Parch 还有自己 个数加在一起组一个Family_size字段(考虑到大家族可能对最后的结果有影响) Name是一个我们一直没有触碰的属性,我们可以做一些简单的处理,比如说男性中带某些字眼的(‘Capt’, ‘Don’, ‘Major’, ‘Sir’)可以统一到一个Title,女性也一样。
13.想法验证
使用手头上的”train_df”和”cv_df”开始试验这些feature engineering的tricks是否有效了。
试验的过程比较漫长,也需要有耐心,而且我们经常会面临很尴尬的状况,就是我们灵光一闪,想到一个feature,然后坚信它一定有效,结果试验下来,效果还不如试验之前的结果。恩,需要坚持和耐心,以及不断的挖掘。
我最好的结果是在『Survived~C(Pclass)+C(Title)+C(Sex)+C(Age_bucket)+C(Cabin_num_bucket)Mother+Fare+Family_Size』下取得的
14.learning curves验证模型是否欠拟合或过拟合