第一课、高级模型评估
# 第一部分:处理缺失值
import pandas as pd
url = 'https://raw.githubusercontent.com/justmarkham/DAT8/master/data/titanic.csv';;
titanic = pd.read_csv(url, index_col='PassengerId')
titanic.shape
# 检查缺少的值
titanic.isnull().sum()
#一个可能的策略是**丢失缺失值**:
#删除任何缺少值的行
titanic.dropna().shape
# 删除年龄缺失的行
titanic[titanic.Age.notnull()].shape
#有时候更好的策略是**推测缺失值**:
# 平均年龄
titanic.Age.mean()
#中年的
titanic.Age.median()
# 最常见的年龄
titanic.Age.mode()
# 填写年龄中位数的缺失值
titanic.Age.fillna(titanic.Age.median(), inplace=True)
# ##第2部分:处理分类特征(复审)
titanic.head(10)
# 编码Sex_Female功能
titanic['Sex_Female'] = titanic.Sex.map({'male':0, 'female':1})
# 创建一个虚拟变量的数据框
embarked_dummies = pd.get_dummies(titanic.Embarked, prefix='Embarked')
embarked_dummies.drop(embarked_dummies.columns[0], axis=1, inplace=True)
# 连接原始DataFrame和虚拟DataFrame
titanic = pd.concat([titanic, embarked_dummies], axis=1)
titanic.head(1)
# 定义X和y
feature_cols = ['Pclass', 'Parch', 'Age', 'Sex_Female', 'Embarked_Q', 'Embarked_S']
X = titanic[feature_cols]
y = titanic.Survived
# train/test 分割
from sklearn.cross_validation import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=1)
# 训练逻辑回归模型
from sklearn.linear_model import LogisticRegression
logreg = LogisticRegression(C=1e9)
logreg.fit(X_train, y_train)
# 对测试集进行预测
y_pred_class = logreg.predict(X_test)
# 计算测试精度
from sklearn import metrics
print metrics.accuracy_score(y_test, y_pred_class)
# ## 第3部分:ROC曲线和AUC
# 预测生存概率
y_pred_prob = logreg.predict_proba(X_test)[:, 1]
import matplotlib.pyplot as plt
plt.rcParams['figure.figsize'] = (8, 6)
plt.rcParams['font.size'] = 14
# 绘制ROC曲线
# ROC曲线指受试者工作特征曲线 / 接收器操作特性曲线(receiver operating characteristic curve), \
# 是反映敏感性和特异性连续变量的综合指标,是用构图法揭示敏感性和特异性的相互关系,
# 它通过将连续变量设定出多个不同的临界值,从而计算出一系列敏感性和特异性,再以敏感性为纵坐标、(1-特异性)为横坐标绘制成曲线,
# 曲线下面积越大,诊断准确性越高。在ROC曲线上,最靠近坐标图左上方的点为敏感性和特异性均较高的临界值。
fpr, tpr, thresholds = metrics.roc_curve(y_test, y_pred_prob)
plt.plot(fpr, tpr)
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.0])
plt.xlabel('False Positive Rate (1 - Specificity)')
plt.ylabel('True Positive Rate (Sensitivity)')
# 计算AUC
# AUC(Area Under Curve)被定义为ROC曲线下的面积,显然这个面积的数值不会大于1。
# 又由于ROC曲线一般都处于y=x这条直线的上方,所以AUC的取值范围在0.5和1之间。
# 使用AUC值作为评价标准是因为很多时候ROC曲线并不能清晰的说明哪个分类器的效果更好,而作为一个数值,对应AUC更大的分类器效果更好。
print metrics.roc_auc_score(y_test, y_pred_prob)
#除了允许您计算AUC之外,查看ROC曲线可以帮助您选择一个阈值,**以平衡灵敏度和特异性**的方式对特定上下文有意义。
#根据实际响应值分组的预测概率直方图
df = pd.DataFrame({'probability':y_pred_prob, 'actual':y_test})
df.hist(column='probability', by='actual', sharex=True, sharey=True)
#如果您在绘制ROC曲线或计算AUC时使用了** y_pred_class **而不是** y_pred_prob **,会发生什么?
# 使用y_pred_class的ROC曲线 - 错误!
fpr, tpr, thresholds = metrics.roc_curve(y_test, y_pred_class)
plt.plot(fpr, tpr)
# AUC使用y_pred_class - 错误!
print metrics.roc_auc_score(y_test, y_pred_class)
#如果使用** y_pred_class **,它将把0和100解释为预测概率0%和100%。
## ##奖金:ROC曲线只对预测概率的排名顺序敏
#打印前10个预测概率
y_pred_prob[:10]
# 取预测概率的平方根(使它们全部变大)
import numpy as np
y_pred_prob_new = np.sqrt(y_pred_prob)
# 打印修改后的预测概率
y_pred_prob_new[:10]
# 预测概率的直方图已经改变
df = pd.DataFrame({'probability':y_pred_prob_new, 'actual':y_test})
df.hist(column='probability', by='actual', sharex=True, sharey=True)
# ROC曲线没有改变
fpr, tpr, thresholds = metrics.roc_curve(y_test, y_pred_prob_new)
plt.plot(fpr, tpr)
#AUC没有改变
print metrics.roc_auc_score(y_test, y_pred_prob_new)
##第四部分:交叉验证
#计算交叉验证的AUC
from sklearn.cross_validation import cross_val_score
cross_val_score(logreg, X, y, cv=10, scoring='roc_auc').mean()
# 添加票价模型
feature_cols = ['Pclass', 'Parch', 'Age', 'Sex_Female', 'Embarked_Q', 'Embarked_S', 'Fare']
X = titanic[feature_cols]
# 重新计算AUC
cross_val_score(logreg, X, y, cv=10, scoring='roc_auc').mean()
第二课、交叉验证参数调整,模型选择和特征选择
##目标:评估模型评估程序、需要一种在机器学习模型之间进行选择的方法
# 估计**样本外的数据的可能性能
from sklearn.datasets import load_iris
from sklearn.cross_validation import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn import metrics
# 读入iris数据
iris = load_iris()
# 创建X(特征)和Y(响应)
X = iris.data
y = iris.target
# 使用train / test拆分不同的random_state值
# train_test_split是交叉验证中常用的函数,功能是从样本中随机的按比例选取train data和test data,形式为:
# 参数代表含义:
# train_data:所要划分的样本特征集
# train_target:所要划分的样本结果
# test_size:样本占比,如果是整数的话就是样本的数量
# random_state:是随机数的种子。
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=4)
#用K = 5检查KNN的分类精度
knn = KNeighborsClassifier(n_neighbors=5)
knn.fit(X_train, y_train)
y_pred = knn.predict(X_test)
print metrics.accuracy_score(y_test, y_pred)
# 模拟将25个观察数据集分成5个等级
from sklearn.cross_validation import KFold
kf = KFold(25, n_folds=5, shuffle=False)
# 打印每个训练和测试集的内容
print '{} {:^61} {}'.format('Iteration', 'Training set observations', 'Testing set observations')
for iteration, data in enumerate(kf, start=1):
print '{:^9} {} {:^25}'.format(iteration, data[0], data[1])
# - 数据集包含** 25个观察**(编号0到24)
# - 5倍交叉验证,因此它运行** 5次迭代**
# - 对于每一次迭代,每个观察值都在训练集或测试集**中,但不是两者**
# - 每个观察都在测试集**中,只有一次**
###比较交叉验证到训练/测试分割
# **交叉验证的优点:**
# - 更准确地估计样本外的准确性
# - 更有效地使用数据(每次观察都用于培训和测试)
# **列车/测试分组的优点:**
# - 比K-fold交叉验证运行速度快K倍
# - 更简单地检查测试过程的详细结果
##交叉验证示例:参数调整
#**目标:**为iris数据集上的KNN选择最佳调整参数(又名“超参数”)
from sklearn.cross_validation import cross_val_score
# 对于KNN(n_neighbors参数),K = 5的10倍交叉验证
knn = KNeighborsClassifier(n_neighbors=5)
scores = cross_val_score(knn, X, y, cv=10, scoring='accuracy')
print scores
# 使用平均精度作为样本外精度的估计
print scores.mean()
#为KNN搜索K的最优值
k_range = range(1, 31)
k_scores = []
for k in k_range:
knn = KNeighborsClassifier(n_neighbors=k)
scores = cross_val_score(knn, X, y, cv=10, scoring='accuracy')
k_scores.append(scores.mean())
print k_scores
import matplotlib.pyplot as plt
# 绘制KNN(x轴)的K值与交叉验证的精度(y轴)
plt.plot(k_range, k_scores)
plt.xlabel('Value of K for KNN')
plt.ylabel('Cross-Validated Accuracy')
###交叉验证示例:模型选择
#**目标:**比较最佳KNN模型和iris数据集上的逻辑回归
#用最好的KNN模型进行10次交叉验证
knn = KNeighborsClassifier(n_neighbors=20)
print cross_val_score(knn, X, y, cv=10, scoring='accuracy').mean()
# 逻辑回归10倍交叉验证
from sklearn.linear_model import LogisticRegression
logreg = LogisticRegression()
print cross_val_score(logreg, X, y, cv=10, scoring='accuracy').mean()
# ##交叉验证示例:功能选择
# #**目标**:选择报纸特征是否应包含在广告数据集的线性回归模型中
import pandas as pd
import numpy as np
from sklearn.linear_model import LinearRegression
# 读入广告数据集
data = pd.read_csv('http://www-bcf.usc.edu/~gareth/ISL/Advertising.csv';;, index_col=0)
# 创建三个功能名称的Python列表
feature_cols = ['TV', 'radio', 'newspaper'] #注意key值还区分大小写
# 使用列表来选择DataFrame(X)的一个子集
X = data[feature_cols]
# 选择Sales列作为回应(y)
y = data.sales
# 所有三个功能的10倍交叉验证
lm = LinearRegression()
scores = cross_val_score(lm, X, y, cv=10, scoring='neg_mean_squared_error')
print scores
# 修复MSE分数的标志
mse_scores = -scores
print mse_scores
#从MSE转换到RMSE
rmse_scores = np.sqrt(mse_scores)
print rmse_scores
# 计算平均RMSE
print rmse_scores.mean()
# 具有两种功能的10倍交叉验证(不包括报纸)
feature_cols = ['TV', 'radio']
X = data[feature_cols]
print np.sqrt(-cross_val_score(lm, X, y, cv=10, scoring='neg_mean_squared_error')).mean()
##改进交叉验证
# **重复交叉验证**
# - 多次重复交叉验证(使用**不同的随机分割**数据)并对结果进行平均
# - 通过**减少与交叉验证的单个试验相关联的方差**,更可靠地估计样本外的表现
# **创建一个保留集**
# **在开始模型构建过程之前,“拿出”一部分数据**
# - 使用剩余数据的交叉验证找到最佳模型,并使用保留集**对其进行测试**
# - 样本外表现更可靠的估计,因为持有集**是真正的样本外**
# **交叉验证迭代中的特征工程和选择**
# - 通常,在交叉验证之前,要素工程和选择发生**
# - 而是在每次交叉验证迭代中执行所有特征工程和选择**
# - 更可靠的样本外表现评估,因为它更好地模拟**模型在样本外的应用
第三课、 初识朴素贝叶斯分类
*P( 类别 | 特征) = P ( 特征 | 类别 ) P( 类别) / P(特征)**
import pandas as pd
import numpy as np
# 将iris数据读入DataFrame
url = 'http://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data';;
col_names = ['sepal_length', 'sepal_width', 'petal_length', 'petal_width', 'species'] #萼片(sepal)、花瓣(petal) species(种类)
iris = pd.read_csv(url, header=None, names=col_names)
iris.head()
# 将天花板函数应用于数字列
iris.loc[:, 'sepal_length':'petal_width'] = iris.loc[:, 'sepal_length':'petal_width'].apply(np.ceil)
iris.head()
# ## 决定如何进行预测
#假设我有一个**样本外的光圈**,具有以下测量值:** 7,3,5,2 **。 我如何预测这个物种?
#显示所有具有以下特征的观察值:7,3,5,2
iris[(iris.sepal_length==7) & (iris.sepal_width==3) & (iris.petal_length==5) & (iris.petal_width==2)]
# 为这些观测计数物种
iris[(iris.sepal_length==7) & (iris.sepal_width==3) & (iris.petal_length==5) & (iris.petal_width==2)].species.value_counts()
# 计数tr所有观察物种fo
iris.species.value_counts()
第四课、朴素贝叶斯分类处理文本文件
from sklearn.feature_extraction.text import CountVectorizer
# 从一个简单的例子开始
simple_train = ['call you tonight', 'Call me a cab', 'please call me... PLEASE!']
# 学习训练数据的“词汇”
vect = CountVectorizer()
vect.fit(simple_train)
vect.get_feature_names()
# 将训练数据转换成“文档 - 术语矩阵”
simple_train_dtm = vect.transform(simple_train)
simple_train_dtm
#打印稀疏矩阵
print simple_train_dtm
# 将稀疏矩阵转换为稠密矩阵
simple_train_dtm.toarray()
# 一起检查词汇和文档项目矩阵
import pandas as pd
pd.DataFrame(simple_train_dtm.toarray(), columns=vect.get_feature_names())
#> - 每个单独的标记出现频率(标准化或不标准)被视为一个**功能**。
#> - 给定文档的所有标记频率的矢量被认为是一个多元**样本**。
#因此,**文档**可以由一个矩阵表示,每个文档有一行**和每个记号**有一列(例如单词)出现在语料库中。
#>我们把**矢量化称为将文本文档集合转化为数字特征向量的一般过程。这个具体的策略(标记化,计数和标准化)被称为**袋子或**袋子的代表。
# 文档通过单词出现来描述,而完全忽略文档中单词的相对位置信息。
#将测试数据转换成文档术语矩阵(使用现有的词汇)
simple_test = ["please don't call me"]
simple_test_dtm = vect.transform(simple_test)
simple_test_dtm.toarray()
# 一起检查词汇和文档项目矩阵
pd.DataFrame(simple_test_dtm.toarray(), columns=vect.get_feature_names())
#**总结:**
# - `vect.fit(train)`学习训练数据的词汇
# - `vect.transform(train)`使用拟合词汇从训练数据建立一个文档项矩阵
# - `vect.transform(test)`使用拟合的词汇从测试数据中建立一个文档项矩阵(并忽略它以前没见过的记号)
# ## Part 2: 读取SMS数据
# 读取制表符分隔的文件
url = 'https://raw.githubusercontent.com/justmarkham/DAT8/master/data/sms.tsv';;
col_names = ['label', 'message']
sms = pd.read_table(url, sep='\t', header=None, names=col_names)
print sms.shape
sms.head(20)
sms.label.value_counts()
#将标签转换为数字变量
sms['label'] = sms.label.map({'ham':0, 'spam':1})
# 定义X和y
X = sms.message
y = sms.label
#分成训练和测试集
from sklearn.cross_validation import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=1)
print X_train.shape
print X_test.shape
# ## Part 3: 向量化SMS数据
# 实例化矢量化器
vect = CountVectorizer()
# 学习训练数据词汇,然后创建文档术语矩阵
vect.fit(X_train)
X_train_dtm = vect.transform(X_train)
X_train_dtm
# 替代方法:将适合和变换合并为一个步骤
X_train_dtm = vect.fit_transform(X_train)
X_train_dtm
# 将测试数据(使用拟合的词汇)转换成文档术语矩阵
X_test_dtm = vect.transform(X_test)
X_test_dtm
# ## Part 4: 检查令牌和他们的计数
# 存储令牌名称
X_train_tokens = vect.get_feature_names()
# 前50个令牌
print X_train_tokens[:50]
# 最后50个令牌
print X_train_tokens[-50:]
# 将X_train_dtm视为一个稠密矩阵
X_train_dtm.toarray()
# 计算每个令牌在X_train_dtm中的所有消息中出现多少次
import numpy as np
X_train_counts = np.sum(X_train_dtm.toarray(), axis=0)
X_train_counts
X_train_counts.shape
# 用它们的计数创建一个令牌的DataFrame
pd.DataFrame({'token':X_train_tokens, 'count':X_train_counts}).sort_values('count')
# ## 计算每个令牌的“spamminess”
#为火腿和垃圾邮件创建单独的数据框
sms_ham = sms[sms.label==0]
sms_spam = sms[sms.label==1]
#学习所有消息的词汇并保存
vect.fit(sms.message)
all_tokens = vect.get_feature_names()
# 为火腿和垃圾邮件创建文档术语矩阵
ham_dtm = vect.transform(sms_ham.message)
spam_dtm = vect.transform(sms_spam.message)
# 计算EACH令牌在所有的火腿消息中出现的次数
ham_counts = np.sum(ham_dtm.toarray(), axis=0)
# 统计每个垃圾邮件中每个令牌的显示次数
spam_counts = np.sum(spam_dtm.toarray(), axis=0)
# 使用单独的火腿和垃圾邮件计数创建一个令牌数据框
token_counts = pd.DataFrame({'token':all_tokens, 'ham':ham_counts, 'spam':spam_counts})
# 添加一个火腿和垃圾邮件计数以避免被零除(在下面的步骤中)
token_counts['ham'] = token_counts.ham + 1
token_counts['spam'] = token_counts.spam + 1
#计算每个令牌的垃圾邮件到火腿的比例
token_counts['spam_ratio'] = token_counts.spam / token_counts.ham
token_counts.sort_values('spam_ratio')
# 第5部分:建立一个朴素贝叶斯模型
from sklearn.naive_bayes import MultinomialNB
nb = MultinomialNB()
nb.fit(X_train_dtm, y_train)
# 对X_test_dtm进行类别预测
y_pred_class = nb.predict(X_test_dtm)
# 计算类别预测的准确性
from sklearn import metrics
print metrics.accuracy_score(y_test, y_pred_class)
# 混乱矩阵
print metrics.confusion_matrix(y_test, y_pred_class)
# 预测(校准不良)概率
y_pred_prob = nb.predict_proba(X_test_dtm)[:, 1]
y_pred_prob
# 计算AUC
print metrics.roc_auc_score(y_test, y_pred_prob)
#打印错误信息的消息文本
X_test[y_test < y_pred_class]
# 打印消息文本的错误否定
X_test[y_test > y_pred_class]
# 你有什么注意到这个漏报?
X_test[3132]
# ## Part 6: 比较朴素贝叶斯和逻辑回归
# 进口/实例化/ FIT
from sklearn.linear_model import LogisticRegression
logreg = LogisticRegression(C=1e9)
logreg.fit(X_train_dtm, y_train)
# 类别预测和预测概率
y_pred_class = logreg.predict(X_test_dtm)
y_pred_prob = logreg.predict_proba(X_test_dtm)[:, 1]
# 计算准确度和AUC
print metrics.accuracy_score(y_test, y_pred_class)
print metrics.roc_auc_score(y_test, y_pred_prob)