25、时间序列分析:犯罪数据的深入洞察

时间序列分析:犯罪数据的深入洞察

在数据分析领域,时间序列分析是一项强大的工具,它能帮助我们从按时间顺序排列的数据中挖掘出有价值的信息。本文将围绕犯罪数据,详细介绍时间序列分析的多种方法和技巧。

数据准备与索引操作

在处理犯罪数据时,我们首先要关注数据的存储和索引。HDF5 文件是一种很好的数据存储格式,它能保留每列的数据类型,从而显著减少内存需求。例如,将 OFFENSE_TYPE_ID OFFENSE_CATEGORY_ID NEIGHBORHOOD_ID 列存储为 pandas category 类型,比存储为 object 类型能节省大量内存:

mem_cat = crime.memory_usage().sum()
mem_obj = crime.astype({'OFFENSE_TYPE_ID':'object',
                        'OFFENSE_CATEGORY_ID':'object',
                        'NEIGHBORHOOD_ID':'object'}) \
               .memory_usage(deep=True).sum()
mb = 2 ** 20
round(mem_cat / mb, 1), round(mem_obj / mb, 1)

为了能按日期智能选择和切片行,索引必须包含日期值。我们将 REPORTED_DATE 列移到索引中,创建一个 DatetimeIndex

crime = pd.read_hdf('data/crime.h5', 'crime') \
          .set_index('REPORTED_DATE')
print(type(crime.index))

有了 DatetimeIndex ,我们可以使用 .loc 索引器通过各种字符串来选择行,甚至索引操作符本身也能达到相同效果。不过,个人更推荐使用 .loc 索引器,因为它更明确,传入的第一个值总是用于选择行。

排序索引能显著提高性能。对比未排序和排序后的 DataFrame 在切片操作上的性能:

%timeit crime.loc['2015-3-4':'2016-1-1']
crime_sort = crime.sort_index()
%timeit crime_sort.loc['2015-3-4':'2016-1-1']

排序后的 DataFrame 性能提升了约 50 倍。

基于 DatetimeIndex 的方法使用

有许多 DataFrame Series 方法只能在 DatetimeIndex 上使用。以下是一些具体操作:
1. 按时间范围选择 :使用 between_time 方法选择所有在凌晨 2 点到 5 点发生的犯罪,无论日期如何:

crime.between_time('2:00', '5:00', include_end=False).head()
  1. 按特定时间选择 :使用 at_time 方法选择所有在特定时间的日期:
crime.at_time('5:47').head()
  1. 选择前 n 个时间片段 :使用 first 方法选择前 n 个时间片段,这里的时间片段由 DateOffset 对象表示。例如,选择前六个月的犯罪数据:
crime_sort = crime.sort_index()
crime_sort.first(pd.offsets.MonthBegin(6))

但这种方法可能会因为索引的时间组件而出现意外结果。可以使用 normalize 参数将时间组件设置为零,或者直接使用切片操作来获得更准确的结果:

crime_sort.first(pd.offsets.MonthBegin(6, normalize=True))
crime_sort.loc[:'2012-06']
  1. 使用偏移别名 :除了直接使用 DateOffset 对象,还可以使用偏移别名。例如:
crime_sort.first('5D') # 5 天
crime_sort.first('5B') # 5 个工作日
crime_sort.first('7W') # 7 周,周日结束
crime_sort.first('3QS') # 第三季度开始
crime_sort.first('A') # 一年结束
每周犯罪数量统计

统计每周的犯罪数量是时间序列分析中的常见需求。我们可以使用 resample groupby 方法来实现:
1. 数据准备 :读取犯罪数据,设置索引并排序:

crime_sort = pd.read_hdf('data/crime.h5', 'crime') \
               .set_index('REPORTED_DATE') \
               .sort_index()
  1. 使用 resample 方法 :使用 resample 方法按周分组,并使用 size 方法统计每周的犯罪数量:
crime_sort.resample('W')
weekly_crimes = crime_sort.resample('W').size()
weekly_crimes.head()

默认情况下,周日被选为一周的最后一天,并作为结果 Series 中每个元素的标签。我们可以手动切片数据来验证结果的准确性:

len(crime_sort.loc[:'2012-1-8'])
len(crime_sort.loc['2012-1-9':'2012-1-15'])

还可以使用锚定偏移来选择不同的周结束日:

crime_sort.resample('W-THU').size().head()
  1. 使用 groupby 方法 groupby 方法也能实现类似功能,但需要传入 pd.Grouper 对象:
weekly_crimes_gby = crime_sort.groupby(pd.Grouper(freq='W')) \
                              .size()
