26、时间序列分析:犯罪数据洞察与分组技巧

时间序列分析:犯罪数据洞察与分组技巧

在数据分析领域,时间序列分析是一项强大的工具,它能帮助我们从时间维度上深入理解数据的变化规律。本文将结合犯罪数据和员工薪资数据,详细介绍如何利用Python的Pandas库进行时间序列分析,包括按工作日和年份统计犯罪数量、使用匿名函数分组以及按时间戳和其他列分组等操作。

按工作日和年份统计犯罪数量

在处理犯罪数据时,我们常常需要了解不同工作日和年份的犯罪情况。通过使用Pandas的 dt 访问器,我们可以轻松地从时间戳中提取所需信息。

操作步骤
  1. 读取数据
import pandas as pd

crime = pd.read_hdf('data/crime.h5', 'crime')
crime.head()
  1. 统计工作日犯罪数量
wd_counts = crime['REPORTED_DATE'].dt.weekday_name.value_counts()
print(wd_counts)

输出结果显示,周末的犯罪和交通事故数量明显较少。
| Weekday | Count |
| ---- | ---- |
| Monday | 70024 |
| Friday | 69621 |
| Wednesday | 69538 |
| Thursday | 69287 |
| Tuesday | 68394 |
| Saturday | 58834 |
| Sunday | 55213 |

  1. 绘制工作日犯罪数量水平条形图
days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
title = 'Denver Crimes and Traffic Accidents per Weekday'
wd_counts.reindex(days).plot(kind='barh', title=title)
  1. 统计年份犯罪数量并绘图
title = 'Denver Crimes and Traffic Accidents per Year'
crime['REPORTED_DATE'].dt.year.value_counts().sort_index().plot(kind='barh', title=title)
  1. 按工作日和年份分组统计犯罪数量
weekday = crime['REPORTED_DATE'].dt.weekday_name
year = crime['REPORTED_DATE'].dt.year
crime_wd_y = crime.groupby([year, weekday]).size()
print(crime_wd_y.head(10))
  1. 重塑数据以方便比较
crime_table = crime_wd_y.rename_axis(['Year', 'Weekday']).unstack('Weekday')
print(crime_table)
  1. 处理2017年不完整数据
criteria = crime['REPORTED_DATE'].dt.year == 2017
last_day_2017 = crime.loc[criteria, 'REPORTED_DATE'].dt.dayofyear.max()
print(last_day_2017)
  1. 计算历史数据中前272天犯罪的平均百分比
crime_pct = crime['REPORTED_DATE'].dt.dayofyear.le(272).groupby(year).mean().round(3)
print(crime_pct)
median_pct = crime_pct.loc[2012:2016].median()
print(median_pct)
  1. 更新2017年数据并调整列顺序
crime_table.loc[2017] = crime_table.loc[2017].div(median_pct).astype('int')
crime_table = crime_table.reindex(columns=days)
print(crime_table)
  1. 绘制犯罪数量热力图
import seaborn as sns
sns.heatmap(crime_table, cmap='Greys')
  1. 考虑人口因素,计算犯罪率
denver_pop = pd.read_csv('data/denver_pop.csv', index_col='Year')
den_100k = denver_pop.div(100000).squeeze()
crime_table2 = crime_table.div(den_100k, axis='index').astype('int')
print(crime_table2)
  1. 绘制调整后犯罪率热力图
sns.heatmap(crime_table2, cmap='Greys')
原理分析
  • dt 访问器:所有包含时间戳的DataFrame列都可以通过 dt 访问器访问许多额外的属性和方法。
  • groupby 方法:非常灵活,可以接受多个Series或函数作为参数,形成不同的分组。
  • unstack 方法:用于将多层索引的Series转换为DataFrame,方便数据比较。
使用匿名函数分组

当DataFrame具有 DatetimeIndex 时,我们可以利用 groupby 方法的特殊功能,使用匿名函数进行分组。

