Python数据分析实践
没想到这么快就大三了,不考虑考研的话今年暑假该实习了。本来想着在国庆前将前面学的全部梳理一下(其实这原本是暑假的明目标),然后这一年全力准备实习。没想到开学就来了个短学期😕,不过也好做个项目也可以检验自己的水平。虽然时间有点短项目有点小很多东西来不及做,但我还是尽量把能用上的用上。
通过此次实践可以巩固以下几个技术:
- 数据分析
- 爬虫
- 可视化交互(这次时间较短所以没有使用前端技术,主要使用 Python 实现)
- Linux 部署项目
- Git 版本控制
废话不多说,下面开始:
背景
基于阿里云天池提供的 arXiv 中公开的论文数据集, 通过数据分析研究学术发展趋势。
数据集和相关资料在这。
前期准备
需求分析
先建立大致分析目标,后续再慢慢调整:
- 每种类型论文数量
- 按月份统计每个月论文的提交数量
- 论文摘要和论文标题出现关键词的频率
- 论文更新次数
- 论文作者关系(联通图)
- 作者的论文个数排行
- 页数、图、表统计
json文件分析
发现给的 json 文件,格式比较乱。所以,使用 json格式化工具 格式化 json 后分析。
{
"id": "0704.0297",
"submitter": "Sung-Chul Yoon",
"authors": "Sung-Chul Yoon, Philipp Podsiadlowski and Stephan Rosswog",
"title": "Remnant evolution after a carbon-oxygen white dwarf merger",
"comments": "15 pages, 15 figures, 3 tables, submitted to MNRAS (Low resolution\n version; a high resolution version can be found at:\n http://www.astro.uva.nl/~scyoon/papers/wdmerger.pdf)",
"journal-ref": null,
"doi": "10.1111/j.1365-2966.2007.12161.x",
"report-no": null,
"categories": "astro-ph",
"license": null,
"abstract": " We systematically explore the evolution of the merger of two carbon-oxygen\n(CO) white dwarfs. The dynamical evolution of a 0.9 Msun + 0.6 Msun CO white\ndwarf merger is followed by a three-dimensional SPH simulation. We use an\nelaborate prescription in which artificial viscosity is essentially absent,\nunless a shock is detected, and a much larger number of SPH particles than\nearlier calculations. Based on this simulation, we suggest that the central\nregion of the merger remnant can, once it has reached quasi-static equilibrium,\nbe approximated as a differentially rotating CO star, which consists of a\nslowly rotating cold core and a rapidly rotating hot envelope surrounded by a\ncentrifugally supported disc. We construct a model of the CO remnant that\nmimics the results of the SPH simulation using a one-dimensional hydrodynamic\nstellar evolution code and then follow its secular evolution. The stellar\nevolution models indicate that the growth of the cold core is controlled by\nneutrino cooling at the interface between the core and the hot envelope, and\nthat carbon ignition in the envelope can be avoided despite high effective\naccretion rates. This result suggests that the assumption of forced accretion\nof cold matter that was adopted in previous studies of the evolution of double\nCO white dwarf merger remnants may not be appropriate. Our results imply that\nat least some products of double CO white dwarfs merger may be considered good\ncandidates for the progenitors of Type Ia supernovae. In this case, the\ncharacteristic time delay between the initial dynamical merger and the eventual\nexplosion would be ~10^5 yr. (Abridged).\n",
"versions": [
{
"version": "v1",
"created": "Tue, 3 Apr 2007 01:50:26 GMT"
},
{
"version": "v2",
"created": "Wed, 4 Apr 2007 17:28:44 GMT"
}
],
"update_date": "2019-08-19",
"authors_parsed": [
[
"Yoon",
"Sung-Chul",
""
],
[
"Podsiadlowski",
"Philipp",
""
],
[
"Rosswog",
"Stephan",
""
]
]
}
字段分析:
id:arXiv ID,可用于访问论文submitter:论文提交者authors:论文作者 4title:文标题comments:论文页数和图表等其他信息 4journal-ref:论文发表的期刊的信息doi:数字对象标识符,https://www.doi.orgreport-no:报告编号categories:论文在 arXiv 系统的所属类别或标签license:文章的许可证abstract:论文摘要versions:论文版本authors_parsed:作者的信息
对 categories 的说明,查询 这个网站 发现 arXiv 将论文分为Computer Science(计算机科学)、Economics(经济学)、Electrical Engineering and Systems Science、(电气工程与系统科学) Mathematics(数学)、Physics(物理)、Quantitative Biology(定量生物学)、Quantitative Finance(定量金融)、Statistics(统计学)8个大类,里面又包含多个小类。因为数量过多,所以为了快速获取全部信息决定使用爬虫获取数据。
爬虫:
- request 库发送网络请求获取网页数据。
- bs4库解析网页文件,提取数据。此外,还可以使用Xpath解析或者使用正则表达式。使用bs4因为语法简单。但是,这个只适用Python。
技术选型
数据分析 Pandas
request、bs4 爬虫
Streamlit + plotly + Altair + pyecharts 可视化
原因:
- 可以实现交互
- 不需要编写前端代码,开发速度快
- 文档丰富
开发工具
- PyCharm
- Jupyter notebook
第一个目标:每种类型论文数量
首先我们爬取了这个网站 的数据。得到了每个小类和大类的对照表,依据源数据 "categories": "astro-ph" 我们可以在对照表中找到对应的大类。然后使用 pandas 连接函数在原来数据的基础上加上了 'group' 字段, 表示每篇论文的大类。但是我们发现并不, 每篇论文只对应一种大类。给的参考代码上是选择第一个类别, 但我们觉得这样不合适,所以决定所有类别都要。因此需要设计一个函数选出包含特定大类的所有数据:
def queryBycategrot(data, categrot):
"""
根据类别查询数据的函数。
参数:
- data:要查询的数据。
- categrot:要按照的类别进行过滤的字符串。
返回:
- 根据指定类别过滤后的数据。
"""
return data[data['group'].str.contains(categrot)]
最后只需要将返回的数据取个长度就可以得到每大类论文的数量。
然后,就可以开始编写代码构建 web应用 展示数据。
在这里我对比了 pyecharts 和 plotly 两个库的区别,结论是:
pyecharts动画交互效果好,交互功能齐全。毕竟有专业前端库Echarts的支持pyecharts默认样式美观,plotly需要自己调整样式plotly代码编写简单,可以快速绘图但交互能力不好- 在
streamlit上 原生支持plotly但pyecharts是第三方支持
总的来说,我更倾向于使用 pyecharts。
性能测试
在这过程中我发现每次运行代码时,总是需要等一段时间。
因为需要进行可视化交互,所以对于程序的运行速度有一定的要求。由于文件的数据量比较大,所以必须要想办法提高运行速度。
通过测试比较 文件读取 与 数据计算 的运行时间,发现程序运行时间主要消耗在 IO 上 ,然后通过修改文件格式为 pkl 成功提高读取数量。测试代码如下:
import pandas as pd
import time
start_time = time.time()
data_csv = pd.read_csv('../arxiv-metadata-oai-2019.csv', dtype={'id': 'str'})
end_time = time.time()
print('csv文件读取时间: ', end_time - start_time)
start_time = time.time()
data_pkl = pd.read_pickle('../arxiv-metadata-oai-2019.pkl')
end_time = time.time()
print('pkl文件读取时间: ', end_time - start_time)
start_time = time.time()
data_csv.groupby('group').size()
end_time = time.time()
print('csv执行时间: ', end_time - start_time)
start_time = time.time()
data_pkl.groupby('group').size()
end_time = time.time()
print('pkl执行时间: ', end_time - start_time)
输出:
csv文件读取时间: 3.394251585006714
pkl文件读取时间: 0.5429229736328125
csv执行时间: 0.009101390838623047
pkl执行时间: 0.008001327514648438
从上面不难看出
- 文件读取占用大量时间
- pkl 文件的读取速度相对于 csv 格式的快了将近 6 倍。
第二个目标:按月份统计每个月论文的提交数量
这个需求比较简单,我们发现数据中存在 "update_date": "2019-08-19"所以我们只需要使用 pandas 将字符串类型转化为时间类型然后按月分组聚合求数量。这样我们就可以画出一个关于每月总论文数量的折线图,这样有点过于单调, 所以我们决定在绘制一个所有大类每月论文发表数量的 气泡图 以及 区域叠加图 。主要过程就是:
- 使用上面函数选出大类数据
- 对月份分组聚合
- 转换为特定的数据格式
- 使用绘图库绘制图形
- 使用
streamlit渲染成网页
第三个目标:论文摘要和论文标题出现关键词的频率
它们分别存储在 "title" 和 "abstract" 字段,两个字段都是字符串。而且是英文的,每个字符都用空格隔开所以需要处理按空格分离单词再统计单词个数。在这个过程中需要注意以下问题:
- 需要先去除标点因为标点符号,因为标点符号和单词之间没有空格
- 需要全部转换为小写,因为有些单词是大写开头
- 需要剔除无意义词,比如:me、of、the
在这里我发现程序执行完成需要一段时间。是因为数据量太多了,所以尝试修改代码。原先是取出一个单词先检查要不要剔除再统计,改为先统计所有单词再剔除无意义单词。这样就减少了大量与停词库比较的时间。但即使是这样,仍旧需要大量时间。但是程序已经没有优化的地方了。所以为了节省演示时间,我决定设置一下数据数量。其实,速度慢是 pandas 决定的,因为 pandas 是单核运行。所以需要加快速度需要使用多核并行的库,甚至是 spark等分布式技术。
最后根据关键字出现的次数构建词云图。
第四个目标:论文更新次数
相关字段长这样
"versions": [
{
"version": "v1",
"created": "Tue, 3 Apr 2007 01:50:26 GMT"
},
{
"version": "v2",
"created": "Wed, 4 Apr 2007 17:28:44 GMT"
}
]
就是一个列表,只需要取列表长度就知道更新次数了。
处理过程:
- 一样先用上面函数选出指定字段的数据
- 取列表长度
- 绘图
绘制图片后发现数据主要集中在 1 、2、3 上所以设计了一个滚动条可以查看不同区间的数据图。
第五个目标:论文作者关系图
相关字段有两个:
"authors": "Sung-Chul Yoon, Philipp Podsiadlowski and Stephan Rosswog"
"authors_parsed": [
[
"Yoon",
"Sung-Chul",
""
],
[
"Podsiadlowski",
"Philipp",
""
],
[
"Rosswog",
"Stephan",
""
]
]
"authors"字符串结构的数据,需要处理一下,因为他虽然姓和名用空格分开每个人用逗号分隔。但是,他最后两个人名是用 and 连接的所以需要特殊判断耗时费力。所以,不用犹豫,果断选择 "authors_parsed"。只需要将每个列表拼接就可以形成人名,然后只需要遍历所有人名,看一下在其余论文中是否存在这个人就行。
本来想着自己写算法实现这个功能的,但是后面发现已经有现成的了,这就是 networkx 库。它可以帮我们快速找到连通图。自己写费时费力速度还不一定有别的快。一样,果断使用 networkx 实现。然后就是绘图。然后做了一些简单统计。
第六个目标:作者的论文个数排行
选择 "submitter"作为论文的主要作者,然后按submitter字段分组聚合。
过程:
- 使用上面函数选出大类数据
- 对提交者字段分组聚合
- 转换为特定的数据格式
- 使用绘图库绘制图形
- 使用
streamlit渲染成网页
为了数据美观,我将行列倒置然后加上颜色映射,即数量越高颜色越深。
第七个目标:页数、图、表统计
相关字段:
"comments": "15 pages, 15 figures, 3 tables, submitted to MNRAS (Low resolution\n
version; a high resolution version can be found at:\n
http://www.astro.uva.nl/~scyoon/papers/wdmerger.pdf)"
可以看到有 15 pages, 15 figures, 3 tables pages 前面的数字表示论文页数、figures 前面的数字表示 图的的个数、tables 前面的数字表示表的个数。
所以只需要使用正则表达式提取相关数据,然后求平均值绘制雷达图。
项目部署
为了使得所有人都能访问项目,需要将项目迁移到云服务器中。主要就三步:
- 申请云服务器(建议使用 Linux 操作系统)
- 安装环境
- 运行项目
这里就不细说怎么做了,网上资源很多我们需要自己学会寻找有用信息。至于怎么使用 Linux 的话,网上教程也很多,我这里也有一些 资料。
总结
这项目我已经放入 Github 中,地址在这。由于就只有两周时间所以做的还是有点简单,后续我还会改进一下加上配置和日志功能。如果有时间的话还会考虑使用 Spark 重写其中部分功能。
