培训OpenNLP文档分类

时间:2017-06-14 16:28:38

标签: java opennlp

我试图使用OpenNLP对发票进行分类。根据它的描述,我将它分为两​​类。我已经构建了一个包含20K描述的培训文件,并将每个文档标记为正确的类。

训练数据看起来像(第一列是代码,我用作类,第二列是发票说明):

85171231 IPHONE 5S CINZA ESPACIAL 16GB (ME432BZA)
85171231 Galaxy S6 SM-G920I
85171231 motorola - MOTO G5 XT1672
00000000 MOTONETA ITALIKA AT110
00000000 CJ BOX UNIBOX MOLA 138X57X188 VINHO

使用OpenNLP中的DocumentCategorizer,我达到了98.5%的正确率。但是,为了提高效率,我采用了错误的分类文档并用它来扩展训练数据。

例如,当我第一次运行时," MOTONETA ITALIKA AT110"被归类为" 85171231"。没关系,因为第一次运行" MOTONETA ITALIKA AT110"没有被分类。所以,我教了分类器明确地提出了" MOTONETA ITALIKA AT110"标记为" 00000000"。

但是,再次运行它,OpenNLP坚持将其归类为" 85171231"即使训练数据包含对" 000000"。

的明确地图

所以我的问题是:我是在教OpenNLP吗?如何提高效率?

我使用的代码是:

MarkableFileInputStreamFactory dataIn = new MarkableFileInputStreamFactory("data.train");

ObjectStream<String> lineStream = new PlainTextByLineStream(dataIn, StandardCharsets.UTF_8);
ObjectStream<DocumentSample> sampleStream = new DocumentSampleStream(lineStream);

TrainingParameters params = new TrainingParameters();
params.put(TrainingParameters.ITERATIONS_PARAM, "100");
params.put(TrainingParameters.CUTOFF_PARAM, "0");

DoccatModel model = DocumentCategorizerME.train("pt", sampleStream, params, new DoccatFactory());

DocumentCategorizer doccat = new DocumentCategorizerME(model);
double[] aProbs = doccat.categorize("MOTONETA ITALIKA AT110".replaceAll("[^A-Za-z0-9 ]", " ").split(" "));
doccat.getBestCategory(aProbs);

1 个答案:

答案 0 :(得分:3)

默认情况下,DocumentCategorizer会使用词袋。这意味着不考虑术语序列。 如果MOTONETA ITALIKA AT110组中85171231的任何术语出现频率较高,则分类器将倾向于使用该组。

你有几个选择:

  • 您可以向群组MOTONETA ITALIKA AT110添加000000的更多变体;
  • 尝试更改要素生成器。

第二个选项是更改模型的创建,如下所示:

int minNgramSize = 2;
int maxNgramSize = 3;
DoccatFactory customFactory = new DoccatFactory(
    new FeatureGenerator[]{
        new BagOfWordsFeatureGenerator(),
        new NGramFeatureGenerator(minNgramSize, maxNgramSize)
    }
);
DoccatModel model = DocumentCategorizerME.train("pt", sampleStream, params, customFactory);

您可以通过删除BagOfWordsFeatureGenerator并更改最小和最大ngram大小来使用要素生成器。