操作步骤
  1. 读取数据并设置索引
crime_sort = pd.read_hdf('data/crime.h5', 'crime').set_index('REPORTED_DATE').sort_index()
  1. 查看 DatetimeIndex Timestamp 的共同属性和方法
common_attrs = set(dir(crime_sort.index)) & set(dir(pd.Timestamp))
print([attr for attr in common_attrs if attr[0] != '_'])
  1. 使用索引统计工作日犯罪数量
crime_sort.index.weekday_name.value_counts()
  1. 使用匿名函数按工作日分组统计犯罪和交通事故数量
crime_sort.groupby(lambda x: x.weekday_name)['IS_CRIME', 'IS_TRAFFIC'].sum()
  1. 使用多个匿名函数按小时和年份分组并重塑数据
funcs = [lambda x: x.round('2h').hour, lambda x: x.year]
cr_group = crime_sort.groupby(funcs)['IS_CRIME', 'IS_TRAFFIC'].sum()
cr_final = cr_group.unstack()
cr_final.style.highlight_max(color='lightgrey')
原理分析
  • DatetimeIndex 具有与单个 Timestamp 对象相似的功能,可以直接使用其属性和方法。
  • groupby 方法可以接受函数作为参数,函数的返回值用于形成分组。
按时间戳和其他列分组

在处理员工薪资数据时,我们可能需要按时间戳(如入职日期)和其他列(如性别)进行分组。

操作步骤
  1. 读取数据并创建 DatetimeIndex
employee = pd.read_csv('data/employee.csv', parse_dates=['JOB_DATE', 'HIRE_DATE'], index_col='HIRE_DATE')
employee.head()
  1. 按性别分组计算平均薪资
avg_salary_by_gender = employee.groupby('GENDER')['BASE_SALARY'].mean().round(-2)
print(avg_salary_by_gender)
  1. 按入职日期分组计算平均薪资
avg_salary_by_hire_date = employee.resample('10AS')['BASE_SALARY'].mean().round(-2)
print(avg_salary_by_hire_date)
  1. 先按性别分组,再按10年时间跨度分组计算平均薪资
avg_salary_by_gender_and_time = employee.groupby('GENDER').resample('10AS')['BASE_SALARY'].mean().round(-2)
print(avg_salary_by_gender_and_time)
  1. 尝试比较男女薪资时出现的问题
sal_avg = employee.groupby('GENDER').resample('10AS')['BASE_SALARY'].mean().round(-2)
sal_avg.unstack('GENDER')

结果显示,男女的10年时间段起始日期不同,导致数据无法对齐。
6. 验证最早入职员工的年份

earliest_male_hire = employee[employee['GENDER'] == 'Male'].index.min()
earliest_female_hire = employee[employee['GENDER'] == 'Female'].index.min()
print(earliest_male_hire)
print(earliest_female_hire)
  1. 使用 groupby 方法同时按性别和时间分组
sal_avg2 = employee.groupby(['GENDER', pd.Grouper(freq='10AS')])['BASE_SALARY'].mean().round(-2)
print(sal_avg2)
  1. 重塑数据以方便比较
sal_final = sal_avg2.unstack('GENDER')
print(sal_final)
原理分析
  • resample 方法只能按时间周期分组,而 groupby 方法可以同时按时间戳和其他列分组。
  • pd.Grouper 可以复制 resample 的功能,通过设置 freq 参数指定时间周期。

通过以上操作,我们可以清晰地看到不同工作日和年份的犯罪情况,以及不同性别和入职时间的员工薪资差异。时间序列分析为我们提供了深入理解数据的视角,帮助我们做出更明智的决策。

时间序列分析:犯罪数据洞察与分组技巧(续)

后续优化与拓展

在前面的分析中,我们已经完成了按工作日和年份统计犯罪数量、使用匿名函数分组以及按时间戳和其他列分组等操作。接下来,我们将进一步优化和拓展这些分析。

