9. 用merge_asof找到上次低20%犯罪率
# 读取crime数据集,行索引设为REPORTED_DATE,并排序
In[145]: crime_sort = pd.read_hdf('data/crime.h5', 'crime') \
.set_index('REPORTED_DATE') \
.sort_index()
# 找到最后一个完整月
In[146]: crime_sort.index.max()
Out[146]: Timestamp('2017-09-29 06:16:00')
# 因为9月份的数据不完整,所以只取到8月份的
In[147]: crime_sort = crime_sort[:'2017-8']
crime_sort.index.max()
Out[147]: Timestamp('2017-08-31 23:52:00')
# 统计每月的犯罪和交通事故数量
In[148]: all_data = crime_sort.groupby([pd.Grouper(freq='M'), 'OFFENSE_CATEGORY_ID']).size()
all_data.head()
Out[148]: REPORTED_DATE OFFENSE_CATEGORY_ID
2012-01-31 aggravated-assault 113
all-other-crimes 124
arson 5
auto-theft 275
burglary 343
dtype: int64
# 重新设置索引
In[149]: all_data = all_data.sort_values().reset_index(name='Total')
all_data.head()
Out[149]:
# 用当前月的统计数乘以0.8,生成一个新的目标列
In[150]: goal = all_data[all_data['REPORTED_DATE'] == '2017-8-31'].reset_index(drop=True)
goal['Total_Goal'] = goal['Total'].mul(.8).astype(int)
goal.head()
Out[150]:
# 用merge_asof函数,找到上次每个犯罪类别低于目标值的月份
In[151]: pd.merge_asof(goal, all_data, left_on='Total_Goal', right_on='Total',
by='OFFENSE_CATEGORY_ID', suffixes=('_Current', '_Last'))
Out[151]:
更多
# 手动创建一个Periods
In[152]: pd.Period(year=2012, month=5, day=17, hour=14, minute=20, freq='T')
Out[152]: Period('2012-05-17 14:20', 'T')
# 具有DatetimeIndex的DataFrame有to_period方法,可以将Timestamps转换为Periods
In[153]: crime_sort.index.to_period('M')
Out[153]: PeriodIndex(['2012-01', '2012-01', '2012-01', '2012-01', '2012-01', '2012-01',
'2012-01', '2012-01', '2012-01', '2012-01',
...
'2017-08', '2017-08', '2017-08', '2017-08', '2017-08', '2017-08',
'2017-08', '2017-08', '2017-08', '2017-08'],
dtype='period[M]', name='REPORTED_DATE', length=453568, freq='M')
In[154]: ad_period = crime_sort.groupby([lambda x: x.to_period('M'),
'OFFENSE_CATEGORY_ID']).size()
ad_period = ad_period.sort_values() \
.reset_index(name='Total') \
.rename(columns={'level_0':'REPORTED_DATE'})
ad_period.head()
Out[154]:
# 判断ad_period的最后两列和之前的all_data是否相同
In[155]: cols = ['OFFENSE_CATEGORY_ID', 'Total']
all_data[cols].equals(ad_period[cols])
Out[155]: True
# 用同样的方法,也可以重构正文中的最后两步
In[156]: aug_2018 = pd.Period('2017-8', freq='M')
goal_period = ad_period[ad_period['REPORTED_DATE'] == aug_2018].reset_index(drop=True)
goal_period['Total_Goal'] = goal_period['Total'].mul(.8).astype(int)
pd.merge_asof(goal_period, ad_period, left_on='Total_Goal', right_on='Total',
by='OFFENSE_CATEGORY_ID', suffixes=('_Current', '_Last')).head()
Out[156]: