如何用Python和Pandas分析犯罪记录开放数据?

数据

首先,访问 Denton 开放数据主页,地址是 

欢迎大家加入小编创建的Python行业交流群,有大牛答疑,有资源共享,有企业招人!是一个非常不错的交流基地!群号:683380553

http://data.cityofdenton.com/ 

如何用Python和Pandas分析犯罪记录开放数据?

首页就有搜索栏,我们可以输入“crime”(犯罪)进行查询。

这是返回的搜索结果。

如何用Python和Pandas分析犯罪记录开放数据?

结果不仅包含数据名称,还有数据类型。第一条是 csv 格式,最符合我们分析的需求,因此我们点击第一项链接。

如何用Python和Pandas分析犯罪记录开放数据?

在这个页面,我们点击右侧蓝色“explore”旁边的下拉按钮,可以看到“预览”和“下载”选项。我们可以直接下载数据集。但此处请你复制下载链接,放到笔记软件或者编辑器里面,备用。

环境

本文的配套源代码,我放在了 Github 项目中。请你点击这个链接访问

http://t.cn/EIKS05O

如何用Python和Pandas分析犯罪记录开放数据?

如果你对我的教程满意,欢迎在页面右上方的 Star 上点击一下,帮我加一颗星。谢谢!

注意这个页面的*,有个按钮,写着“在 Colab 打开”(Open in Colab)。请你点击它。

然后,Google Colab 就会自动开启。

如何用Python和Pandas分析犯罪记录开放数据?

Colab 为你提供了全套的运行环境。你只需要依次执行代码,就可以复现本教程的运行结果了。如果你对 Google Colab 不熟悉,没关系。我这里有一篇教程,专门讲解 Google Colab 的特点与使用方式。为了你能够更为深入地学习与了解代码,我建议你在 Google Colab 中开启一个全新的 Notebook ,并且根据下文,依次输入代码并运行。在此过程中,充分理解代码的含义。

这种看似笨拙的方式,其实是学习的有效路径。

代码

首先,将我们前面获取到的数据下载地址,存入到 url 变量中。

url ="http://data.cityofdenton.com/dataset/17695047-0aeb-46a2-a9db-66847743ed1c/resource/d356a409-6764-46d7-942d-4d5a7ffb1c28/download/crime_data_20190301.csv"

然后,利用 wget 命令,把 csv 格式的数据下载到本地。

!wget {url}

crime_data_20190301100%[===================>]9.22M8.22MB/sin1.1s

2019-03-0402:31:39(8.22MB/s) - ‘crime_data_20190301.csv’ saved [9667384/9667384]

读入 Pandas 软件包。

importpandasaspd

用 Pandas 的 csv 数据格式读取功能,把数据读入,并且存入到 df 变量里面。

df = pd.read_csv('crime_data_20190301.csv')

让我们看看 df 的前几行。

df.head()

如何用Python和Pandas分析犯罪记录开放数据?

好的,数据已经成功读取。

下面我们来着重分析一下,都有哪些犯罪类型,每种类型下,又有多少记录。

这里我们使用的是 Pandas 中的 value_counts 函数。它可以帮助我们自动统计某一列中不同类别出现的次数,而且还自动进行排序。为了显示的方便,我们只要求展示前10项内容。

df.crime.value_counts().iloc[:10]

如何用Python和Pandas分析犯罪记录开放数据?

看来, Denton 最主要的犯罪类型,是“轻微人身攻击”(Simple Assault)。“酒醉”(Drunkenness)的次数也不少,排名第三位。

为了更直观查看数据统计结果,我们调用 Pandas 内置的绘图函数 plot ,并且指定绘图类型为“横向条状图”(barh)。

df.crime.value_counts().iloc[:10].sort_values().plot(kind='barh')

如何用Python和Pandas分析犯罪记录开放数据?

这样看起来,一目了然。

下面,我们着重了解某一种犯罪的情况。因为犯罪类型五花八门,所以我们从中选择一种严重的暴力犯罪——抢劫(Robbery)。

这里,为了后续分析的便利。我们首先把抢劫类型的犯罪单独提炼出来,存储在 robbery 这样一个新的数据框里。

robbery = df[df.crime.str.contains('ROBBERY')]; robbery.head()

如何用Python和Pandas分析犯罪记录开放数据?

我们来看看 robbery 数据框的大小。

robbery.shape