封装函数进行特定犯罪类型分析

为了方便对特定类型的犯罪进行分析,我们可以封装一个函数,将前面的步骤整合在一起,并添加选择特定犯罪类型的功能。

ADJ_2017 = 0.748
days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']

def count_crime(df, offense_cat):
    df = df[df['OFFENSE_CATEGORY_ID'] == offense_cat]
    weekday = df['REPORTED_DATE'].dt.weekday_name
    year = df['REPORTED_DATE'].dt.year
    ct = df.groupby([year, weekday]).size().unstack()
    ct.loc[2017] = ct.loc[2017].div(ADJ_2017).astype('int')
    pop = pd.read_csv('data/denver_pop.csv', index_col='Year')
    pop = pop.squeeze().div(100000)
    ct = ct.div(pop, axis=0).astype('int')
    ct = ct.reindex(columns=days)
    sns.heatmap(ct, cmap='Greys')
    return ct

# 示例:分析汽车盗窃犯罪
count_crime(crime, 'auto - theft')

这个函数接受一个DataFrame和一个犯罪类型作为参数,返回一个经过处理的DataFrame,并绘制相应的热力图。

多索引列数据的选择

在使用多个匿名函数分组后,得到的结果是一个具有多索引列的DataFrame。我们可以使用 xs 方法选择特定的数据。

# 选择交通事故数据
traffic_data = cr_final.xs('IS_TRAFFIC', axis='columns', level=0).head()
print(traffic_data)

# 选择2016年的数据
data_2016 = cr_final.xs(2016, axis='columns', level=1).head()
print(data_2016)

xs 方法允许我们从多索引的任何级别选择单个值,通过指定 axis level 参数来确定选择的位置。

总结与流程图

通过以上的分析,我们可以总结出整个时间序列分析的流程:

graph LR
    classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px;
    classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
    classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px;

    A([开始]):::startend --> B(读取数据):::process
    B --> C{数据类型}:::decision
    C -->|犯罪数据| D(按工作日和年份统计犯罪数量):::process
    D --> E(处理不完整数据):::process
    E --> F(考虑人口因素计算犯罪率):::process
    F --> G(绘制热力图):::process
    C -->|员工数据| H(按时间戳和其他列分组):::process
    H --> I(处理分组数据对齐问题):::process
    I --> J(计算平均薪资):::process
    J --> K(绘制图表或展示结果):::process
    D --> L(使用匿名函数分组):::process
    L --> M(选择特定数据):::process
    G --> N([结束]):::startend
    K --> N
    M --> N

这个流程图展示了整个时间序列分析的主要步骤,包括数据读取、不同类型数据的处理、分组操作、数据处理和结果展示等。

关键要点回顾
  • dt 访问器 :是处理时间戳数据的强大工具,可用于提取时间相关的信息,如工作日名称、年份等。
  • groupby 方法 :非常灵活,可以接受Series、函数等作为参数,实现多种分组方式。
  • unstack 方法 :用于将多层索引的Series转换为DataFrame,方便数据的比较和分析。
  • resample 方法 :用于按时间周期对数据进行分组,但只能处理时间戳数据。
  • pd.Grouper :可以复制 resample 的功能,并且可以与其他列一起使用,实现更复杂的分组。
  • xs 方法 :用于从多索引的DataFrame中选择特定的数据。

通过掌握这些方法和技巧,我们可以更深入地分析时间序列数据,发现数据中的规律和趋势,为决策提供有力的支持。

在实际应用中,我们可以根据具体的需求对这些方法进行组合和扩展,以满足不同的分析场景。例如,我们可以进一步分析不同时间段内犯罪类型的变化趋势,或者研究员工薪资与工作绩效之间的关系等。时间序列分析为我们打开了一扇了解数据动态变化的窗口,让我们能够更好地应对各种复杂的数据分析问题。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值