DBLP数据集用weka数据挖掘 xml转csv格式文件
写在前面
之前做了中国科学院大学的一门研讨课《数据挖掘技术与应用》,老师讲的非常好,这门课的几个大项目真的让我学到了许多知识,我受益匪浅,不过其中的DBLP数据集数据挖掘这个项目着实给我带来了不小的麻烦,老师要求使用weka,我们一个小组弄了好几个整天才弄出来,中间遇到了无数的坑,也经历了无数的绝望,最重要的是网上这方面的资料甚少,好在最后总算做出来了。所以我准备写一篇博客,既方便我自己后面查阅,更能造福后人。
这篇博客用到的所有文件和代码以及最后生成的文件我都放到百度云里面了,代码我也会贴到CSDN博客上。(百度云链接:https://pan.baidu.com/s/1KkDvTRLr5FXGgDYRelIGag 提取码:xscf)
好了,闲话不多说了,我也不准备介绍什么是DBLP之类的,直接上操作过程。
DBLP数据集挖掘分为三个步骤,可能有更好的步骤,但是我们是这样处理的:一、文件格式转换,xml转csv;二、csv格式文件数据数据预处理(主要在excel下操作);三、weka进行数据挖掘。
xml转csv格式文件
第一步xml文件转换,首先在网上下载DBLP的数据集,xml格式。如果你也是上的这门课并且和我用的是同一个数据挖掘的课本,那么你会发现课本上提供的下载链接已经失效了。我用的这个链接,到我发帖的时候依然有效,地址为https://dblp.uni-trier.de/xml/下载其中的dblp.dtd和dblp.xml.gz。解压dblp.xml.gz,可以得到相应的xml文件。我的百度云盘里也分享了相关文件。dblp.dtd的作用我有点忘记了,总之把它和dblp.xml文件放在同一个目录下就好。
第一步继续,我们搭建python运行环境,笔者提供的程序是使用的VS2017的python环境运行的程序,当然也可以使用其它环境。程序稍微改一改直接就可以用。导入程序后,首先更改程序第13行的DBLP_XML_PATH参数,修改为相应的xml文件路径,注意路径如果要用反斜杠\隔开的话前面要加r,否则要拿正斜杠/隔开。之后修改程序第101行的saveToCsv(self.storage,“F:\dblp1.csv”)中的路径为要保存的csv文件的路径。
程序中第73行的if self.count % 1000 == 0:表示每处理1000条信息输出一次提示信息,第98行的if self.count % 1000000 == 0:表示每处理1000000条信息保存一次,后面接了一句exit(0),表示处理完1000000条信息后就不处理了,强制退出程序,这里会触发一个异常中断,请不用担心,正常关闭程序就可以,你会发现处理后的.csv文件已经生成。如果你想要把xml文件里面的所有信息都提取出来,请注释exit(0),并且解注释return,同时把1000000改为一个较小的数字,比如10000。
如果你上述过程遇到了一点问题,并且如此大的dblp文件让你难以去调试究竟哪出了问题,那么你可以使用我提供的dblp1.xml文件进行测试,这个文件很小,只有20多条信息,所以请注意在使用前把上一段代码中的1000000和1000都改为1,祝你好运~
xml转csv格式文件程序如下:
# -*- coding:utf-8 -*-
'''
@author:shinefriend
@createDate:2019.07.16
@version:2.0.0
'''
import sys
from xml.sax import handler, make_parser
import pickle
import os
import csv
DBLP_XML_PATH = r'F:\dblp2\dblp.xml'
#此处需要完整添加所有“块”结构的标签,或者需要处理的类型的标签
paperTag = ('article','inproceedings','proceedings','book',
'incollection','phdthesis','mastersthesis','www')
class CoauthorHandler(handler.ContentHandler):
def __init__(self):
self.title = ''
self.year = ''
self.author = ''
self.count = 0
self.count2 = 0
self.isPaperTag = 0
self.isTitleTag = 0
self.isYearTag = 0
self.isAuthorTag = 0
#self.authors = ''
self.authors = []#存储每个“块”中的所有author
self.storage = {}#用来存储生成的数据,结构为{'title':[year, [author1, author2, ...]]}
#with open(file_path, "wb") as csvfile:
def startDocument(self):
print('Document Start')
def endDocument(self):
print('Document End')
def startElement(self, name, attrs):
if name in paperTag:
self.isPaperTag = 1
if name == 'title':
self.isTitleTag = 1
if name == 'author':
self.isAuthorTag = 1
if name == 'year':
self.isYearTag = 1
def endElement(self, name):
if name == 'author':
self.authors.append(self.author)
#self.authors=self.authors+self.author
#print(self.author)
#print(self.authors)
self.author = ''
self.count2 += 1
#del self.authors
#self.authors = []
if name == 'year' or name == 'title':
pass
if name in paperTag:
if self.count2>1:#删除单个作者的文献
self.count += 1
self.storage[self.title] = []
self.storage[self.title].append(self.year)
self.storage[self.title].append(self.authors)
self.year = ''
self.authors = []
self.count2 = 0
#if self.count % 1 == 0:
if self.count % 1000 == 0: #每1000轮输出一次提示信息
print(self.count)
#print(self.author)
#print('\n')
#exit(0)
#if count == 468:
#str=input('请输入零')
#items = self.storage.items()
#with open("D:\dblp.csv",'a',newline='',encoding='utf-8') as csvfile:#a
#writer = csv.writer(csvfile)#,dialect='excel'
#if count == 468:
#str=input('请输入一')
#for item in items:
#tmp_li = []
#tmp_li.append(item[0])
#tmp_li.append(item[1][0])
#tmp_li.append(item[1][1])
#writer.writerow(tmp_li)
#if count == 468:
#str=input('请输入六')
#saveToCsv(self.storage,"D:\\dblp.csv")
#print(self.storage)
#self.storage = {}
#self.storage = {}
if self.count % 1000000 == 0:
#if self.count % 10 == 0:
print('已保存')
saveToCsv(self.storage,"F:\\dblp1.csv")
exit(0)
#return
def characters(self, content):
if self.isTitleTag == 1:
self.isTitleTag = 0
self.title = content
if self.isAuthorTag == 1:
self.isAuthorTag = 0
self.author = content
if self.isYearTag == 1:
self.isYearTag = 0
self.year = content
def parserDblpXml():
handler = CoauthorHandler()
parser = make_parser()
parser.setContentHandler(handler)
f = open(DBLP_XML_PATH,'r')
#str=input('程序调试点2,输入任意内容继续:')
parser.parse(f)
f.close()
return handler.storage
def saveToCsv(storage, file_path):
items = storage.items()
#with open(file_path, "wb") as csvfile:
with open(file_path,'w',newline='',encoding='utf-8') as csvfile:#a
writer = csv.writer(csvfile)#,dialect='excel'
for item in items:
tmp_li = []
tmp_li.append(item[0])
tmp_li.append(item[1][0])
tmp_li.append(item[1][1])
writer.writerow(tmp_li)
csvfile.close()
if __name__ == '__main__':
str=input('程序即将运行,回车键继续:')
storage = parserDblpXml()
数据预处理
程序的第一步终于结束了,我们开始第二步,数据预处理。如果你只处理了1000000条数据的话,你会拿到一个140多MB的csv格式的文件,内容大致如下:
首先我们可以将题目和日期全部删除掉,这两项对我们挖掘作者间的合作关系没有太大的意义。之后我们通过excel表格全选替换的方法(快捷键ctrl+F),将作者栏中的[]和单引号全部删除掉,只需要让替换为的内容为空就可以做到。
第二步第二阶段:之后我们需要把作者分栏,我们要把每个作者分到单独的一列,选中要分栏的列(当然我们目前只有第一列有数据了),选择菜单栏中的数据->分列,弹出的窗口第一步勾选分隔符号,第二步勾选逗号,勾去其它选项,直接点击完成即可。注意由于1000000条数据数据量太大,因此excel(准确的说是csv格式文件)很有可能卡死,遇到这种情况可以每100000条数据分到一个文件中,分栏10次,再汇总。笔者的电脑性能不是特别高,由于笔者是后面又把项目做了一遍,这里笔者小小的偷个懒,只选取前10000条数据进行后续的实验,电脑性能好的大佬们可以按照我接下来的说明把1000000条数据都处理了。分栏完成后,再在文件的第一行依次加入标题,为author1, author2, author3, author4, author5。只保留前5个作者,其它作者都删掉,缺省的作者都用问号?来填充。
但是,到此,第二步就结束了吗?没那么简单,你把这个文件导入weka,会发现第二行就有问题,咋回事?用txt或者notepad++打开这个文件你会发现多出了一堆逗号,所以说我们需要把这些多出的逗号都删掉。方法就是在csv文件中,把前5列后面尽可能多的列选中,然后把这些看似没有内容的列删除掉,这些逗号就也会跟着删除掉。
第二步第三阶段:没那么容易,导入weka后,第240行竟然有问题,检查后,发现这个作者竟然有双引号,无奈,用查找替换的方法把所有的双引号都删掉,这次好像就能成功导入weka了,如果还有其它问题,按照问题所在的行数,做相应的修改即可。(导入数据是点击Explorer,选择open file,选择.csv格式并选择相应的文件导入)
weka数据挖掘
接下来第三步,这一步相对容易(指的是对10000条数据),如果你选择处理1000000条数据,一定要有一台足够好的电脑,并且需要花费大量的时间去等待weka处理。笔者为了演示方便,只处理10000条数据。导入第二步处理完成的文件后,选择菜单栏中的Associate,修改相应的参数如下,下面的值为我设置的值,可以参考,但不一定是最好的。点击start,开始进行数据挖掘。右下角的小鸟只要一直在动就说明软件还在跑,等待测试结果。改变置信度C或者其它参数的值,进行调整,观察不同的实验结果。
那么至此,DBLP数据挖掘就结束了,祝大家实验顺利~