统计2019年后计算机各个方向论文数量
步骤拆解
- 数据导入
- 数据预处理——类别信息拆分、保留19年之后数据
- 获取论文类别信息(爬虫)
- 统计计算机方向论文
- 可视化
1.数据导入
1.1.导入包
# 导入所需的包
import seaborn as sns # 导入画图的包
from bs4 import BeautifulSoup # 导入网页抓取包
import re # 用于正则表达式,匹配字符串
import requests #用于网络连接,发送网络请求,使用域名获取对应信息
import json #读取数据,我们的数据为json格式的(处理网络爬虫数据的常用格式)
import pandas as pd #数据处理、数据分析库
import matplotlib.pyplot as plt #画图工具
1.2 导入数据
# 读入数据
data=[] #初始化 # 使用with语句优势:1.自动关闭文件句柄;2.自动显示(处理)文件读取数据异常
with open("arxiv-metadata-oai-snapshot.json",'r') as f:
for line in f:
data.append(json.loads(line))
data=pd.DataFrame(data) # 将list变为dataframe格式,方便使用pandas进行分析
data.shape #显示数据大小
1.3 查看数据基本信息
data.head()
data.info()
2.数据预处理
2.1 拆分类别字段
# 简单看下类别数据
data["categories"].describe()
# 一共有1796811样本,不同的值由62055种(A+B 和 A+C是不同的两种)
# 出现频率最高的是 astro-ph,频次是86914
# 由于论文的类别不止一种,因此需要将categories字段拆开,分别统计每个类别的数量
unique_categories=set([i for l in [x.split(' ') for x in data["categories"]] for i in l])
# set函数:set() 函数创建一个无序不重复元素集,可进行关系测试,删除重复数据 ——set()是一种创建集合的标准方法
# x.split(' ')表示以空格为分界对数据进行拆分
unique_categories
# 是一个集合
通过计算unique_categories这个集合的项目数得到一共有多少种相互独立的论文类别
len(unique_categories)
# 一共176种不同的论文类型
# len() 方法,用于返回列表、元组的项目数或长度
2.2 仅保留2019年以后的数据(被统计的对象)
- 原来表示时间的update_date字段为object类型,需转换成datetime类数据,从而从中提取出年份数据
# 对时间特征进行处理,只看2019年以后的数据
# 时间数据的字段是update_date
# 简单观察下发现是objetc类的数据,应该要转成datetime类?
data["update_date"].head()
data["year"]=pd.to_datetime(data["update_date"]).dt.year
#pd.to_datetime 转为datetime格式数据
# .dt.year 仅保留年份
data["year"].head()
#转换为年份完毕
#找出时间在2019年以后(含)的所有行
data1=data[data["year"]>=2019]
data1.head(5)
2.3 简单聚合下不同年份、不同类型下的论文数
groupby
被聚合对象.groupby[‘以x字段聚合’,‘以y字段聚合’].统计方式
e.g.
grouped=data1.groupby(['categories','year'])
# 以 categories 进行排序,如果同一个categories 相同则使用 year 特征进行排序
grouped.count()
# 不同类型论文在2019年后不同年度的分布
3.获取论文类别的关联关系
用于锁定哪些论文类型属于计算机类
3.1 爬取论文类型计算关系
re.sub(pattern, repl, string, count=0, flags=0)
关于正则:
- pattern : 正则中的模式字符串
- repl : 替换的字符串,也可为一个函数
- string : 要被查找替换的原始字符串
- count : 模式匹配后替换的最大次数,默认 0 表示替换所有的匹配
- flags : 编译时用的匹配模式,数字形式
- 其中pattern、repl、string为必选参数 ‘’’
# 爬取所有类别
website_url=requests.get('https://arxiv.org/category_taxonomy').text #获取网页的文本数据
soup= BeautifulSoup(website_url,'lxml') #爬取数据,这里使用lxml的解析器,加速
root=soup.find('div',{'id':'category_taxonomy_list'}) #找出 BeautifulSoup 对应的标签入口
tags=root.find_all(["h2","h3","h4","p"], recursive=True) # 读取 tags
# 将网页转为源代码格式,大体能看懂是一个找要爬取位置的操作
# 初始化str和list变量
# 从源代码中大致看出分三个层级
level_1_name=""
level_2_name=""
level_2_code=""
level_1_names=[]
level_2_codes=[]
level_2_names=[]
level_3_codes=[]
level_3_names=[]
level_3_notes=[]
# 进行抓取的过程
for t in tags:
if t.name=="h2":
level_1_name=t.text
level_2_code=t.text
level_2_name=t.text
elif t.name=="h3":
raw=t.text
level_2_code=re.sub(r"(.*)\((.*)\)",r"\2",raw) #正则表达式:模式字符串:(.*)\((.*)\);被替换字符串"\2";被处理字符串:raw
level_2_name=re.sub(r"(.*)\((.*)\)",r"\1",raw)
elif t.name=="h4":
raw=t.text
level_3_code=re.sub(r"(.*) \((.*)\)",r"\1",raw)
level_3_name=re.sub(r"(.*) \((.*)\)",r"\2",raw) # 首位为要替换的,\1和\2是要替换成的
elif t.name=="p":
notes=t.text
level_1_names.append(level_1_name)
level_2_names.append(level_2_name)
level_2_codes.append(level_2_code)
level_3_names.append(level_3_name)
level_3_codes.append(level_3_code)
level_3_notes.append(notes)
#根据以上信息生成dataframe格式的数据
df_taxonomy=pd.DataFrame({
'group_name':level_1_names,
'archive_name':level_2_name,
'archive_id':level_2_codes,
'category_name':level_3_names,
'categories':level_3_codes,
'category_description':level_3_notes
})
#按照 "group_name" 进行分组,在组内使用 "archive_name" 进行排序
df_taxonomy.groupby(["group_name","archive_name"])
df_taxonomy
4.统计计算机方向论文
连接原来的论文数据与论文类别
_df = data1.merge(df_taxonomy, on="categories", how="left").drop_duplicates(["id","group_name"]).groupby("group_name").agg({"id":"count"}).sort_values(by="id",ascending=False).reset_index()
_df
5.可视化
fig = plt.figure(figsize=(15,12))
explode = (0, 0, 0, 0.2, 0.3, 0.3, 0.2, 0.1)
plt.pie(_df["id"], labels=_df["group_name"], autopct='%1.2f%%', startangle=160, explode=explode)
plt.tight_layout()
plt.show()
仅保留计算机科学类论文,并统计该大类下,细分类别论文数随时间的变化
group_name="Computer Science"
cats = data.merge(df_taxonomy, on="categories").query("group_name == @group_name")
cats.groupby(["year","category_name"]).count().reset_index().pivot(index="category_name", columns="year",values="id")
知识点总结:
- split+for循环,用于拆分同一字段内多值的情况;
- len(),配合上一步,获得所有枚举值
- 时间类型数据格式转换+获取年份数据:pd.to_datetime(被转换字段).dt.year
- groupby
- reset_index 重置索引
- 爬虫
- 正则
- merge
正则举例
# 插播 正则举例
import re
phone="2004-959-559 # 这是一个电话号码"
#删除注释
num=re.sub(r'#.*$','',phone) #匹配从#开始,$-匹配到末尾/匹配行尾;替换为空值;.*贪婪匹配
print("电话号码:",num)
#移除非数字内容
num=re.sub(r'\D',"",phone) # \D匹配所有数字内容
#指定保留哪一部分
#就我们的代码来说
raw='Astrophysics(astro-ph)'
raw1=re.sub(r"(.*)\((.*)\)",r"\1",raw) # \1或\2是啥?- 要第几位的
raw1
raw2=re.sub(r"(.*)\((.*)\)",r"\2",raw) # \1或\2是啥?- 要第几位的
raw2