Análise preguiçosa com Stanford CoreNLP para obter sentimentos apenas de frases específicas
Estou procurando maneiras de otimizar o desempenho do meu pipeline de sentimentos Stanford CoreNLP. Como resultado, você deseja obter sentimentos de sentenças, mas apenas aquelas que contêm palavras-chave específicas fornecidas como entrada.
Eu tentei duas abordagens:
Abordagem 1: pipeline StanfordCoreNLP anotando texto inteiro com sentimento
Eu defini um pipeline de anotadores: tokenize, ssplit, analise, sentiment. Eu o executei no artigo inteiro, procurei palavras-chave em cada frase e, se elas estivessem presentes, execute um método que retorne o valor da palavra-chave. Não fiquei satisfeito com o fato de o processamento demorar alguns segundos.
Este é o código:
List<String> keywords = ...;
String text = ...;
Map<Integer,Integer> sentenceSentiment = new HashMap<>();
Properties props = new Properties();
props.setProperty("annotators", "tokenize, ssplit, parse, sentiment");
props.setProperty("parse.maxlen", "20");
props.setProperty("tokenize.options", "untokenizable=noneDelete");
StanfordCoreNLP pipeline = new StanfordCoreNLP(props);
Annotation annotation = pipeline.process(text); // takes 2 seconds!!!!
List<CoreMap> sentences = annotation.get(CoreAnnotations.SentencesAnnotation.class);
for (int i=0; i<sentences.size(); i++) {
CoreMap sentence = sentences.get(i);
if(sentenceContainsKeywords(sentence,keywords) {
int sentiment = RNNCoreAnnotations.getPredictedClass(sentence.get(SentimentCoreAnnotations.SentimentAnnotatedTree.class));
sentenceSentiment.put(sentence,sentiment);
}
}
Abordagem 2: pipeline StanfordCoreNLP anotando texto inteiro com frases, anotadores separados sendo executados em frases de interesse
Devido ao fraco desempenho da primeira solução, eu defini a segunda solução. Eu defini um pipeline com anotadores: tokenize, ssplit. Procurei palavras-chave em cada frase e, se elas estivessem presentes, criei uma anotação apenas para essa frase e executei os próximos anotadores: ParserAnnotator, BinarizerAnnotator e SentimentAnnotator.
Os resultados foram realmente insatisfatórios por causa do ParserAnnotator. Mesmo se eu o inicializei com as mesmas propriedades. Às vezes, demorava ainda mais tempo do que todo o pipeline executado em um documento na Abordagem 1.
List<String> keywords = ...;
String text = ...;
Map<Integer,Integer> sentenceSentiment = new HashMap<>();
Properties props = new Properties();
props.setProperty("annotators", "tokenize, ssplit"); // parsing, sentiment removed
props.setProperty("parse.maxlen", "20");
props.setProperty("tokenize.options", "untokenizable=noneDelete");
StanfordCoreNLP pipeline = new StanfordCoreNLP(props);
// initiation of annotators to be run on sentences
ParserAnnotator parserAnnotator = new ParserAnnotator("pa", props);
BinarizerAnnotator binarizerAnnotator = new BinarizerAnnotator("ba", props);
SentimentAnnotator sentimentAnnotator = new SentimentAnnotator("sa", props);
Annotation annotation = pipeline.process(text); // takes <100 ms
List<CoreMap> sentences = annotation.get(CoreAnnotations.SentencesAnnotation.class);
for (int i=0; i<sentences.size(); i++) {
CoreMap sentence = sentences.get(i);
if(sentenceContainsKeywords(sentence,keywords) {
// code required to perform annotation on one sentence
List<CoreMap> listWithSentence = new ArrayList<CoreMap>();
listWithSentence.add(sentence);
Annotation sentenceAnnotation = new Annotation(listWithSentence);
parserAnnotator.annotate(sentenceAnnotation); // takes 50 ms up to 2 seconds!!!!
binarizerAnnotator.annotate(sentenceAnnotation);
sentimentAnnotator.annotate(sentenceAnnotation);
sentence = sentenceAnnotation.get(CoreAnnotations.SentencesAnnotation.class).get(0);
int sentiment = RNNCoreAnnotations.getPredictedClass(sentence.get(SentimentCoreAnnotations.SentimentAnnotatedTree.class));
sentenceSentiment.put(sentence,sentiment);
}
}
Questões
Gostaria de saber por que analisar no CoreNLP não é "preguiçoso"? (No meu exemplo, isso significaria: realizado apenas quando o sentimento de uma frase é chamado). É por razões de desempenho?
Como um analisador de uma frase pode funcionar quase tanto quanto um analisador de um artigo inteiro (meu artigo tinha 7 frases)? É possível configurá-lo de uma maneira que funcione mais rápido?