(660, 6)

一共是660条记录,每条记录有6列。

我们查看一下“犯罪位置”(locname)类型,以及每种类型对应的记录条目数。

这次,我们使用 groupby 函数,先把犯罪位置进行分类,然后用 size 函数来查看条目统计。

这里,我们指定排序为从大到小。

robbery.groupby('locname').size().sort_values(ascending=False)

作为练习,希望你可以用 value_counts 函数,自己改写上面的语句。

如何用Python和Pandas分析犯罪记录开放数据?

根据结果显示,入室抢劫次数最多,在学校、公交车上发生的次数最少。

下面还是用 plot 函数,把结果可视化呈现。

robbery.groupby('locname').size().sort_values(ascending=False).head(10).sort_values().plot(kind='barh')

如何用Python和Pandas分析犯罪记录开放数据?

下一步,我们尝试把分析的粒度做得更加细致——研究一下,哪些街区比较危险。

如何用Python和Pandas分析犯罪记录开放数据?

回顾上图中,地址信息都表示为类似“19XX BRINKER RD”这样的方式。把具体地址的后两位隐藏,是为了保护受害者的隐私。

我们如果要统计某一条街道的犯罪数量,就需要把前面的数字忽略,并且按照街道名称加总。

这个处理起来,并不困难,只要用正则表达式即可。

regex =r"\d+XX\s(?P<street>.*)"

subst ="\\g<street>"

这里,我们用括号把需要保留的内容,赋值为 street 分组。然后替换的时候,只保留这个分组的信息。于是前面的具体地址数字就忽略了。

调用 Pandas 的 str.replace 函数,我们可以让它自动将每一个地址都进行解析替换,并且把结果存入到了一个新的列名称,即 street 。

robbery["street"] = robbery.publicadress.str.replace(regex, subst)

看看此时新的 robbery 数据框样子。

robbery.head()

如何用Python和Pandas分析犯罪记录开放数据?

注意最后多出来的一列,确实已经变成了我们希望转换的形式。

依然按照前面的方法,我们分组统计每一条街道上的犯罪数量,并且进行排序。

robbery.groupby('street').size().sort_values(ascending=False).head(10)

如何用Python和Pandas分析犯罪记录开放数据?

看来,大学西道(W University DR)抢劫频发,没事儿最好少去瞎转悠。我住的街道还好,没有出现在前10名的范畴。

注意,我们其实是在分析10年的犯罪信息汇总。如果更进一步,想要利用时间数据,进行切分,我们就得把日期信息做一下转换处理。

这里,请你安装一个特别好用的时间分析软件包 python-dateutil 。我第一次使用的时候,立即决定弃用 datetime 包了。

!pip install python-dateutil

我们从 dateutil 里面的 parser 模块,载入全部内容。

fromdateutil.parserimport*

下面,我们抽取年度信息。因为目前的日期时间列(incidentdatetime)是个字符串,因此我们可以直接用 parse 函数解析它,并且抽取其中的年份(year)项。

robbery["year"] = robbery.incidentdatetime.apply(lambdax: parse(x).year)

以此类推,我们抽取“月”和“小时”的信息。

robbery["month"] = robbery.incidentdatetime.apply(lambdax: parse(x).month)

robbery["hour"] = robbery.incidentdatetime.apply(lambdax: parse(x).hour)

好了,来看看此时的 robbery 数据框。

robbery.head()

如何用Python和Pandas分析犯罪记录开放数据?

注意后三列是我们刚刚生成的。

我们先按照年度来看看抢劫犯罪数量的变化趋势。

robbery.groupby('year').size()

如何用Python和Pandas分析犯罪记录开放数据?

注意这里,数量最少的是 2019 年。看似是很喜人的变化。可惜我们分析数据的时候,一定要留心这种细节。我们读取的数据,统计时间截止到 2019 年的 3 月初。因此,2019年数据并不全。

所以,比较稳妥的方法,是干脆去掉所有2019年的条目。

robbery = robbery[~(robbery.year ==2019)]

去除后,看看此时的 robbery 数据框。

robbery.shape

(643, 10)

数量没错,恰好少了 17 行。

好了,我们来绘制一下抢劫犯罪数量变化趋势折线图。

Pandas 的 plot 函数,默认状态下,就是绘制折线图。因此我们不需要加入参数。

robbery.groupby('year').size().plot()

