二、引用kaggle上面的入门例子,Titanic的数据学习,是kaggle网站上分享的代码,我基本上是将它翻译过来了,原网址: https://www.kaggle.com/omarelgabry/titanic/a-journey-through-titanic python版本:我装的是anaconda,里面有了各种包,但是没有seaborn包,使用pip install seaborn 安装或者conda install seaborn。
2、我觉得最难的是: ①有一个统计学的底蕴,能够对数据充满敏感,对于数据分布有一定的感知能力,这就需要对各种数据分布非常了解。 ②在数据字段操作的时候,要同时操作train和test两个集合,以便在建模时候的变量准确。 ③对于sklearn中各个模型和模型的使用都有一定的了解。
3、在我实习时,数据处理用R来写的,在查看每个变量的分布之前,有对数据进行很粗糙的处理,比如: _集中度、缺失度、因子水平、iv值 _ ,这些变量如果达不到一定的硬性标准,脚本会自动删除这些变量,不需要查看变量的分布就可以做到。 我觉得这个可以作为数据处理的标准化流程之一,一定要谨记!!! 三、代码: 1、数据准备和加载: ①首先引入包
from pandas import DataFrame
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_style(\'whitegrid\')
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble importRandomForestClassifier
引入了pandas中的DataFrame对象,numpy包,matplotlib包,seaborn包,还有sklearn包的逻辑回归模型和随机森林分类器,sklearn中的子包和文档需要仔细研究、、
②加载并查看数据:
titanic_df=pd.read_csv(\'C:\\Datemining\\tatannic\\train.csv\', dtype={"Age": np.float64}, )
test_df=pd.read_csv(\'C:\\Datemining\\tatannic\\test.csv\', dtype={"Age": np.float64}, )
titanic_df.head()
titanic_df.info()
print("----------------------------")
test_df.info()
titanic_df = titanic_df.drop([\'PassengerId\',\'Name\',\'Ticket\'], axis=1)
test_df = test_df.drop([\'Name\',\'Ticket\'], axis=1)
用pandas.read_csv()方法读入本地的csv格式的train和test文件(R语言写法为read.csv()),读入后数据的类型默认是DataFrame,用DataFrame.head()方法得到它的前几行,用DataFrame.info()方法得到它的列变量信息。
将train的\'PassengerId\',\'Name\',\'Ticket\'这三列删除,test删除\'Name\',\'Ticket\'列。
train和test的变量信息分别如下:
<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
----------------------------
<class \'pandas.core.frame.DataFrame\'>
RangeIndex: 418 entries, 0 to 417
Data columns (total 11 columns):
PassengerId 418 non-null int64
Pclass 418 non-null int64
Name 418 non-null object
Sex 418 non-null object
Age 332 non-null float64
SibSp 418 non-null int64
Parch 418 non-null int64
Ticket 418 non-null object
Fare 417 non-null float64
Cabin 91 non-null object
Embarked 418 non-null object
dtypes: float64(2), int64(4), object(5)
memory usage: 27.8+ KB
用DataFrame.shape属性可以查看数据框的大小,删除了三列变量后train的大小是一个891×9的数据框。
titanic_df.shape
(891, 9)
2、变量探索: ①‘Embarked’字段,我觉得翻译过来应该称“乘船类型” 数据框引用某一列有两种方式,一个是用.引用,一个是[ ]引用,个人倾向于第一个,更像面向对象的引用方式。(如果是R语言,用dataframe$Embarked引用) 统计得到train数据中Embarked非空值,用count()函数,可以看出Embarked有两个空值
titanic_df.Embarked.count()
Out[16]: 889
或者:
titanic_df[\'Embarked\'].count()
Out[19]: 889
可以查看第哪几个记录是空值:
titanic_df.Embarked[titanic_df.Embarked.isnull()]
Out[8]:
61 NaN
829 NaN
Name: Embarked, dtype: object
isnull() 会返回一个值是boolean的Series序列,在引用时候返回值是ture的值(R语言会写成 titanic_df$Embarked[which(titanic_df$Embarked==NA)] 可以看到61和829条记录是空值,只有两个是空。 可以用groupby方法大致统计一下,Embarked的取值情况:
titanic_df.groupby(\'Embarked\').Survived.count()
>Out[13]:
Embarked
C 168
Q 77
S 646
Name: Survived, dtype: int64
可以看出Embarked取值只有3个值,每个值对应的人数有统计量,发现基本上大部分取值都是\'S\',即顾客。因此将两个空值用出现次数最多的\'S\'来填补
(如果是数值int类型,并且确实率在可接受范围内(<20%)可以用均值、中位数来填补)
titanic_df["Embarked"] = titanic_df["Embarked"].fillna("S")
把Embarked这个变量画出来,看一下它的大致分布和样子,初步判断应该做怎样的筛选:
sns.catplot(\'Embarked\',\'Survived\',data=titanic_df,height=3,aspect=3)
使用了seaborn中的factorplot函数,产看它的文档发现factorplot()函数的图像的kind参数可以设为:violin、strip、bar、box。可以下去试一下,个人觉得kind=\'violin\'是最容易看出它的分布和人数情况,也是最有用的!
下面这句话定义了一个fig图和它对应的三个子图axis1,axis2,axis3,
fig, (axis1,axis2,axis3) = plt.subplots(1,3,figsize=(15,5))
可以将它拆分为四句话:
fig=plt.figure(figsize=(15,5))
axis1=fig.add_subplot(1,3,1)
axis2=fig.add_subplot(1,3,2)
axis2=fig.add_subplot(1,3,3)
第一种写法更精炼! 延伸一下,在使用matplotlib的pyplot的figure定义图像时候,如果统一定义坐标轴的名称用plt的属性,例如:
import matplotlib.pyplot as plt
fig=plt.figure(figsize=(10,5))
fig.title(\'testdata\')
fig.xlabel(\'age\')
fig.ylabel(\'survived\')
plt.show()
如果单独定义每个头像的坐标轴和title:
axis1=fig.add_subplot(131)
axis1.set_xlabel(\'age\')
axis1.set_ylabel(\'survived\')
temp1.plot()
temp1是一个DataFrame,只要plot()就默认为占用这个axis1
经过初步统计和factorplot函数的画图后,大致对Embarked这个变量的分布情况有了一定的了解,因为定义了一个fig里面有三个子图,接下来就是对3个子图的填充:
sns.countplot(x=\'Embarked\', data=titanic_df, ax=axis1)
sns.countplot(x=\'Survived\', hue="Embarked", data=titanic_df, order=[1,0], ax=axis2)
上面两行分别填充fig的前两个图,axis1对Embarked的三个取值进行统计,axis2对Survived的取值做统计; 下面是构造了一个embark_perc数据框计算它的三个取值的均值。
embark_perc = titanic_df[[\'Embarked\',\'Survived"]].groupby([\'Embarked\'],as_index=False).mean()
sns.barplot(x=\'Embarked\', y=\'Survived\', data=embark_perc,order=[\'S\',\'C\',\'Q\'],ax=axis3)
titanic_df[[\'Embarked\',\'Survived"]].groupby([\'Embarked\'] 相当于sql语句中的groupby函数,mean()函数对它计算均值后,生成了一个数据框DataFrame。(图就不上传了)
使用pd.get_dummies()方法得到Embarked这个变量的指标,然后train和test分别右连接这个统计指标表,会产生三个新的变量:‘S’,‘C’,‘Q’。 可能连接后’S’变量贡献度太小,删除’S’这个变量,保留’C’,‘Q’,而且很显然这两列的值都是0或1的标签。
embark_dummies_titanic = pd.get_dummies(titanic_df[\'Embarked\'])
embark_dummies_titanic.drop([\'S\'], axis=1, inplace=True)
embark_dummies_test = pd.get_dummies(test_df[\'Embarked\'])
embark_dummies_test.drop([\'S\'], axis=1, inplace=True)
titanic_df = titanic_df.join(embark_dummies_titanic)
test_df = test_df.join(embark_dummies_test)
titanic_df.drop([\'Embarked\'], axis=1,inplace=True)
test_df.drop([\'Embarked\'], axis=1,inplace=True)
将原来的Emabrked这个变量删除:
titanic_df.drop([\'Embarked\'], axis=1,inplace=True)
test_df.drop([\'Embarked\'], axis=1,inplace=True)
注:删除时候,要对train和test数据都做一样的处理。不能忘了、、
①‘Fare’字段:票价 如果变量是数值类型,可以用describe方法查看统计特性:
test_df.Fare.describe()
>Out[7]:
count 417.000000
mean 35.627188
std 55.907576
min 0.000000
25% 7.895800
50% 14.454200
75% 31.500000
max 512.329200
Name: Fare, dtype: float64
test_df.shape
>Out[5]: (418, 10)
test_df.Fare.count()
>Out[6]: 417
发现test数据中有一个Fare变量是空值,用fillna()方法填充中值:
test_df["Fare"].fillna(test_df["Fare"].median(), inplace=True)
数据处理转换,将float转换成int类型:
titanic_df[\'Fare\'] = titanic_df[\'Fare\'].astype(int)
test_df[\'Fare\'] = test_df[\'Fare\'].astype(int)
分别得到Fare变量对应的幸存和没有幸存的记录,(这种引用很像R语言中的which()函数):
fare_not_survived = titanic_df["Fare"][titanic_df["Survived"] == 0]
fare_survived = titanic_df["Fare"][titanic_df["Survived"] == 1]
转换成数据框DataFrame,并作图出来:
avgerage_fare = DataFrame([fare_not_survived.mean(), fare_survived.mean()])
std_fare = DataFrame([fare_not_survived.std(), fare_survived.std()])
频率直方图:
titanic_df[\'Fare\'].plot(kind=\'hist\', figsize=(10,3),bins=100, xlim=(0,50))
注:直接调用plot()也是一种简单画图方法,与matplotlib.pyplot中面向对象画图一样,需要研究、、
avgerage_fare.index.names = std_fare.index.names = ["Survived"]
avgerage_fare.plot(yerr=std_fare,kind=\'bar\',legend=False)
③Age变量:年龄 面向对象画图,两个图,分别设置title:
fig, (axis1,axis2) = plt.subplots(1,2,figsize=(15,4))
axis1.set_title(\'Original Age values - Titanic\')
axis2.set_title(\'New Age values - Titanic\')
分别得到train和test年龄的平均数,方差,空值的数量:
average_age_titanic = titanic_df["Age"].mean()
std_age_titanic = titanic_df["Age"].std()
count_nan_age_titanic = titanic_df["Age"].isnull().sum()
average_age_test = test_df["Age"].mean()
std_age_test = test_df["Age"].std()
count_nan_age_test = test_df["Age"].isnull().sum()
随机制造count_nan_age_test 个年龄,然后填充到空值中(这个方法需要谨记,很有用!!!用到的是numpy包的可迭代序列):
rand_1 = np.random.randint(average_age_titanic - std_age_titanic, average_age_titanic + std_age_titanic, size = count_nan_age_titanic)
rand_2 = np.random.randint(average_age_test - std_age_test, average_age_test + std_age_test, size = count_nan_age_test)
titanic_df[\'Age\'].dropna().astype(int).hist(bins=70, ax=axis1)
titanic_df["Age"][np.isnan(titanic_df["Age"])] = rand_1
test_df["Age"][np.isnan(test_df["Age"])] = rand_2
用下面这段代码替换上面的代码不行,提示是Series不能hash:
rand_1 = Series(np.random.randint(average_age_titanic - std_age_titanic, average_age_titanic + std_age_titanic, size = count_nan_age_titanic))
rand_2 = Series(np.random.randint(average_age_test - std_age_test, average_age_test + std_age_test, size = count_nan_age_test))
titanic_df["Age"][titanic_df["Age"].isnull()]=rand_1
test_df["Age"][test_df["Age"].isnull]=rand_2
将年龄转换为int:
titanic_df[\'Age\'] = titanic_df[\'Age\'].astype(int)
test_df[\'Age\'] = test_df[\'Age\'].astype(int)
作图:
titanic_df[\'Age\'].hist(bins=70, ax=axis1)
titanic_df[\'Age\'].hist(bins=70, ax=axis2)
继续作图,seaborn的FaceGrid()方法,需要查一下、
facet = sns.FacetGrid(titanic_df, hue="Survived",aspect=4)
facet.map(sns.kdeplot,\'Age\',shade= True)
facet.set(xlim=(0, titanic_df[\'Age\'].max()))
facet.add_legend()
每个年龄的存活率:
fig, axis1 = plt.subplots(1,1,figsize=(18,4))
average_age = titanic_df[["Age", "Survived"]].groupby([\'Age\'],as_index=False).mean()
sns.barplot(x=\'Age\', y=\'Survived\', data=average_age)
④Cabin变量:船舱号
titanic_df.shape
>Out[4]: (891, 12)
titanic_df.Cabin.count()
>Out[5]: 204
titanic_df.drop("Cabin",axis=1,inplace=True)
test_df.drop("Cabin",axis=1,inplace=True)
可以看到,总共891个记录,只有204个记录是非空的,而且它是一个字符型的,所以这个变量被删除了。
⑤整合Parch和SibSp变量(不太明白这两个变量的中文意思…) 将Parch和SibSp变量整合为一个Famliy变量,作为一个取值为0和1的标签变量。
titanic_df.Parch.describe()
>Out[15]:
count 891.000000
mean 0.381594
std 0.806057
min 0.000000
25% 0.000000
50% 0.000000
75% 0.000000
max 6.000000
Name: Parch, dtype: float64
titanic_df.Parch[titanic_df.Parch!=0].count()
>Out[14]: 213
titanic_df.SibSp[titanic_df.SibSp!=0].count()
>Out[17]: 283
可以发现,两者只有极少数不是0值,故:
titanic_df[\'Family\'] = titanic_df["Parch"] + titanic_df["SibSp"]
titanic_df[\'Family\'].loc[titanic_df[\'Family\'] > 0] = 1
titanic_df[\'Family\'].loc[titanic_df[\'Family\'] == 0] = 0
test_df[\'Family\'] = test_df["Parch"] + test_df["SibSp"]
test_df[\'Family\'].loc[test_df[\'Family\'] > 0] = 1
test_df[\'Family\'].loc[test_df[\'Family\'] == 0] = 0
删除这两列:
titanic_df = titanic_df.drop([\'SibSp\',\'Parch\'], axis=1)
test_df = test_df.drop([\'SibSp\',\'Parch\'], axis=1)
画图:
fig, (axis1,axis2) = plt.subplots(1,2,sharex=True,figsize=(10,5))
sns.countplot(x=\'Family\', data=titanic_df, order=[1,0], ax=axis1)
计算幸存的人平均有几个家人:
family_perc = titanic_df[["Family", "Survived"]].groupby([\'Family\'],as_index=False).mean()
sns.barplot(x=\'Family\', y=\'Survived\', data=family_perc, order=[1,0], ax=axis2)
axis1.set_xticklabels(["With Family","Alone"], rotation=0)
seaborn里的countplot()方法和barplot()方法。
⑥整合变量Sex: 定义一个函数来判断age是否超过16岁,对其进行分类,小于16岁分类为’child’,大于16岁保留性别:
def get_person(passenger):
age,sex = passenger
return \'child\' if age < 16 else sex
新建的变量名为Person:,用apply()函数对train和test数据分类(像R中的apply):
titanic_df[\'Person\'] = titanic_df[[\'Age\',\'Sex\']].apply(get_person,axis=1)
test_df[\'Person\'] = test_df[[\'Age\',\'Sex\']].apply(get_person,axis=1)
删除Sex变量
titanic_df.drop([\'Sex\'],axis=1,inplace=True)
test_df.drop([\'Sex\'],axis=1,inplace=True)
达到变量的指标,并将它们的columns换成\'Child\',\'Female\',\'Male\'
person_dummies_titanic = pd.get_dummies(titanic_df[\'Person\'])
person_dummies_titanic.columns = [\'Child\',\'Female\',\'Male\']
person_dummies_titanic.drop([\'Male\'], axis=1, inplace=True)
person_dummies_test = pd.get_dummies(test_df[\'Person\'])
person_dummies_test.columns = [\'Child\',\'Female\',\'Male\']
person_dummies_test.drop([\'Male\'], axis=1, inplace=True)
titanic_df = titanic_df.join(person_dummies_titanic)
test_df = test_df.join(person_dummies_test)
定义图,作图:
fig, (axis1,axis2) = plt.subplots(1,2,figsize=(10,5))
sns.countplot(x=\'Person\', data=titanic_df, ax=axis1)
person_perc = titanic_df[["Person", "Survived"]].groupby([\'Person\'],as_index=False).mean()
sns.barplot(x=\'Person\', y=\'Survived\', data=person_perc, ax=axis2, order=[\'male\',\'female\',\'child\'])
效果不明显,最后删了它:
titanic_df.drop([\'Person\'],axis=1,inplace=True)
test_df.drop([\'Person\'],axis=1,inplace=True)
⑦Pclass变量:等级
sns.factorplot(\'Pclass\',\'Survived\',order=[1,2,3], data=titanic_df,size=5)
# create dummy variables for Pclass column, & drop 3rd class as it has the lowest average of survived passengers
将Pclass的三个取值做成标签,并删除train和test中的class_3变量,因为它的幸存率太低了!
pclass_dummies_titanic = pd.get_dummies(titanic_df[\'Pclass\'])
pclass_dummies_titanic.columns = [\'Class_1\',\'Class_2\',\'Class_3\']
pclass_dummies_titanic.drop([\'Class_3\'], axis=1, inplace=True)
pclass_dummies_test = pd.get_dummies(test_df[\'Pclass\'])
pclass_dummies_test.columns = [\'Class_1\',\'Class_2\',\'Class_3\']
pclass_dummies_test.drop([\'Class_3\'], axis=1, inplace=True)
titanic_df.drop([\'Pclass\'],axis=1,inplace=True)
test_df.drop([\'Pclass\'],axis=1,inplace=True)
titanic_df = titanic_df.join(pclass_dummies_titanic)
test_df = test_df.join(pclass_dummies_test)
⑧数据探索结束,将train和test的变量化为统一:
X_train = titanic_df.drop("Survived",axis=1)
Y_train = titanic_df["Survived"]
X_test = test_df.drop("PassengerId",axis=1).copy()
三、建立模型 此时应用sklearn包了: ①用逻辑回归去拟合X_train和Y_train,然后用logreg.predict()函数去预测X_test的数据,最后用拟合的结果去给模型打分!
logreg = LogisticRegression()
logreg.fit(X_train, Y_train)
Y_pred = logreg.predict(X_test)
logreg.score(X_train, Y_train)
②随机森林:
random_forest = RandomForestClassifier(n_estimators=100)
random_forest.fit(X_train, Y_train)
Y_pred = random_forest.predict(X_test)
random_forest.score(X_train, Y_train)
四、相关分析(不懂!!):
coeff_df = DataFrame(titanic_df.columns.delete(0))
coeff_df.columns = [\'Features\']
coeff_df["Coefficient Estimate"] = pd.Series(logreg.coef_[0])
五、生成csv,提交文件: 先构造一个数据框DataFrame
submission = pd.DataFrame({
"PassengerId": test_df["PassengerId"],
"Survived": Y_pred
})
再将其写成一个csv文件:
submission.to_csv(\'titanic.csv\', index=False)
至于,加标签后的准确率就是你排名高低的依据了,如果变量控制的好,无效变量少,那么你的得分率肯定是很高的,如果你建立模型的时候无效的变量 很多,那拟合出的结果肯定不理想,同时,你也需要比较各种不同模型,选择一个建立模型后的score最高的一个模型提交。