问答机器人的Python分类器

作者: 一个不知死活的胖子 | 来源:发表于2016-07-28 14:22 被阅读4951次

    导语

    现在问答机器人真是火的不要不要的,大致分为两类:普适多场景的和单一专业场景的问答机器人。由于资源有限,不知死活的笔者只做了单一场景的分类器,如对海量数据、多场景的问答机器人感兴趣的话可以参考QA问答系统中的深度学习技术实现,对于该网站在NLP方面的贡献简直不能更感激(请允许献上我的膝盖)!

    1. 问答语料库

    由于仅面向业务,场景单一,所以训练集语料库只包含20类,共400多条问题,每类问题对应一个回答。

    2. 训练词向量

    不知死活的笔者决定兴师动众的选择word2vec将训练集语料转化为词向量作为模型的输入。关于word2vec的原理及其C语言的词向量训练方法,请参考word2vec词向量训练及中文文本相似度计算以及该博文内的链接。笔者根据【python gensim使用】word2vec词向量处理中文语料用Python训练的中文词向量模型。(英文的词向量训练可以参考
    利用Gensim训练关于英文维基百科的Word2Vec模型(Training Word2Vec Model on English Wikipedia by Gensim)

    2.1 中文语料库

    可以参考Windows下使用Word2vec继续词向量训练中提到的语料库,不知死活的笔者选择从搜狗实验室下载了全网新闻语料,不得不说,搜狗实验室是非常具有贡献力的!完整版1.02G,解压后2.22G,共378个文件,HTML格式,你值得拥有!

    News List.png

    2.2 分词合并

    首先是分词,可供选择的工具有很多:Jieba、ANSJ、NLPIR、LTP等等,在此笔者选择Jieba进行分词:

    import jieba  
    
    def readLines(filename):
        # read txt or csv file
        fp = open(filename, 'r')
        lines = []
        for line in fp.readlines():
            line = line.strip()
            line = line.decode("utf-8")
            lines.append(line)
        fp.close()
        return lines
    
    def parseSent(sentence):
        # use Jieba to parse sentences
        seg_list = jieba.cut(sentence)
        output = ' '.join(list(seg_list)) # use space to join them
        return output
    

    然后将所有文档合并,并写入corpus.csv中:

    import re  
    import codecs  
    import os 
    
    # only content is valid
    pattern = "<content>(.*?)</content>"
    csvfile = codecs.open("corpus.csv", 'w', 'utf-8')
    fileDir = os.listdir("./corpus/")
    for file in fileDir:
        with open("./corpus/%s" % file, "r") as txtfile:
            for line in txtfile:
                m = re.match(pattern, line)
                if m:
                    segSent = parseSent(m.group(1))
                    csvfile.write("%s" % segSent)
    

    特别mark以下,codecs这个包在调整编码方面的贡献真的不要太大,尤其是常常对于中文编码无力的不知死活的笔者来说,简直是神器!
    对于中文的编码处理:utf-8 --> unicode --> utf-8

    2.3 训练word2vec模型

    在此,笔者使用gensim的word2vec进行词向量的训练:

    from gensim.models import word2vec
    import logging
    
    logging.basicConfig(format = '%(asctime)s : %(levelname)s : %(message)s', level = logging.INFO)
    sentences = word2vec.Text8Corpus("corpus.csv")  # 加载语料
    model = word2vec.Word2Vec(sentences, size = 400)  # 训练skip-gram模型
    
    # 保存模型,以便重用
    model.save("corpus.model")
    # 对应的加载方式
    # model = word2vec.Word2Vec.load("corpus.model")
    
    # 以一种C语言可以解析的形式存储词向量
    model.save_word2vec_format("corpus.model.bin", binary = True)
    # 对应的加载方式
    # model = word2vec.Word2Vec.load_word2vec_format("corpus.model.bin", binary=True)
    

    关于调参,可自行参考gensim文档。

    2.4 获得词向量

    接下来就是使用上述获得的model将训练集的中文语料转化为词向量:

    def getWordVecs(wordList):
        vecs = []
        for word in wordList:
            word = word.replace('\n', '')
            try:
                # only use the first 500 dimensions as input dimension
                vecs.append(model[word])
            except KeyError:
                continue
        # vecs = np.concatenate(vecs)
        return np.array(vecs, dtype = 'float')
    

    3. 构建模型

    3.1 Naive Bayes

    效果良好,效率高!

    from sklearn.naive_bayes import MultinominalNB
    
    MNB = MultinominalNB(alpha = 0.000607)
    

    3.2 Random Forest

    效果良好,效率一般。

    from sklearn.ensemble import RandomForestClassifier
    
    RFC = RandomForestClassifier(min_samples_leaf = 3, n_estimators = 100)
    

    3.3 RBM + Logistic Regression

    效果很好,效率很低……由于这个模型只需要训练一次,所以效率关系不大(抱歉我随便乱用模型,实际上这模型本身来源于sklearn上的实例……原本着使用效果至上的原则,然而至于为何这样搭配……)

    from sklearn.pipeline import Pipeline
    from sklearn.linear_model import LogisticRegression
    from sklearn.neural_network import BernoulliRBM
    
    rbm.learning_rate = 0.07
    rbm.n_iter = 50
    # more components tend to give better prediction performance, but larger fitting time
    rbm.n_components = 800
    rbm.batch_size = 10
    logistic.C = 10000.0
    rbm = BernoulliRBM(random_state = 0, verbose = True)
    logistic = LogisticRegression()
    clf = Pipeline(steps = [('rbm', rbm), ('logistic', logistic)])
    

    总的来说,神经网络(例如MLP)对这类文本分类问题效果普遍不错,至于传统机器学习算法,朴素贝叶斯也有不俗的表现。

    4. 其他

    这次学习到sklearn中一个非常有用的功能sklearn.externals.joblib,可用于导出训练好的模型,这对于training cost非常高的模型来说实在是非常好用啊!

    from sklearn.externals import joblib
    
    # save classifier
    joblib.dump(clf, "Classifier.pkl")
    # load classifier
    clf = joblib.load("Classifier.pkl")
    

    其次就是sklearn中的sklearn.pipeline.Pipeline,将多个模型结合在一起,通过Pipeline的方式进行训练,真的是非常方便啊!

    from sklearn.pipeline import Pipeline
    
    clf = Pipeline(steps = [clf1, clf2])

    相关文章

      网友评论

      • 东北菇凉在江南:请问下Corpus.csv是所有评论放在一起的合集分词后的单词集吗?
      • LucasJin:胖子,你这个任务是干啥?对句子进行分类吗?你训练的都是新闻数据,是要完成什么神奇的任务啊
      • 8776bc99ada8:博主,multinomial naive bayes 的输入矩阵应该不包含负值,直接用词向量组成的句子向量会报错,博主有做什么处理嘛? thx~

      本文标题:问答机器人的Python分类器

      本文链接:https://www.haomeiwen.com/subject/byivjttx.html