时间序列(time series)是来自随时间变化的系统的一系列度量。
本章使用的示例来自Zachary M. Jones。Jones的研究目的是调查像大麻合法化这样的政策性决定会对市场产生何种影响。希望大家对本章内容感兴趣,但借此机会重申对数据分析保持专业性态度的重要性。药品是否非法,哪些药品应当属于非法,这是很重要而又难以回答的公共政策问题,人们应当基于诚实准确的数据进行决策。
导入和清洗数据
从Jones先生的网站下载数据,通过下面代码将数据读取到一个pandas DataFrame中:
transactions = pandas.read_csv('mj-clean.csv', parse_dates=[5])
这个DataFrame中每一行都代表一次交易,具有如下列:
- city 字符串,代表城市名
- state 州名的两字母缩写
- price 交易价格,单位为美元
- amount 购买量,单位为克
- quality 由购买者汇报的货品质量,值为高、中或低
- date 汇报日期,这个日期应该在购买日期后不久
- ppg 每克价格,单位为美元
- lat 交易发生地点的大致维度,由城市名获得
- lon 交易发生地点的大致经度
每次交易都是一个时间事件,因此这个数据集可以看成一个事件序列。很多分析时间序列的方法要求度量是均匀分布的,或者度量均匀分布至少可以使分析更为简单。
为了演示这些方法,将这个数据集按照汇报的质量分组,并计算每克的日均价格,将每组数据转换为均匀分布的序列。
def GroupByQualityAndDay(transactions):
groups = transactions.groupby('quality')
dailies = {}
for name, group in groups:
dailies[name] = GroupByDay(group)
return dailies
def GroupByDay(transactions, func=np.mean):
grouped = transactions[['date', 'ppg']].groupby('date')
daily = grouped.aggregate(func)
daily['date'] = daily.index
start = daily.date[0]
one_year = np.timedelta64(1, 'Y')
daily['years'] = (daily.date - start) / one_year
return daily
groupby是DataFrame的方法,返回一个GroupBy对象groups。得到的grouped是一个映射,将每个日期对应到包含该日期汇报价格的DataFrame。aggregate是GroupBy的方法,遍历所有的组,对组中每列都执行一个函数。GroupByDay方法得到的DataFrame包含列ppg、date和years。
绘制图形
GroupByQualityAndDay得到的结果是从每个质量级别到日均价格DataFrame的映射。绘制这3个时间序列的代码如下:
thinkplot.PrePlot(rows=3)
for i, (name, daily) in enumerate(dailies.items()):
thinkplot.SubPlot(i+1)
title = 'price per gram ($)' if i==0 else ''
thinkplot.Config(ylim=[