使用Thuctc进行中文文本分类应用

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sinat_29673403/article/details/79526143

这几个月一直在做跟机器学习相关的东西用来减轻运营在文章方面的工作量:文章自动审核及分类(单分类与多分类并存情况,及对文章进行标签化)
这里介绍的是使用Thuctc对文章进行分类,根据条件来判断多分类情况的取舍(ps:为什么不使用thuctc对文章进行审核,是因为用来训练审核的样本并不好,可能存在脏数据,而且对于关键词的标识度有所偏差,导致结果不太理想,便改用了其他方法)

首先介绍一下:THUCTC(THU Chinese Text Classification),是由清华大学自然语言处理实验室推出的中文文本分类工具包,能够自动实现用户自定义的文本分类语料的训练、评测、分类功能。在这里我并没有使用额外的中文分词工具(例如jieba),而是用的工具包本身自带的分词,就这样就已经满足需求了。
在这里面使用的权重计算方法是tf-idf(逆文档频率)用以评估一字词对于一个文件集或一个语料库中的其中一份文件的重要程度。字词的重要性随着它在文件中出现的次数成正比增加,但同时会随着它在语料库中出现的频率成反比下降。这样我们就能获得一些频率较高的关键词,而忽略那些干扰项。
在使用样本进行训练的时候一定要非常注意不要出现过拟合现象,通俗来说就是在训练模型中使用过多参数,以致太适应训练数据而非一般情况,导致实际应用的时候,模型预测结果反而更差。当然过拟合的可能性不只取决于参数个数和数据,也跟模型架构与数据的一致性有关。此外对比于数据中预期的噪声或错误数量,跟模型错误的数量也有关。通常我们最容易注意的就是不要使正负训练样本集的大小相差过大,应该使用规模相当的正负训练样本进行训练,不至于使得训练后的模型所作出的预判更偏向于样本规模更大的样本分类,导致预测结果的偏差(原因在于对于样本规模更大的样本分类模型收集的信息更多,往往将一些可能是属于其他样本分类的数据信息也一并收入,导致结果的偏差)
好了,话不多说,让我们用用看吧,样本数据的获取就要看你自己的样本数据是怎么存放和调取的了,这个官方网站上也有对样本数据的存放的要求,在这里就不多赘述。主要是如何训练模型和预测模型的。(官方有给demo,直接拿过来学习就很够了)
首先是,训练模型:

public static void createModel(int kind, String bootPath){
        Demo d = new Demo();
        d.setBootPath(bootPath);
        d.runClassTrainAndTest(kind, 1.0,1.0, 5000);//生成分类训练模型
}
public void runClassTrainAndTest(int kind, double train_per, double test_per, int symbol) {

    // 新建分类器对象
    BasicTextClassifier classifier = new BasicTextClassifier();

    // 设置参数
    String defaultArguments = ""
         + "-train " + bootPath + trainClassName[kind]  // 设置您的训练路径,这里的路径只是给出样例
         + " -test " + bootPath + testClassName[kind]
         + " -n 1 "
         + "-svm libsvm "
         + "-d1 "+train_per  // 前70%用于训练
         + " -d2 "+test_per  // 后30%用于测试
         + " -f " + symbol // 设置保留特征数,可以自行调节以优化性能35000
         +  " -s "+ bootPath + trainClassModel[kind]  // 将训练好的模型保存在硬盘上,便于以后测试或部署时直接读取模型,无需训练
         ;

    // 初始化
    classifier.Init(defaultArguments.split(" "));

    // 运行
    classifier.runAsBigramChineseTextClassifier();

}

将保存好的模型拿出来进行预测,看看结果如何:

public static void onlyClass(int kind, int date, String bootPath){
        Demo d = new Demo();
        d.setBootPath(bootPath);
        d.runLoadClassModelAndUse(kind, date,4);
    }
public void runLoadClassModelAndUse(int kind, int date, int resultNum) {
        // 新建分类器对象
        BasicTextClassifier classifier = new BasicTextClassifier();

        // 设置分类种类,并读取模型
        classifier.loadCategoryListFromFile(this.bootPath+trainClassModel[kind]+"/category");
        classifier.setTextClassifier(new BigramChineseTextClassifier(classifier.getCategorySize()));
        classifier.getTextClassifier().loadModel(this.bootPath+trainClassModel[kind]);
        // 之后就可以使用分类器进行分类
        CreateTrainData c = new CreateTrainData();//数据库操作类
        ResultSet rs = c.getClassArticleInfos(kind, date);
        try {
            if(rs.next()){
                do{
                    String text = rs.getString("title")+ " " + rs.getString(description[kind]);
                    int topN = resultNum; // 保留最有可能的N个结果
                    rs.getString("title");
                    ClassifyResult[] result = classifier.classifyText(text, topN); 
                    rs.getString("title");
                    for(int k=0; k < result.length; k++){
                        if(k != 0){
                            double distance = result[k].prob/result[k-1].prob;//判断该预测结果是否符合要求,如果下一个预测结果的概率与上一个预测结果的概率相差太大,则代表不是该文档的分类,将后面的预测结果都舍去
                            if(distance < 0.75){
                                break;
                            }
                        }
                        String sql = " INSERT INTO btb_map (id, article_class_id, article_id, type, class_sort) values (0,"+classifier.getCategoryName(result[k].label)+","+rs.getString("id")+", 2, 0)";
                        c.getResult(sql);
                    }
                }while(rs.next());

            }
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }



        System.out.println("模型预测完成!");
    }

看起来是不是很简单,比较大的改动就是对于结果的取舍,因为涉及到一个文档是否为多分类,所以进行了一个小小的判断。在应用过程中发现thuctc对于分类的问题效果比较好,误差在能够接受的范围内,准确度能达到百分之八十多。对于存在多分类的文档的预判效果也很好,算是一个惊喜吧。
在此,我并没有对源码进行过多的剖析,是因为我觉得其他大大们的文章已经很好的解释了这些。如果有需要,小伙伴们也可以去看看。地址为:http://blog.csdn.net/u014595019/article/details/51474408,鼓掌撒花~
如果有什么不明白的地方或者有什么需要讨论的,欢迎来找我交流,共勉哦~

猜你喜欢

转载自blog.csdn.net/sinat_29673403/article/details/79526143