基于 ACE语料库的 信息抽取与文本分类

一、背景介绍

1.事件抽取:

根据ACE中的定义,事件由事件触发词(Trigger)和描述事件结构的元素(Argument)构成,元素和事件之间的关系定义为角色(Argument role)。

在后面的任务中,我们首先需要提取出语料库中的每句话,以及它所对应的类别,作为分类任务的训练数据。(暂时没有考虑触发词了)

2.ACE语料(Automatic Content Extraction?)

(1)对事件类型的定义:8个类别,33个子类别

(2)ACE中文语料的来源与层次架构

(3)apf.xml文件(标注结果)的内容:

 其中框起来的“镇压”就是一个触发词,体现了该段的“感情色彩”,也就是该段所对应的“类别”----在第一行的“TYPE”里可以看到是conflict,这也是我们后面做文本分类的label来源。

(4) smg文件(原文)内容:

3.文本分类

(1)传统方法:

(2) 深度学习方法

4.其他tips:

代码规范问题:python代码规范 

面向过程-->面向对象编程

 

二、实战(1.0版 第一次动手实践)

(有小学生的感觉,有些乖蠢笨)

1.构造样本集

这是个繁琐个过程,需要足够的耐心与细心。

首先观察xml文件内容,要看这颗树是如何伸展,在哪里获取我们需要的内容或属性(类似爬虫)

需要的包

  • import re 正则表达式,用来匹配需要解析的文件名
  • from lxml import etree 用来解析xml文件

新学了OOP思想,原本我程序写的是完全基于过程(读文件-->由root解析-->提取信息-->转换为想要的格式-->写文件)去思考的,那么现在我可以把提取信息这件事当成一个class,传入的可以是不同的数据(这里也就是语料库不同来源的文件),那么可以为每种(这里是三种bn/nw/wl)定义各自的方法,在main函数调用的时候,分别创建三个instance,去按照各自的方法去提取信息,那么在这当中,读写文件、转换格式的操作都是一样,可以只写一个函数在class里,这样整个class结构就出来啦!所以这样的思想可以帮助我们更宏观地把握程序设计,而不是完全由过程为导向(一环扣一环)虽然执行起来必须是一个接一个,但是思想上可以理解为一种“并行”(我现在是这个感觉,以后可能有更深的体会)。

2.数据预处理(分词、去停用词)

利用哈工大pyltp分词工具,并用停用词表(可自己编辑)

from pyltp import Segmentor  

def cut_sentence(file_in):
    cutwords_list = [] #清零
    file_original_txt = open(file_in,'r',encoding='utf-8')
    stopwords = [ line.rstrip() for line in open('stopwords',encoding='utf-8') ] #rstrip() 删除 str末尾的指定字符(默认为空格)
    
    segmentor = Segmentor() 
    segmentor.load('./project/cws.model')  #加载模型
    sentences = file_original_txt.readlines()
    
    for sente in sentences:
        temp='' #用来存放被切分后的“句子”
        sente = str(sente).encode('utf-8').decode('utf-8-sig') #编码、解码。否则label会认为是 '\ufeff' 非法字符
        label = str(sente[0:1]) #去label
        temp += label+'\t'
        sente = sente[2:] #去label
        words = segmentor.segment(sente)  #分词,类型为 pyltp.VectorOfString
        word_list = list(words) #收纳在list中
        for word in word_list[1:]:
            if word not in stopwords:
                temp += word+' '
        cutwords_list.append(temp)
        
    segmentor.release()  #释放模型
    file_original_txt.close()
    
#     with open('f_out.txt','w',encoding='utf-8') as f_out:
#         for i in cutwords_list:
#             f_out.write(i+'\n')
    return cutwords_list

cut_sentence('project/dataset/train_set1.txt')

结果: 

 

3.特征工程(TFIDF)

一步到位的方法:

from sklearn.feature_extraction.text import TfidfVectorizer
vect = TfidfVectorizer(ngram_range=(1,3), min_df=3, max_df=0.9, use_idf=1, smooth_idf=1, sublinear_tf=1)
vect.fit(X_train) # 或者直接X_train = vect.fit_transform(X_train)

X_train = vect.transform(X_train)
X_test = vect.transform(X_test)

我当时的操作:

from sklearn.feature_extraction.text import TfidfTransformer #计算tfidf
from sklearn.feature_extraction.text import CountVectorizer  #计算df
vectorizer=CountVectorizer()#该类会将文本中的词语转换为词频矩阵,矩阵元素a[i][j] 表示j词在i类文本下的词频  
transformer=TfidfTransformer()#该类会统计每个词语的tf-idf权值     

def get_tfidf(file_in):
    corpus = []
    for sente in cut_sentence(file_in):
        corpus.append(sente[2:])        #去label
#     print(corpus)
    tf=vectorizer.fit_transform(corpus) #第一个fit_transform是将文本转为词频矩阵                    
    tfidf=transformer.fit_transform(tf) #第二个fit_transform是计算tf-idf
    print(type(tfidf),'\t',tfidf.shape)
    return tfidf
get_tfidf('./project/dataset/train_set0.txt')

 结果:

4.分类模型

from sklearn import svm
from sklearn.linear_model.logistic import LogisticRegression
from sklearn.ensemble import RandomForestClassifier  
from sklearn.neighbors import KNeighborsClassifier  
from sklearn.linear_model import SGDClassifier
from sklearn import tree
from sklearn.externals import joblib
from sklearn import metrics

def training(train_set_in):
    X = get_tfidf(train_set_in)
    Y = []
    for sente in cut_sentence(train_set_in):
        Y.append(sente[0:1])
    svc=svm.SVC(C=1,kernel='poly',degree=3,gamma=10,coef0=0) #选择模型 & 参数
    lr = LogisticRegression()   
    knn = KNeighborsClassifier()  
    dt = tree.DecisionTreeClassifier()
    
    rf = RandomForestClassifier()
#     multi_target_forest = MultiOutputClassifier(rf)  # 构建多输出多分类器
#     clf = multi_target_forest.fit(X, Y)
    sgdc = SGDClassifier(loss="modified_huber", penalty="l2", alpha=0.00002, n_jobs=-1)# modified_huber; penalty="elasticnet"
#     pre = clf.predict(X)
#     print('多输出多分类器预测输出分类:\n',y_pred)
    
    clf = sgdc.fit(X,Y) #训练模型
    joblib.dump(clf,'train_model.m') #保存模型
    
def testing(test_set_in):
    file_original_txt = open(test_set_in,'r',encoding='utf-8')
    original_txt = file_original_txt.readlines() #原始文本
    i,j = 0,0
    clf = joblib.load('train_model.m') #加载模型   
    for sente in cut_sentence(test_set_in):
        label = int(sente[0:1])
        T = [] 
        T.append(str(sente[2:]))      
        tf=vectorizer.transform(T) #将数据进行转换,比如数据的归一化和标准化,将测试数据按照训练数据同样的模型进行转换,得到特征向量。
        tfidf=transformer.transform(tf)
        print(label,'\t',int(clf.predict(tfidf)),'\t',str(original_txt[j][2:])) 
        if label == int(clf.predict(tfidf)):
            i += 1 
        j += 1  
    print('\nprecision :',i/j)
    
training('./project/dataset/train_set0.txt')
testing('./project/dataset/test_set0.txt')

 结果:

5.模型评估与改进

 

三、pipeline

  • 3
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值