如何用Python和Pandas分析犯罪记录开放数据?

看来,从 2013 到 2016 年的抢劫犯罪形成了一个低谷。近两年的数据,又有上行的趋势。

但是,我们能否就此得出结论,说 Denton 这两年的治安,越来越差了呢?

还不行。

因为考虑犯罪,不能只看绝对数值,还要看相对比例。我这里给你提供一个数据源,请你参考它,进行比例数值计算,修正上面的折线图。

下面,我们比较一下,不同月份之间,是否有明显的抢劫犯罪发生数量差别。

robbery.groupby('month').size().plot(kind='bar')

如何用Python和Pandas分析犯罪记录开放数据?

从上图中,可以看到,从 2010 到 2018 年,10月和12月犯罪数量较多,2月和7月相对好一些。

但是,我们可能更加关心近年的情况。因为扔掉了2019年的不完整数据,此时我们能使用的最近年份,是2018。

我们就把2018年的月份犯罪记录统计做可视化。

robbery[robbery.year==2018].groupby('month').size().plot(kind='bar')

如何用Python和Pandas分析犯罪记录开放数据?

2018年的10月,犯罪数量相对不算高,但12月看来确实是需要注意安全的。

下面我们来看看,抢劫一般发生在什么时间。这次我们用的,是小时(hour)数据。

robbery.groupby('hour').size().plot(kind='bar')

如何用Python和Pandas分析犯罪记录开放数据?

从总体数据看来,每天早上8点,你是不用太担心抢劫的;晚上23点嘛……

我们再看看2018年的情况。

robbery[robbery.year==2018].groupby('hour').size().plot(kind='bar')

如何用Python和Pandas分析犯罪记录开放数据?

8点依然比较安全。但是最危险的时段,变成了晚上8点多。莫非劫匪们也打算早点儿休息?

如果我们更加小心谨慎,还可以根据不同月份,来查看不同时段的抢劫案件发生数量。

这里,我们把 groupby 里面的单一变量,换成一个列表。于是 Pandas 就会按照列表中指定的顺序,先按照月份分组,再按照小时分组。

robbery[robbery.year==2018].groupby(['month','hour']).size()

如何用Python和Pandas分析犯罪记录开放数据?

但是这样的统计结果,无法直接绘制。我们需要做一个变换。这里用的是 Pandas 中的 unstack 函数,把内侧的分组索引(hour)转换到列上。

robbery[robbery.year==2018].groupby(['month','hour']).size().unstack(0)

如何用Python和Pandas分析犯罪记录开放数据?

因为许多时间段,本来就没有抢劫案件发生,所以这个表中,出现了许多空值(NaN)。我们根据具体情况,采用0来填充。Pandas 中数据填充的函数是 fillna。

robbery[robbery.year==2018].groupby(['month','hour']).size().unstack(0).fillna(0)

如何用Python和Pandas分析犯罪记录开放数据?

好了,这下就可以可视化了。

我们希望绘制的,不是一张图,而是 12 张。分别代表 12 个月。这种图形,有个专门的名称,叫做“分面图”(facet plot)。 Pandas 的 plot 函数有一个非常方便的参数,叫做 subplots ,可以帮助我们轻松达成目标。

每张图,我们依然采用柱状图的方式。因为默认方式绘制的图像,尺寸可能不符合我们的预期。因此我们显式指定图片的长宽。

robbery[robbery.year==2018].groupby(['month','hour']).size().unstack(0).fillna(0).plot(subplots=True, kind='bar', figsize=(5,30))

如何用Python和Pandas分析犯罪记录开放数据?

你看了这张图以后,作何感想?

我觉得,每个月份,这张图对于哪个时段最好不要出门,都具备比较高的指导意义。因此……可以当成黄历来使用。

开个玩笑啦,别当真。

如果你对于图像的品质有追求,我建议你学用 Matplotlib 或者 seaborn 来重绘上图。这也作为今天的最后一道练习题,留给你解决。欢迎你把答案用留言的方式和大家分享。

小结

通过本文的学习,希望你已掌握了以下内容:

如何检索、浏览和获取开放数据;

如何用 Python 和 Pandas 做数据分类统计;

如何在 Pandas 中做数据变换,以及缺失值补充;

如何用 Pandas 中的 plot 函数做折线图、柱状图,以及分面图(facet plot)。

上一篇:word->excel数据处理


下一篇:Python_并发编程总结