4.2 为回归清洗数据
首先,从http://mng.bz/P16w下载一组数据——一组来自2014年夏天纽约市311服务的电话呼叫。Kaggle有其他311数据集,但我们使用这个数据集是因为它的有趣的属性。呼叫数据是CSV格式的文件,有以下有趣的属性:
- 唯一的呼叫标识符,显示呼叫创建的日期。
- 上报的事件或信息请求的位置和邮政编码。
- 呼叫中心座席为解决呼叫的问题而采取的特定操作。
- 电话是从哪个区(比如布朗克斯或皇后区)打来的。
- 通话状态。
数据集包含了很多对机器学习有用的信息,但在本练习中,你只需要关注呼叫创建日期。创建一个名为311.py的文件,然后编写函数读取CSV文件的每行,检查周数并计算每周的呼叫量之和。
你的代码需要处理数据文件中的一些混乱。首先,你需要将单个呼叫(有时一天会有几百个)聚合为七天或周的容器中,如清单4.1中的变量bucket
。变量freq
(frequency的缩写)保存每周和每年的呼叫量。如果311 CSV文件包含超过一年的数据(就像其他你可以在kaggle上找到的文件),运行你的代码使其可以按年选择数据训练。清单4.1的运行结果是一个freq
的字典,它的值是呼叫数量,索引是表示年或周数的period
变量。t.tm_year
变量保存了解析出来的年份信息,它通过由Python的time
库的strptime
函数根据传入的呼叫创建时间(在CSV文件中通过date_idx
索引,用一个整数定义的日期字段所在的列号)和date_parse
格式字符串解析得到。date_parse
格式字符串是一个模式,它定义了日期作为文本在CSV文件中的显示方式,这样Python就知道如何将其转换为时间的表示方式。
清单4.1 从311 CSV文件中读取并按周聚合呼叫数据
清单4.1中的大部分代码处理现实世界的数据,这些数据不是由NumPy调用产生的符合正态分布的随机(x,y)数据点——这是本书的一个主题。机器学习希望有干净的数据来施展黑魔法,但是现实世界的数据需要清洗。从NYC开放数据门户(https://data.cityofnewyork.us/browse?q=311)中随机取一组311 CSV文件,你会发现差别很大。有些文件包含多个年份的呼叫,所以你的代码必须处理这种情况;有些文件有缺失的行,或者缺少特定单元格的年份和日期值,你的代码仍然要能处理。编写有弹性的数据清洗代码是机器学习的基本原则之一,所以编写这段代码将是本书中很多例子的第一步。
调用清单4.1中定义的read
函数,你会得到一个以(year
,week number
)为索引或简单按(week number
)为索引的Python字典,取决于你是否将年作为最后一个参数传入。在311.py代码中调用该函数。该函数以列索引(1代表第二列,索引从0开始)和一个字符串作为输入,类似这样:
它告诉函数日期字段的序号是1(或从0开始索引的第二列),你的日期格式化为字符串,类似'month/day/yearhour:minutes:seconds AM/PM'
或'12/10/2014 00:00:30 AM'
(对应2014年12月10日午夜零时30秒),并且你希望只从CSV文件中取2014年的日期。
如果你使用Jupyter,你可以通过查看freq
字典来打印频率的值。结果是一个52周(索引从0开始,所以是0~51)的柱状图,包含每周的调用次数。从输出可以看出,数据集中在第22周到第35周,即2014年5月26日到8月25日:
定义计算机代码、数据和软件标准的国际标准化组织(ISO)发布了用字符串表示日期和时间的常用ISO-8601标准。Python的time
和iso8601
库实现了该标准。该标准包括与从周一开始的日期和时间相关联的周号规范(https://www.epochconverter.com/weeknumbers),这似乎是311数据的有用表示。虽然有其他周号的表示方式,但是它们大多数都有不同的开始日,比如周日。
通过将基于时间的日期转化为x轴上的周数,你得到一个代表时间的整数值,可以很容易地排序和可视化。这个值与回归函数要预测的呼叫频率y轴值是对应的。
将周数转化为日期
你处理的很多基于时间的数据有时用周数表示会更好。例如,处理1~52的整数比处理字符串'Wednesday, September 5, 2014'
好得多。EpochConverter网站可以很容易地告诉你一年和日期的星期数。要想查看清单4.1中2014年输出的日期映射到周数的列表,请访问https://www.epochconverter.com/weeks/2014。
你可以使用Python简单的datetime
库得到相同的信息:
这段代码输出24,因为2010年6月16日是那年的第24周。
打开一个Jupyter Notebook,复制清单4.2代码,以便从你的freq
字典(从read
函数返回)中可视化每周呼叫频率的直方图,并生成图4.3,这是本章开始时讨论的数据点的分布。通过检查数据点的分布,你可以决定一个在TensorFlow中的回归模型预测模型。清单4.2设置输入的训练值为1~52周,预测的输出值为该周的呼叫数。变量X_train
保存freq
字典的索引数组(整数0~51,对应52周),变量Y_train
保存每周的311呼叫量。nY_train
保存归一化的Y_train
(除以maxY
),范围是0到1。我将在本章的后面解释为什么,简单说它简化了训练的过程。代码的最后一行使用Matplotlib创建数据(周数,呼叫量)点的散点图。
清单4.2 可视化和设置输入数据
清单4.2的输出如图4.3所示。它与我们在第3章中尝试用模型拟合的直线或曲线差别很大。还记得我说过现实世界中的数据不总是那么美好吗?直觉上,数据告诉我们那年的前两个季度大部分时间没有电话;高峰期从春季持续到夏季;秋天和冬天没有电话。也许在夏天纽约很多人使用311,至少在2014年是这样。还有可能这些数据只是实际信息的一个子集,但我们仍然看看能否做出一个好的模型。
图4.3 y轴为呼叫计数,对应x轴上一年的周(0~51)。活动在2014年5月开始增加并在2014年8月底减少
如果你看到过某项测验的分数的分布,一个常见的描述0~100分数排序的模型是曲线或钟形曲线。事实上,在本章的剩余部分我们将教TensorFlow预测器来模拟这种类型的模型。