weekly_crimes_gby.head()
weekly_crimes.equal(weekly_crimes_gby)
  1. 更多操作 :即使索引不包含时间戳,也可以使用 resample groupby 方法,通过 on key 参数指定包含时间戳的列。还可以绘制每周犯罪数量的折线图:
crime = pd.read_hdf('data/crime.h5', 'crime')
weekly_crimes2 = crime.resample('W', on='REPORTED_DATE').size()
weekly_crimes2.equals(weekly_crimes)

weekly_crimes_gby2 = crime.groupby(pd.Grouper(key='REPORTED_DATE',
                                              freq='W')).size()
weekly_crimes_gby2.equals(weekly_crimes_gby)

weekly_crimes.plot(figsize=(16, 4), title='All Denver Crimes')
犯罪和交通事故的季度聚合

在丹佛的犯罪数据中,犯罪和交通事故记录在同一个表中,通过 IS_CRIME IS_TRAFFIC 列区分。我们可以按季度对这两类数据分别进行聚合:
1. 数据准备 :读取数据,设置索引并排序:

crime_sort = pd.read_hdf('data/crime.h5', 'crime') \
               .set_index('REPORTED_DATE') \
               .sort_index()
  1. 按季度聚合 :使用 resample 方法按季度分组,并对 IS_CRIME IS_TRAFFIC 列求和:
crime_quarterly = crime_sort.resample('Q')['IS_CRIME',
                                           'IS_TRAFFIC'].sum()
crime_quarterly.head()
  1. 使用不同偏移别名 Q 表示季度结束, QS 表示季度开始。可以使用不同的偏移别名来调整季度的计算方式:
crime_sort.resample('QS')['IS_CRIME',
                          'IS_TRAFFIC'].sum().head()
  1. 结果验证 :手动切片数据验证结果的准确性:
crime_sort.loc['2012-4-1':'2012-6-30',
               ['IS_CRIME', 'IS_TRAFFIC']].sum()
  1. 使用 groupby 方法 :同样可以使用 groupby 方法实现相同的聚合:
crime_quarterly2 = crime_sort.groupby(pd.Grouper(freq='Q')) \
                             ['IS_CRIME', 'IS_TRAFFIC'].sum()
crime_quarterly2.equals(crime_quarterly)
  1. 可视化分析 :绘制犯罪和交通事故的趋势图,以便更好地分析趋势:
plot_kwargs = dict(figsize=(16,4),
                   color=['black', 'lightgrey'],
                   title='Denver Crimes and Traffic Accidents')
crime_quarterly.plot(**plot_kwargs)

还可以绘制犯罪和交通事故的百分比增长图,以获得不同的视觉视角:

crime_begin = crime_quarterly.iloc[0]
crime_quarterly.div(crime_begin) \
               .sub(1) \
               .round(2) \
               .plot(**plot_kwargs)

通过以上方法,我们可以深入分析犯罪数据的时间特征,为决策提供有力支持。在实际应用中,我们可以根据具体需求选择合适的方法和参数,以获得更准确和有价值的结果。

以下是一个简单的流程图,展示了统计每周犯罪数量的主要步骤:

graph TD;
    A[读取数据] --> B[设置索引并排序];
    B --> C[使用 resample 方法分组];
    C --> D[使用 size 方法统计数量];
    D --> E[验证结果];
    B --> F[使用 groupby 方法分组];
    F --> D;
操作 方法 示例代码
按时间范围选择 between_time crime.between_time(‘2:00’, ‘5:00’, include_end=False).head()
按特定时间选择 at_time crime.at_time(‘5:47’).head()
选择前 n 个时间片段 first crime_sort.first(pd.offsets.MonthBegin(6))
统计每周犯罪数量 resample + size crime_sort.resample(‘W’).size()
按季度聚合 resample + sum crime_sort.resample(‘Q’)[‘IS_CRIME’, ‘IS_TRAFFIC’].sum()

时间序列分析:犯罪数据的深入洞察

深入理解 resample groupby 方法

在前面的内容中,我们已经介绍了使用 resample groupby 方法进行时间序列分析的基本操作。下面我们将进一步深入理解这两个方法的工作原理和更多细节。

resample 方法默认与 DatetimeIndex 配合使用,它的第一个参数是规则,用于确定如何对索引中的时间戳进行分组。例如,使用偏移别名 W 将数据按周分组,默认以周日为一周的结束日。我们可以通过以下代码查看 resample 对象可用的属性和方法:

r = crime_sort.resample('W')
resample_methods = [attr for attr in dir(r) if attr[0].islower()]
print(resample_methods)

这些方法包括 agg aggregate apply 等,可用于对分组后的数据进行各种操作。

虽然 resample 方法在按时间戳分组时很方便,但实际上 groupby 方法也能实现相同的功能。使用 groupby 方法时,需要传入 pd.Grouper 对象,并通过 freq 参数指定偏移量。例如:

