#titanic

import numpy as np
import pandas as pd ##读取查看数据
from sklearn.tree import DecisionTreeClassifier ##决策树
import matplotlib.pyplot as plt ##绘图
from sklearn.model_selection import GridSearchCV,train_test_split,cross_val_score ##网格搜索调参

###读入数据
data=pd.read_csv("./data/train.csv")

###查看数据
print(data.head(0))##数据前几行,默认前五行
print(data.tail())##数据后几行,默认后五行
print(data.info())##数据信息

###数据预处理
#1.删除无关列
#data=data.drop(['Cabin','Name','Ticket'],axis=1)#inplace默认为false,是否覆盖原表
data.drop(['Cabin','Name','Ticket'],inplace=True,axis=1)#axis=1,删除列;axis=0,删除行
print(data.info())

#2.处理缺失值(填补和删除)
data['Age']=data['Age'].fillna(data['Age'].mean())##填补缺失值fillna,用均值填补*.mean()
print(data.info())

data=data.dropna(axis=0)#删除有缺失值的行dropna
print(data.info())

#3.将非数值类型数据转换成数值
print(data.head(5))
print(type(data['Embarked'].unique()))##查看Embarked数据的种类,以数组形式(numpy.ndarray)返回列的所有唯一值

labels=data['Embarked'].unique().tolist()##将数组转换成列表形式存入labels中
data["Embarked"]=data['Embarked'].apply(lambda x:labels.index(x))#lambda函数也叫匿名函数,即没有具体名称的函数,它允许快速定义单行函数,可以用在任何需要函数的地方
                                                                  #lambda原型为:lambda 参数:操作(参数)
                                                                  #apply函数的格式为:apply(func,*args,**kwargs),kwargs是一个包含关键字参数的字典
                                                                  #当一个函数的参数存在于一个元组或者一个字典中时,用来间接的调用apply这个函数,并肩元组或者字典中的参数按照顺序传递给参数
print(data.head(5))

data['Sex']=(data['Sex']=='male').astype('int')#先将sex转换成true/false,再转换成0/1
print(data.head(5))

#4.将特征和标签分开
x=data.iloc[:,data.columns!='Survived']
y=data.iloc[:,data.columns=='Survived']

xtrain,xtest,ytrain,ytest=train_test_split(x,y,test_size=0.3)

print(xtrain.head(5))#索引顺序变乱

#将index索引重新编号
#xtrain.index=range(xtrain.shape[0])
for i in [xtrain,xtest,ytrain,ytest]:
    i.index=range(i.shape[0])

print(xtrain.head(5))

##5.训练模型
clf=DecisionTreeClassifier(random_state=25)
clf=clf.fit(xtrain,ytrain)
score=clf.score(xtest,ytest)

print(score)

#10次交叉验证
clf=DecisionTreeClassifier(random_state=25)
score=cross_val_score(clf,x,y,cv=10).mean()

print(score)

#6.调参
tr=[]
te=[]
for i in range(10):
    clf=DecisionTreeClassifier(random_state=25
                               ,max_depth=i+1
                               ,criterion='entropy'
                              )
    clf=clf.fit(xtrain,ytrain)
    score_tr=clf.score(xtrain,ytrain)
    score_te=cross_val_score(clf,x,y,cv=10).mean()
    tr.append(score_tr)
    te.append(score_te)

print(max(te))
plt.plot(range(1,11),tr,color='red',label='train')
plt.plot(range(1,11),te,color='blue',label='test')
plt.xticks(range(1,11))
plt.legend()
plt.show()

#numpy的用法
#np.linspace(0,0.5,50)#0-0.5随机有序取50个数
#np.arange(0,0.5,0.01)#0-0.5步长为0.01取数
#gini_threholds=np.linspace(0,0.5,50)
#entropy_threholds=np.linspace(0,1,50)

#设置一串参数和对应的参数取值范围
parameters={'criterion':('gini','entropy')
            ,'splitter':('best','random')
            ,'max_depth':[*range(1,10)]
            ,'min_samples_leaf':[*range(1,50,5)]
            ,'min_impurity_decrease':[*np.linspace(0,0.5,20)]

}
##网格搜索:同时调整多个参数的枚举技术
clf=DecisionTreeClassifier(random_state=25)
GS=GridSearchCV(clf,parameters,cv=10)
GS=GS.fit(xtrain,ytrain)

print(GS.best_params_)#GS.best_params_:从输入的参数和参数取值的列表中,返回最佳组合
print(GS.best_score_)#GS.best_score_:网格搜索后模型的评判标准
##注意:网格搜索不能舍弃某个参数,只能权衡最好的结果,所以有可能结果不如自己一开始的结果