9. 用merge_asof找到上次低20%犯罪率

  1. # 读取crime数据集,行索引设为REPORTED_DATE,并排序
  2. In[145]: crime_sort = pd.read_hdf('data/crime.h5', 'crime') \
  3. .set_index('REPORTED_DATE') \
  4. .sort_index()
  1. # 找到最后一个完整月
  2. In[146]: crime_sort.index.max()
  3. Out[146]: Timestamp('2017-09-29 06:16:00')
  1. # 因为9月份的数据不完整,所以只取到8月份的
  2. In[147]: crime_sort = crime_sort[:'2017-8']
  3. crime_sort.index.max()
  4. Out[147]: Timestamp('2017-08-31 23:52:00')
  1. # 统计每月的犯罪和交通事故数量
  2. In[148]: all_data = crime_sort.groupby([pd.Grouper(freq='M'), 'OFFENSE_CATEGORY_ID']).size()
  3. all_data.head()
  4. Out[148]: REPORTED_DATE OFFENSE_CATEGORY_ID
  5. 2012-01-31 aggravated-assault 113
  6. all-other-crimes 124
  7. arson 5
  8. auto-theft 275
  9. burglary 343
  10. dtype: int64
  1. # 重新设置索引
  2. In[149]: all_data = all_data.sort_values().reset_index(name='Total')
  3. all_data.head()
  4. Out[149]:

9. 用merge_asof找到上次低20%犯罪率 - 图1

  1. # 用当前月的统计数乘以0.8,生成一个新的目标列
  2. In[150]: goal = all_data[all_data['REPORTED_DATE'] == '2017-8-31'].reset_index(drop=True)
  3. goal['Total_Goal'] = goal['Total'].mul(.8).astype(int)
  4. goal.head()
  5. Out[150]:

9. 用merge_asof找到上次低20%犯罪率 - 图2

  1. # 用merge_asof函数,找到上次每个犯罪类别低于目标值的月份
  2. In[151]: pd.merge_asof(goal, all_data, left_on='Total_Goal', right_on='Total',
  3. by='OFFENSE_CATEGORY_ID', suffixes=('_Current', '_Last'))
  4. Out[151]:

9. 用merge_asof找到上次低20%犯罪率 - 图3

更多

  1. # 手动创建一个Periods
  2. In[152]: pd.Period(year=2012, month=5, day=17, hour=14, minute=20, freq='T')
  3. Out[152]: Period('2012-05-17 14:20', 'T')
  1. # 具有DatetimeIndex的DataFrame有to_period方法,可以将Timestamps转换为Periods
  2. In[153]: crime_sort.index.to_period('M')
  3. Out[153]: PeriodIndex(['2012-01', '2012-01', '2012-01', '2012-01', '2012-01', '2012-01',
  4. '2012-01', '2012-01', '2012-01', '2012-01',
  5. ...
  6. '2017-08', '2017-08', '2017-08', '2017-08', '2017-08', '2017-08',
  7. '2017-08', '2017-08', '2017-08', '2017-08'],
  8. dtype='period[M]', name='REPORTED_DATE', length=453568, freq='M')
  9. In[154]: ad_period = crime_sort.groupby([lambda x: x.to_period('M'),
  10. 'OFFENSE_CATEGORY_ID']).size()
  11. ad_period = ad_period.sort_values() \
  12. .reset_index(name='Total') \
  13. .rename(columns={'level_0':'REPORTED_DATE'})
  14. ad_period.head()
  15. Out[154]:

9. 用merge_asof找到上次低20%犯罪率 - 图4

  1. # 判断ad_period的最后两列和之前的all_data是否相同
  2. In[155]: cols = ['OFFENSE_CATEGORY_ID', 'Total']
  3. all_data[cols].equals(ad_period[cols])
  4. Out[155]: True
  1. # 用同样的方法,也可以重构正文中的最后两步
  2. In[156]: aug_2018 = pd.Period('2017-8', freq='M')
  3. goal_period = ad_period[ad_period['REPORTED_DATE'] == aug_2018].reset_index(drop=True)
  4. goal_period['Total_Goal'] = goal_period['Total'].mul(.8).astype(int)
  5. pd.merge_asof(goal_period, ad_period, left_on='Total_Goal', right_on='Total',
  6. by='OFFENSE_CATEGORY_ID', suffixes=('_Current', '_Last')).head()
  7. Out[156]:

9. 用merge_asof找到上次低20%犯罪率 - 图5