weekly_crimes_gby = crime_sort.groupby(pd.Grouper(freq='W')) \
                              .size()

这两种方法的结果是等价的:

weekly_crimes.equal(weekly_crimes_gby)
自定义 DateOffset 对象

当现有的 DateOffset 对象不能满足需求时,我们可以自定义 DateOffset 对象。例如:

dt = pd.Timestamp('2012-1-16 13:40')
dt + pd.DateOffset(months=1)

还可以使用多个日期和时间组件来创建自定义的 DateOffset 对象:

do = pd.DateOffset(years=2, months=5, days=3,
                   hours=8, seconds=10)
pd.Timestamp('2012-1-22 03:22') + do
不同季度锚定偏移的应用

在按季度聚合犯罪和交通事故数据时,不同的锚定偏移可以满足不同的业务需求。默认情况下,偏移别名 Q 以 12 月 31 日为一年的最后一天,计算季度范围,并以季度的最后一天作为聚合结果的标签。而 QS 以 1 月 1 日为一年的第一天。

如果我们希望季度从 3 月 1 日开始,可以使用 QS - MAR 来锚定偏移别名:

crime_sort.resample('QS-MAR')['IS_CRIME', 'IS_TRAFFIC'] \
          .sum().head()

这对于那些财务年度不从 1 月 1 日开始的企业或组织非常有用。

总结与建议

通过对犯罪数据的时间序列分析,我们可以总结出以下几点:
1. 数据准备 :确保索引为 DatetimeIndex ,并对数据进行排序,以提高性能。
2. 方法选择 resample 方法提供了更简洁的按时间分组方式,而 groupby 方法结合 pd.Grouper 也能实现相同功能。
3. DateOffset 对象 :灵活使用 DateOffset 对象和偏移别名,可以精确控制时间范围的选择。
4. 结果验证 :在进行数据分析时,手动切片数据验证结果的准确性是很重要的。

以下是一个总结表格,对比了不同方法的特点和适用场景:
| 方法 | 特点 | 适用场景 |
| — | — | — |
| resample | 专门用于时间序列分组,使用偏移别名方便 | 按固定时间间隔分组统计 |
| groupby + pd.Grouper | 通用分组方法,结合 pd.Grouper 实现时间分组 | 复杂分组需求,可结合其他分组条件 |
| between_time | 按时间范围选择 | 选择特定时间段内的数据 |
| at_time | 按特定时间选择 | 选择特定时间点的数据 |
| first | 选择前 n 个时间片段 | 选择数据的起始部分 |

下面是一个流程图,展示了整个犯罪数据时间序列分析的主要步骤:

graph TD;
    A[读取数据] --> B[设置索引并排序];
    B --> C[按时间选择数据];
    C --> D[按时间分组统计];
    D --> E[验证结果];
    E --> F[可视化分析];
    C --> G[自定义时间范围];
    G --> D;

通过以上的分析和操作,我们可以更好地理解犯罪数据的时间特征,为城市安全规划、资源分配等提供有价值的参考。在实际应用中,我们可以根据具体问题进一步扩展和优化分析方法,以获得更深入的洞察。

希望本文能帮助你掌握时间序列分析的基本方法和技巧,在实际项目中灵活运用这些方法解决问题。如果你有任何疑问或建议,欢迎在评论区留言。

基于分布式模型预测控制的多个固定翼无人机一致性控制(Matlab代码实现)内容概要:本文围绕“基于分布式模型预测控制的多个固定翼无人机一致性控制”展开,采用Matlab代码实现相关算法,属于顶级EI期刊的复现研究成果。文中重点研究了分布式模型预测控制(DMPC)在多无人机系统中的一致性控制问题,通过构建固定翼无人机的动力学模型,结合分布式协同控制策略,实现多无人机在复杂环境下的轨迹一致性和稳定协同飞行。研究涵盖了控制算法设计、系统建模、优化求解及仿真验证全过程,并提供了完整的Matlab代码支持,便于读者复现实验结果。; 适合人群:具备自动控制、无人机系统或优化算法基础,从事科研或工程应用的研究生、科研人员及自动化、航空航天领域的研发工程师;熟悉Matlab编程和基本控制理论者更佳; 使用场景及目标:①用于多无人机协同控制系统的算法研究与仿真验证;②支撑科研论文复现、毕业设计或项目开发;③掌握分布式模型预测控制在实际系统中的应用方法,提升对多智能体协同控制的理解与实践能力; 阅读建议:建议结合提供的Matlab代码逐模块分析,重点关注DMPC算法的构建流程、约束处理方式及一致性协议的设计逻辑,同时可拓展学习文中提及的路径规划、编队控制等相关技术,以深化对无人机集群控制的整体认知。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值