6. 按工作日和年测量犯罪

  1. # 读取crime数据集,将REPORTED_DATE作为一列
  2. In[105]: crime = pd.read_hdf('data/crime.h5', 'crime')
  3. crime.head()
  4. Out[105]:

6. 按工作日和年测量犯罪 - 图1

  1. # 可以通过Timestamp的dt属性得到周几,然后统计
  2. In[106]: wd_counts = crime['REPORTED_DATE'].dt.weekday_name.value_counts()
  3. wd_counts
  4. Out[106]: Monday 70024
  5. Friday 69621
  6. Wednesday 69538
  7. Thursday 69287
  8. Tuesday 68394
  9. Saturday 58834
  10. Sunday 55213
  11. Name: REPORTED_DATE, dtype: int64
  1. # 画一张水平柱状图
  2. In[107]: days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday',
  3. 'Friday', 'Saturday', 'Sunday']
  4. title = 'Denver Crimes and Traffic Accidents per Weekday'
  5. wd_counts.reindex(days).plot(kind='barh', title=title)
  6. Out[107]: <matplotlib.axes._subplots.AxesSubplot at 0x117e39e48>

6. 按工作日和年测量犯罪 - 图2

  1. # 相似的,也可以画出每年的水平柱状图
  2. In[108]: title = 'Denver Crimes and Traffic Accidents per Year'
  3. crime['REPORTED_DATE'].dt.year.value_counts() \
  4. .sort_index() \
  5. .plot(kind='barh', title=title)
  6. Out[108]: <matplotlib.axes._subplots.AxesSubplot at 0x11b1c6d68>

6. 按工作日和年测量犯罪 - 图3

  1. # 将年和星期按两列分组聚合
  2. In[109]: weekday = crime['REPORTED_DATE'].dt.weekday_name
  3. year = crime['REPORTED_DATE'].dt.year
  4. crime_wd_y = crime.groupby([year, weekday]).size()
  5. crime_wd_y.head(10)
  6. Out[109]: REPORTED_DATE REPORTED_DATE
  7. 2012 Friday 8549
  8. Monday 8786
  9. Saturday 7442
  10. Sunday 7189
  11. Thursday 8440
  12. Tuesday 8191
  13. Wednesday 8440
  14. 2013 Friday 10380
  15. Monday 10627
  16. Saturday 8875
  17. dtype: int64
  1. # 重命名索引名,然后对Weekday做unstack
  2. In[110]: crime_table = crime_wd_y.rename_axis(['Year', 'Weekday']).unstack('Weekday')
  3. crime_table
  4. Out[110]:

6. 按工作日和年测量犯罪 - 图4

  1. # 找到数据中2017年的最后一天
  2. In[111]: criteria = crime['REPORTED_DATE'].dt.year == 2017
  3. crime.loc[criteria, 'REPORTED_DATE'].dt.dayofyear.max()
  4. Out[111]: 272
  1. # 计算这272天的平均犯罪率
  2. In[112]: round(272 / 365, 3)
  3. Out[112]: 0.745
  4. In[113]: crime_pct = crime['REPORTED_DATE'].dt.dayofyear.le(272) \
  5. .groupby(year) \
  6. .mean() \
  7. .round(3)
  8. crime_pct
  9. Out[113]: REPORTED_DATE
  10. 2012 0.748
  11. 2013 0.725
  12. 2014 0.751
  13. 2015 0.748
  14. 2016 0.752
  15. 2017 1.000
  16. Name: REPORTED_DATE, dtype: float64
  17. In[114]: crime_pct.loc[2012:2016].median()
  18. Out[114]: 0.748
  1. # 更新2017年的数据,并将星期排序
  2. In[115]: crime_table.loc[2017] = crime_table.loc[2017].div(.748).astype('int')
  3. crime_table = crime_table.reindex(columns=days)
  4. crime_table
  5. Out[115]:

6. 按工作日和年测量犯罪 - 图5

  1. # 用seaborn画热力图
  2. In[116]: import seaborn as sns
  3. sns.heatmap(crime_table, cmap='Greys')
  4. Out[116]: <matplotlib.axes._subplots.AxesSubplot at 0x117a37ba8>

6. 按工作日和年测量犯罪 - 图6

  1. # 犯罪貌似每年都在增加,但这个数据没有考虑每年的新增人口。
  2. # 读取丹佛市人口denver_pop数据集
  3. In[117]: denver_pop = pd.read_csv('data/denver_pop.csv', index_col='Year')
  4. denver_pop
  5. Out[117]:

6. 按工作日和年测量犯罪 - 图7

  1. # 计算每10万人的犯罪率
  2. In[118]: den_100k = denver_pop.div(100000).squeeze()
  3. crime_table2 = crime_table.div(den_100k, axis='index').astype('int')
  4. crime_table2
  5. Out[118]:

6. 按工作日和年测量犯罪 - 图8

  1. # 再画一张热力图
  2. In[119]: sns.heatmap(crime_table2, cmap='Greys')
  3. Out[119]: <matplotlib.axes._subplots.AxesSubplot at 0x1203024e0>

6. 按工作日和年测量犯罪 - 图9

原理

  1. # loc接收一个排好序的列表,也可以实现reindex同样的功能
  2. In[120]: wd_counts.loc[days]
  3. Out[120]: Monday 70024
  4. Tuesday 68394
  5. Wednesday 69538
  6. Thursday 69287
  7. Friday 69621
  8. Saturday 58834
  9. Sunday 55213
  10. Name: REPORTED_DATE, dtype: int64
  1. # DataFrame和Series相除,会使用DataFrame的列和Series的行索引对齐
  2. In[121]: crime_table / den_100k
  3. /Users/Ted/anaconda/lib/python3.6/site-packages/pandas/core/indexes/base.py:3033: RuntimeWarning: '<' not supported between instances of 'str' and 'int', sort order is undefined for incomparable objects
  4. return this.join(other, how=how, return_indexers=return_indexers)
  5. Out[121]:

6. 按工作日和年测量犯罪 - 图10

更多

  1. # 将之前的操作打包成一个函数,并且可以根据犯罪类型筛选数据
  2. In[122]: ADJ_2017 = .748
  3. def count_crime(df, offense_cat):
  4. df = df[df['OFFENSE_CATEGORY_ID'] == offense_cat]
  5. weekday = df['REPORTED_DATE'].dt.weekday_name
  6. year = df['REPORTED_DATE'].dt.year
  7. ct = df.groupby([year, weekday]).size().unstack()
  8. ct.loc[2017] = ct.loc[2017].div(ADJ_2017).astype('int')
  9. pop = pd.read_csv('data/denver_pop.csv', index_col='Year')
  10. pop = pop.squeeze().div(100000)
  11. ct = ct.div(pop, axis=0).astype('int')
  12. ct = ct.reindex(columns=days)
  13. sns.heatmap(ct, cmap='Greys')
  14. return ct
  15. In[123]: count_crime(crime, 'auto-theft')
  16. Out[123]:

6. 按工作日和年测量犯罪 - 图11