用Python实现科研自动化

这个学期如期开课了,虽然是在家里。这学期我导开了一门《高等教育管理专题研究》,一口气给了11个专题。为了对这11个专题的文献分布情况有一个粗略的印象,我觉得都得找相关的文献来看看,但是11个专题都要重新检索一遍,重复性工作让人头秃……于是,我写了个python脚本,自动生成各个主题的关键词和引文分布情况的报告,效果如下图。

看到点击“运行”不到3秒钟就自动生成了6000字左右“像模像样”的报告,不禁流下激动的泪水。

要是有一天能写个程序能将我的想法整理成论文就好了[狗头]。为了留存这个美好的幻想,我把报告生成的思路记录下来,权当为以后积累点技术基础。编程思路包括:提取PDF内容、CSSCI文献题录数据的格式处理、关键词词频计算、引文数据统计、关键词共被引网络生成、word的自动编写与插入(包括样式、表格等)

一、报告结构的拟定

写报告的思路比较固定,我个人的体会是:叙述要求、描述数据和展示结果。那么每个一级标题下,先附上老师的要求,然后描述数据在哪里下载的,最后将结果数据的图表展示出来。按照这个思路走下来了,将每个部分的模板编写为如下这样。

确定了报告框架之后,下面的事情便变得简单,把内容填上去,在写个循环语句,报告就完成了,下面说的都是如何填空的事情。

二、PDF内容提取

我导给了一个PDF,需要把PDF的一级标题和二级标题的内容提取出来,填充themeName和themeKeyword部分。

在python中,提取PDF内容的包有pdfminer、tabula、pdfplumber等(引自:Python:解析PDF文本及表格——pdfminer、tabula、pdfplumber 的用法及对比),都大同小异。经过对比选择了pdfplumber,没安装的话需要先安装一下。

pip install pdfplumber

主要代码如下。

pdfPath = 'Auto_data/course_text/2019-2020春季学期《高等教育管理专题研究》拟研究专题.pdf'
pdf = pdfplumber.open(pdfPath)
for p in pdf.pages:
    test = p.extract_text().split('\n')

通过上述代码就可以提取PDF的所有内容。但是想要正确提取内容还有其他的工作,使用正则表达式根据标题的特点提取一级和二级标题内容、编程将全角标点变成半角标点、去掉标题中的中文和英文标点等、将一级标题和二级标题内容建立对应关系等。非主干代码占了所有代码量的80%以上,真特么的符合“二八法则”。

三、文献题录数据下载与提取

在一个主题词下载之前,先确定该主题的文献检索方式。把下图的检索方式使用代码进行整理,便可以得到searchWord和searchWay。

themeKeyword = '、'.join(themes_keypoints[ii])
searchWord, searchWay = search_type(ii, searchWord_group)

def wordM(word):
    word = "“" + word + "”"
    return word

def search_type(i, searchWord_group):
    word_group = searchWord_group[i]
    slen = len(word_group)
    if (slen > 1):
        endLen = slen - 1
        searchWay = ',检索方式为:'+ word_group[endLen]
        searchWord = '、'.join(word_group[:endLen])
    else:
        searchWord = word_group[0]
        searchWay = ''
    return searchWord, searchWay

随后,在CSSCI官网,下载文献题录数据。

下载下来的数据是这样的。

对了,原来以为有数据规模会很大(并不大),所以使用如下代码生成了一个Windows批处理文件,可以达到一键生成文件夹目录的效果。

file_name = 'Auto_data/lite_data/themes_list.bat'
with open(file_name, "w") as f:
    index = 0
    for i in range(len(themes_group)):
        index = int(index) + 1
        if index < 10: # 记得加0,不然不按顺序
            index = '0' + str(index)
        else:
            index = str(index)
        contant = 'md '+ index + '_' + themes_group[i] + ' '
        f.writelines(contant)
        f.writelines('\n')

在下载得到数据后,需要对数据信息进行提取,提取的信息包括:标题、第一作者、关键词、发表时间、参考文献。标识符如下。

matching_columns = ['【来源篇名】','【第一作者】','【关 键 词】','【年代卷期】','【参考文献】']
separator = '-----------------------------------------------------------------------'

使用正则表达式匹配相关信息,使用.replace函数去掉标识符,再进行其他操作,将信息放入字典中,便完成了信息提取工作。核心代码如下:

for i in range(len(matching_columns)):
    m = matching_columns[i]
    isMatching = re.match(m, curData) #把标题、作者等信息放入字典中
    if isMatching:
        if (i == 0):
            data_dict['article'] = curData.replace(m,'')
        elif (i == 1):
            data_dict['author'] = curData.replace(m,'')
        elif (i == 2):
            data_dict['keyword'] = curData.replace(m,'')
        elif (i == 3):
            data_dict['year'] = curData.replace(m,'').split(',')[0]
        elif (i == 4):
            isReference = 1
isSeparator = re.match(separator, curData)

在完成信息提取之后,生成了这一个主题的题录信息字典data_dict,通过len(data_dict)可以知道这一个主题一共有多少条文献题录数据。

searchNum = len(data_dict)

四、关键词与引文数据统计

