基于书籍《Hands-on Machine Learning with Scikit-Learn, Keras & TensorFlow》的笔记
2.获取数据与EDA(探索性数据分析)
我们使用jupyter(一个非常方便的文本与代码结合的编辑器-不用保存为python文件)作为整个开发的IDE,在开发之前,您将需要安装一个Anaconda以获取所有ML中常见的python模块。
2.1 下载数据
一般来说,数据都存储在关系型数据库里(或者其他一些常见的数据存储),并分布在多个表/文档/文件中,访问前,你将需要证书(注意私有数据永远不应该被复制到不安全数据存储区),然后你需要熟悉数据库的模式。本次教程并不涉及这些内容,按照原书,我们只需要下载一个压缩文件housing.tgz即可,文件包含了所有的数据-用逗号分隔值的CSV文件housing.csv(csv文件是常用的机器学习数据的标准格式文件,使用pandas模块能够很好地处理csv文件进行EDA分析).
一个好的选择是编写一个小的脚本函数来实现下载、解压缩和提取CSV文件,因为当数据发生变化时,你将只需要直接运行即可(或者设立定期自动运行的计划任务),同时,这个函数也适用于多台机器都需要该数据集的时候。
import os
import tarfile
import urllib
DOWNLOAD_ROOT="https://raw.githubusercontent.com/ageron/handson-ml2/master/"
HOUSING_PATH=os.path.join("datasets","housing")
HOUSING_URL=DOWNLOAD_ROOT+"datasets/housing/housing.tgz"
def fetch_housing_data(housing_url=HOUSING_URL,housing_path=HOUSING_PATH):
os.makedirs(housing_path,exist_ok=True)
tgz_path=os.path.join(housing_path,"housing.tgz")
urllib.request.urlretrieve(housing_url,tgz_path)
housing_tgz=tarfile.open(tgz_path)
housing_tgz.extractall(path=housing_path)
housing_tgz.close()
每当你调用一次fetch_housing_data(),就会自动在jupyter的工作区创建一个datasets/housing目录,然后下载housing.tgz文件,并将housing.csv解压到这个目录。是不是很方便呢?
接下来,使用pandas加载这个数据,为了自动化,也需要编写一个小函数。
import pandas as pd
import numpy as np
def load_housing_data(housing_path=HOUSING_PATH): #函数返回一个包含所有数据的pandas DataFrame对象
csv_path=os.path.join(housing_path,"housing.csv")
return pd.read_csv(csv_path)
2.2 快速查看数据结构
fetch_housing_data()
housing=load_housing_data()
housing.head() #快速查看DataFrame方法的前五行是怎么样的-很好用的方法
Figure 前7个特征
每一行代表一个区域,总共有10个属性,longitude, latitude, housing_median_age, total_rooms, total_bed rooms, population, households, median_income, median_house_value, and ocean_proximity.
housing.info()
使用housing.info()可以快速获取数据集的一个简单描述,特别是总行数,各个属性的类型以及非空值的数量。
可以看到,整个数据集包含20640个实例(区域),大多数属性都是数值属性,有一个是object,我们猜测它可能是文本属性(当然,从csv文件中加载,除了数值应该就是文本),值得注意的是,有一个特征total_bedrooms只有20433个非空值,这说明有207个样本缺失了该属性,这个问题需要被解决,我们将在后面详细讨论它。对于文本数据,我们常常猜测它是否会是一个类别型的数据,如果不幸不是的话,那将会涉及到NLP(自然语言处理)了,这个我们暂时不做讨论。我们可以尝试使用value_counts()函数查看有多少种分类存在,每种类别下分别有多少个区域:
很幸运,该属性确实是一个类别型的文本数据,这使得我们的机器学习系统简单了许多,后面我们将使用一种编码的方式来处理这种数据。
最后,我们使用describe()方法显示数值属性的摘要-值得注意的是,这里的空值(所以属性total_bedrooms的count是20433个样本)会被忽略,所以总样本数。
housing.describe()
提示一下,这里的25% 50% 75%分别代表第一四分位数,中位数以及第75百分位数,例如25%中的housing_median_age的值是18,所以这代表1/4的区域的房子年龄中位数都<=18.
我们还可以通过绘制每个数值属性的直方图来快速了解数据类型的分布。
%matplotlib inline # only in a Jupyter notebook
import matplotlib.pyplot as plt
housing.hist(bins=50, figsize=(20,15))
plt.show()
Figure 每个数值属性的直方图
观察直方图,我们可以获得以下信息并进行思考:
-
首先,收入中位数(median_income)属性似乎看起来并不像使用美元来衡量,因为其X轴的范围是(0~15),经与收集数据的团队进行核实,原来其确实对数据进行了按比例缩小,并且设定了上限为15(实际为15.0001),下限为0.5(实际为0.4999),数字后的单位为万美元。使用经过预处理的属性是很常见的,但是你需要知道其相对于原始数据经过了怎么样的计算与转换。
-
观察housing_median_age和median_house_value,可以发现明显存在一个边界值,而median_house_value事实上是我们的标签,所以这个问题可能比较严重,因为这可能导致我们的机器学习算法学习认为median_house_value永远不会超过该边界值,所以你需要与下游任务团队(即需要使用我们的预测值输出的团队)进行核实,如果他们确实需要超过50万美元的预测值,那么我们将讨论如何解决这个问题:
- 对标签值为边界值(50万dollar)的实例,重新收集数据
- 将这些标签值为边界值的数据从训练集中和测试集中移除,因为如果预测值超过50万美元,系统不应该被评估为预测错误)
-
这些属性值被缩放的程度各不相同,在后面将讨论这个问题。
-
最后,许多直方图都表现出重(zhong)尾的现象,即图像在中位数右侧的延伸比左侧要远得多,这可能导致某些机器学习算法难以检测出其模式,我们会在后面尝试一些转化方法,将这些属性转化为更偏向于钟形的分布。
到这里,我们已经对整个数据集有了一个大致的了解。