“蜥蜴书”是我机器学习的启蒙书,现在开始二刷,顺便记录一下笔记。好记性不如烂笔头嘛。第一章是介绍,不做笔记了,第二章是我的笔记开始。
官方github:https://github.com/ageron/handson-ml2
pip3 install -U jupyter matplotlib numpy pandas scipy scikit-learn
补充:
其实作者还用了好多其他的库,后面的章节笔记会说明。也可以直接看github上的requirements.txt
import numpy as np
import pandas as pd
import sklearn
from matplotlib import pyplot as plt
如果下载速度慢,可以使用镜像:
常用的国内 PyPI 镜像
完整代码:
pip3 install -U jupyter matplotlib numpy pandas scipy scikit-learn -i https://mirrors.aliyun.com/pypi/simple/
书本上是推荐使用jupyter notebook的,但是网页版的不好用。个人推荐vscode+jupyter插件,很方便,值得一试。
数据是.csv文件,有两种方式下载:
一种是从官方github中找到datasets→housing→housing.csv,然后下载就可以了。
如果github登录不上,我放到了阿里云盘,可以自取。
机器学习实战数据所需的数据集下载:蓝奏云链接 或者 csdn下载
# pandas读取csv文件
housing=pd.read_csv("housing.csv")
# 查看数据前5行
housing.head()
# 查看数据的简单描述,总行数、每个属性的类型的非空值的数量
housing.info()
# 查看具体某一列的分类的数量
housing["ocean_proximity"].value_counts()
# 查看数据各个属性的摘要
housing.describe()
# 直方图显示查看各个属性
housing.hist()
书籍使用了两种方式(本质上是一样的,注意使用随机数种子来确保程序每次运行时分割的测试集和训练集一致),
一种:numpy的random模块的permutation函数来打乱数据集,再从数据集中选择20%的数据作为测试集。
另一种:使用了sklearn库的model_selection模块的train_test_split函数来分割测试集和训练集。
from sklearn.model_selection import train_test_split
train_set, test_set = train_test_split(housing, test_size=0.2, random_state=42,shuffle=True) # shuffle控制划分训练集和测试集的时候是否打乱
如果数据的某一种属性相当的重要,创建训练/测试集需要在这个非常重要的属性下划分,需要使用分层随机分割:
housing["income_cat"] = pd.cut(housing["median_income"],bins=[0., 1.5, 3.0, 4.5, 6., np.inf],labels=[1, 2, 3, 4, 5]) # bins区间为什么设置这些值是作者设定的,在5个区间上的数据数量也不是等量的,为什么不是等量的我也不知道
from sklearn.model_selection import StratifiedShuffleSplit
split = StratifiedShuffleSplit(n_splits=1, test_size=0.2, random_state=42)
for train_index, test_index in split.split(housing, housing["income_cat"]):
strat_train_set = housing.loc[train_index]
strat_test_set = housing.loc[test_index]
# 删除income_cat
for set_ in (strat_train_set, strat_test_set):
set_.drop("income_cat", axis=1, inplace=True)
使用dataFrame的plot()函数;来将数据可视化
housing.plot(kind="scatter",x="longitude",y="latitude",alpha=0.1)
上面的图只能看出数据的密集程度,如果想在这个基础上查看其他参数,比如这个经纬度点的房价,人口数量,可以变化散点图中点的大小和颜色来展示。
housing.plot(kind="scatter",x="longitude",y="latitude",alpha=0.4,s=housing["population"]/100,label="population",c=housing["median_house_value"],cmap=plt.get_cmap("jet"),figsize=(20,10),colorbar=True)
属性线性相关性分析:
corr=housing.corr()
corr["median_house_value"].sort_values(ascending=False) # 降序排列
用属性线性相关性可视化(散布矩阵绘画):
# 11个属性图片展示太多了,先看四个属性
pd.plotting.scatter_matrix(housing[["median_house_value","median_income","total_rooms","housing_median_age"]],figsize=(20,10))
从图中可以看到房价和收入有强的相关性。
单独把房价和收入摘出来看
housing.plot(kind="scatter",x="median_income",y="median_house_value",alpha=0.1,figsize=(20,10))
从训练集中把标签和内容分开,为后面监督学习做准备
housing=train_set.drop("median_house_value",axis=1)
housing_label=train_set["median_house_value"].copy()
蜥蜴书的作者对缺失值处理有三种方式:
df.dropna()
df.drop("",axis=1)
series.fillna()
作者还介绍了sklearn库中的一个估算器可以实现第三种方法:
from sklearn.impute import SimpleImputer
我看了一下,比较麻烦,还是计算出中位数再填充的块
housing["total_bedrooms"].fillna(housing["total_bedrooms"].median(),inplace=True)
大多机器学习算法更喜欢数字,把文本转化为数字,便于机器处理。
作者开始使用了sklearn.preprocessing.OrdinalEncoder
,每一个文本类型代表一个数字列表。
但是ocean_proximity属性使用数字会引发一个问题:相邻的数字机器算法会认为这两个文本的相关性强,干扰到训练。作者使用sklearn中的独热编码来转换。
from sklearn.preprocessing import OneHotEncoder
encoder=OneHotEncoder()
housing_cat_1hot=encoder.fit_transform(housing[["ocean_proximity"]]) # 这里注意是housing[[""]],因为fit_tranform需要传入的是2维数据,housing[""]是series,是一维。housing[[""]]是df,是二维数据
housing_cat_1hot是稀疏矩阵。如果不喜欢,可以使用toarray()
方法转换为正常的矩阵。
housing["rooms_per_household"]=housing["total_rooms"]/housing["households"]
housing["bedrooms_per_room"]=housing["total_bedrooms"]/housing["total_rooms"]
housing["population_per_household"]=housing["population"]/housing["households"]
归一化:将值缩小到0~1之间
MinMaxScaler
标准化:减平均值再除以方差得到。
StandadScaler
# 标准化
housing_num=housing.drop("ocean_proximity",axis=1) # 先剔除文本,将其他数值标准化
from sklearn.preprocessing import StandardScaler
standard=StandardScaler()
housing_num_standard=standard.fit_transform(housing_num)
housing_pre=np.hstack((housing_num_standard,housing_cat_1hot.toarray()))
作者在书中介绍了自定义转换器并把以上的步骤使用pipline
把转换器封装在一起。这里不介绍pipline。
得到housing_pre
(预处理之后的数据),就可以使用这个数据结合housing_label
来建立监督模型
本书的作者使用了三种模型,第一种是线型模型;第二种是决策树模型;第三种是随机森林模型
这种模型有拟合不足的风险
from sklearn.linear_model import LinearRegression
lin_reg=LinearRegression()
lin_reg.fit(housing_pre,housing_label)
此模型有过度拟合的风险
from sklearn.tree import DecisionTreeRegressor
tree_reg=DecisionTreeRegressor()
tree_reg.fit(housing_pre,housing_label)
这个模型训练的比较慢
from sklearn.ensemble import RandomForestRegressor
forest_reg=RandomForestRegressor()
forest_reg.fit(housing_pre,housing_label)
建立模型之后需要看看哪个模型比较好。就是看看预测的结果和训练集的结果差距多大。
可以使用均方误差和平方根误差。这俩都能表示预测的准确程度,值越小越好。
sklearn提供了一个写好的函数mean_squared_error
来计算均方根误差值(使用numpy也可以)
from sklearn.metrics import mean_squared_error
housing_predictions=lin_reg.predict(housing_pre)
lin_mse=mean_squared_error(housing_label,housing_predictions)
print(lin_mse)
其他的模型同样,不展示了
交叉验证是将训练集划分为多份,模型训练多次,每次都留一份验证。最终得到多份的误差
from sklearn.model_selection import cross_val_score
scores=cross_val_score(tree_reg,housing_pre,housing_label,scoring="neg_mean_squared_error",cv=10)
rmse=np.sqrt(-scores)
print(rmse)
# 输出:
'''
[72266.89772264 65389.88429289 71386.01269181 71873.55861274
74896.78226165 70089.43997179 73353.55621241 71874.246097
72878.52508422 69893.43017067]
'''
作者把训练集划分为十份,来验证十次,最终得到十个结果
使用交叉验证可以避免过拟合的风险。但是因为要计算多次,可能耗时一些
模型保存文件,方便程序下次调用。作者介绍了pickle和joblib两种库来保存。
pickle:
import pickle
with open('model.pickle','wb') as f:
pickle.dump(model,f)
with open('model.pickle','rb') as f:
model_get = pickle.load(f)
joblib:
import joblib
joblib.dump(model, 'model_.pkl')
model = joblib.load('model_.pkl')
pickle需要操作文件对象,joblib直接传个文件名就可,还是joblib代码量少
模型调整超参数,作者举例两种调整超参数的方法:
网格搜索和随机搜索
# 网格搜索
from sklearn.model_selection import GridSearchCV
# 随机搜索
使用验证集并通过rmse来评估模型预测的准确性
predictions = model.predict(test_set)
rmse = np.sqrt(mean_squared_error(test_set_label,predictions))
print(rmse)