关键词的词频计算使用的是类似Excel的数据透视表的方法写成的,这一点在《如何用python表白》一文中已经讲到,计算函数如下。其中,words_count.head(10)是输出到word中的排名前10的关键词,len(set(all_words))是关键词的数量,对应word中的词频分布表和关键词个数keywordNum。

def all_words(df):
    all_words = []
    for w in df['keyword']:
        w_group = w.split('/')
        all_words.extend(w_group)
    print('关键词次数:',len(all_words))
    print('关键词个数:',len(set(all_words))) #使用set方法
    print('\n')
    
    df_word = pd.DataFrame({'word': all_words})
    words_count = df_word.groupby(by=['word'])['word'].count()
    words_count = words_count.to_frame()
    words_count.columns = ['count']
    words_count = words_count.sort_values(by='count', ascending=False)
    print(words_count.head(10))
    return all_words, words_count, len(set(all_words))

引文数据的提取编程思路类似, references_count.head(10)是输出到word中的被引量排名前10的参考文献。

def all_references(df):
    all_references = []
    for r in df['reference']:
        r_group = r.split('/')
        all_references.extend(r_group)
    print('\n')
    print('引用文献次数:',len(all_references))
    print('引用文献篇数:',len(set(all_references))) #使用set方法
    
    df_references = pd.DataFrame({'reference': all_references})
    references_count = df_references.groupby(by=['reference'])['reference'].count()
    references_count = references_count.to_frame()
    references_count.columns = ['count']
    references_count = references_count.sort_values(by='count', ascending=False)
    
    for index in list(references_count.index):
        if not isRef(index):
            references_count.drop(index)
    
    print(references_count.head(10))
    return references_count

五、关键词共现网络的生成

由于需要分析,关键词共现网络以截图的方式放入报告中,有一些结果还是很好的,可以说很好看了,比如下面这张,很容易给像我这样的博士研究生以思考的启发,比如可以这么说:“创新创业教育的生长,根基在于创新创业活动的开展,课程体系是连接两者的关键因素。此外,创新创业教育还涉及教学改革、教学组织模式、高校人才培养、教学策略的运用等多方面的内容……”

其他的也有好看的,比如“产教融合”的图,中心词、核心词和外围词都十分完整,十分便于分析。

六、word的自动编写

当我们所有的内容都准备好之后,就可以考虑word的自动生成了。我使用的模块是python-docx,没安装的话需要事先安装一下。

pip install python-docx

安装完成后,导入自己已经调好样式的空白word页面。

document = Document('Auto_data/result/input.docx')

先将我们的内容以字符串的形式存储在几个变量中。

first_para = '专题下的思考方向包括:'+ themeKeyword + '。'
second_para = '使用CSSCI进行检索,检索词为:'+ str(searchWord) + str(searchWay) + '。共下载文献题录数据' + str(searchNum) + '条,所有文献一共涉及关键词' + str(keywordNum) + '个,词频分布如下。'
third_para = '关键词共现网络如下。'
fourth_para = '被引用次数排名前10的文献如下。'

使用document.add_paragraph方法就可以将我们的内容以段落的形式插入word中,style可以选择样式,例如'Heading 2'是指二级标题样式,'Normal'是指正文样式。

t1 = document.add_paragraph(themeName, style = 'Heading 2')
p1 = document.add_paragraph(first_para, style = 'Normal')
p2 = document.add_paragraph(second_para, style = 'Normal')

表格的插入比较麻烦。先使用document.add_table生成题头。然后使用.add_row().cells方法增加行,使用for循环进行对表格单元格进行赋值,完成表格的生成。

table1 = document.add_table(rows=1, cols=4, style='网格型1')
hdr_cells = table1.rows[0].cells
hdr_cells[0].text = '关键词'
hdr_cells[1].text = '词频'
hdr_cells[2].text = '关键词'
hdr_cells[3].text = '词频'
table_size = int(maxKeyword/2)
for i in range(table_size):
    another_i = i + table_size
    row_cells = table1.add_row().cells
    row_cells[0].text = t1_data.index[i]
    row_cells[1].text = str(t1_data['count'][i])
    row_cells[2].text = t1_data.index[another_i]
    row_cells[3].text = str(t1_data['count'][another_i])

之后,使用for循环,将11个专题的内容都放入word中,使用document.save保存word,这样,我们6000字的报告就生成啦!

document.save('Auto_data/result/11个专题下的文献计量分析.docx')

写在后面

在思考编程过程的时候,决定这并不是什么难事,下载数据、提取信息、生成word就完事了。

但是……想法一时爽,编程编断手,虽然报告的生成仅仅需要不到3秒钟,但是累计编程时间超过9个小时,中间涉及正则表达式、字符的unicode编码等新知识点,以及许多大大小小的bug,太占用专业学习的时间。这种报告只是信息的简单叠加,并不具备自主分析的效果,论文还是得自己写[微笑]。能实现一个想法总还是一件开心的事情,程序最大的特点就是复用性,以后就当做写文献综述前的预处理流程吧。大家如果对报告或者源码感兴趣,欢迎在后台留言与我交流哇!

你可能感兴趣的:(用Python实现科研自动化)