Guia de aula laboratorial
O guia da 5º aula prática está disponível online. Os tópicos abordados incluem conceitos relacionados com a extracção de conhecimento através de técnicas de prospecção de texto.
O ficheiro extraccao-web.zip (
http://web.tagus.ist.utl.pt/~bruno.martins/materials/class-materials/labs-gti/extraccao-web/extraccao-web.zip ) inclui vários exemplos para os conceitos abordados nas aulas de laboratório referentes a extracção de informação.
Extracção de conhecimento
Uma componente importante de um processo de extracção de informação a partir de fontes não estruturadas relaciona-se com a análise computacional do texto. Entre as tarefas mais comuns encontram-se as seguintes:
- Classificar passagens de texto de acordo com a língua ou com o tema (e.g. detectar notícias sobre desporto, economia ou política).
- Encontrar menções a entidades no texto (e.g. nomes de pessoas, endereços de email, moradas) e relacionar estas entidades com entradas em bases de dados existentes.
A ferramenta LingPipe não possui um utilitário de linha de comandos. A sua utilização faz-se sempre no contexto de uma aplicação Java. O exemplo que se segue mostra como o LingPipe pode ser utilizado para classificar uma dada String de acordo com a sua língua. Esta é uma tarefa essencial para muitas aplicações de processamento de texto, estando na base de operações de processamento mais complexas (e.g. permite por exemplo efectuar a selecção de um conjunto de regras de extracção de acordo com a língua do documento).
import com.aliasi.classify.*;
public class ExampleLangClassification {
public static String classify ( String text ) throws Exception {
// Treinar um classificador baseado em tri-gramas usando duas frases de texto
String[] categories = { "pt", "en" };
String[] exampleText = { "Frase em Português", "Sentence in English" };
DynamicLMClassifier classifier = DynamicLMClassifier.createNGramProcess(categories,3);
classifier.train(categories[0],exampleText[0].toCharArray(),0,exampleText[0].length());
classifier.train(categories[1],exampleText[1].toCharArray(),0,exampleText[1].length());
JointClassification jc = classifier.classifyJoint(text.toCharArray(),0,text.length());
return
jc.bestCategory();
}
public static void main(String[] args) throws Exception {
for (int i = 0; i < args.length; ++i) {
System.out.println("input=" + args[i]);
String bestCategory = classify(args[i]);
System.out.println("output=" + bestCategory);
}
}
}
O algoritmo DynamicLMClassifier é na realidade uma generalização do popular algoritmo de classificação "Naive Bayes". Este último usa um processo estatístico com base no Teorema de Bayes, o qual diz que a probabilidade de um dado documento pertencer a uma classe, verificando-se a ocorrência de uma série de features (neste exemplo de classificação de acordo com a língua, trigramas de caracteres), é igual à probabilidade de encontrar aquela série de features num documento da mesma classe a multiplicar pela probabilidade de um dado documento ser da mesma classe e dividindo pela probabilidade de encontrar as mesmas feaures num documento de qualquer classe. No final do processo, escolhe-se a classe com maior probabilidade. O "naive" referece-se ao facto de ao calcular a probabilidade de ocorrência uma série de features, o algoritmo faz uma simplificação ao assumir a independência entre elas (i.e. o facto de uma palavra ocorrer no texto não depende em nada da ocorrência de outras palavras, o que na prática não se verifica).
Mais informações sobre os algoritmos de classificação poderão ser obtidas na documentação da ferramenta LingPipe ou nos slides das aulas teóricas de GTI.
No que diz respeito à tarefa de encontrar menções a entidades em texto, a ferramenta LingPipe permite a utilização de métodos sofisticados baseados em aprendizagem automática, assim como métodos mais directos baseados em dicionários de entidades ou expressões regulares. O seguinte exemplo mostra como a ferramenta LingPipe pode ser utilizada para encontrar entidades (neste caso endereços de email) sobre um texto, com base na utilização de expressões regulares.
import com.aliasi.chunk.*;
import java.util.*;
public class ExampleFindEmails extends RegExChunker {
public ExampleFindEmails() {
super(EMAIL_REGEX,CHUNK_TYPE,CHUNK_SCORE);
}
private final static String EMAIL_REGEX = "[A-Za-z0-9](([_\\.\\-]?[a-zA-Z0-9]+)*)@([A-Za-z0-9]+)(([\\.\\-]?[a-zA-Z0-9]+)*)\\.([A-Za-z]{2,})";
private final static String CHUNK_TYPE = "email";
private final static double CHUNK_SCORE = 1.0;
public static void main(String[] args) {
Chunker chunker = new ExampleFindEmails();
for (int i = 0; i < args.length; ++i) {
Chunking chunking = chunker.chunk(args[i]);
System.out.println("input=" + args[0]);
Set chunkSet = chunking.chunkSet();
Iterator it = chunkSet.iterator();
while (it.hasNext()) {
Chunk chunk = (Chunk) it.next();
int start = chunk.start();
int end = chunk.end();
String text = args[0].substring(start,end);
System.out.println(" extraccão=" + chunk + " valor=" + text);
}
}
}
}
Já o exemplo que se segue mostra como o LingPipe pode ser utilizado para encontrar entidades em texto com base num dicionário de palavras.
import com.aliasi.chunk.*;
import com.aliasi.dict.*;
import com.aliasi.tokenizer.*;
import java.util.*;
public class ExampleEntityRecognition {
static final double CHUNK_SCORE = 1.0;
public static void main(String[] args) {
// Define the dictionary
MapDictionary dictionary = new MapDictionary();
dictionary.addEntry(new DictionaryEntry("Bruno Martins","PERSON",CHUNK_SCORE));
dictionary.addEntry(new DictionaryEntry("Spatial Databases","DB_ID_1232",CHUNK_SCORE));
dictionary.addEntry(new DictionaryEntry("livro","PRODUCT",CHUNK_SCORE));
// Recognizer for dictionary entries (true,true=allmatches,case_sensitive)
ExactDictionaryChunker chunker = new ExactDictionaryChunker(dictionary,IndoEuropeanTokenizerFactory.FACTORY,true,true);
for (int i = 0; i < args.length; ++i) {
String text = args[i];
System.out.println("TEXT=" + text);
System.out.println("All matches=" + chunker.returnAllMatches() + " Case sensitive=" + chunker.caseSensitive());
Chunking chunking = chunker.chunk(text);
for (Chunk chunk : chunking.chunkSet()) {
int start = chunk.start();
int end = chunk.end();
String type = chunk.type();
double score = chunk.score();
String phrase = text.substring(start,end);
System.out.println("phrase=|" + phrase + "|" + " start=" + start + " end=" + end + " type=" + type + " score=" + score);
}
}
}
}
Exemplos mais detalhados da utilização da ferramenta LingPipe podem ser encontrados online no site da mesma (
http://www.alias-i.com/lingpipe/web/demos.html
).
Combinando as ferramentas Web-harvest e LingPipe
Uma forma muito simples de combinar a API da ferramenta LingPipe com processadores da ferramenta Web-harvest para extracção de informação (por exemplo para classificar o conteúdo textual dado como resultado de um outro processo de extracção) envolve a utilização do Web-harvest a partir de uma aplicação Java que passe um Objecto específico que faça chamadas a métodos na API do LingPipe como uma variável de contexto. O exemplo que se segue mostra como isso pode ser feito:
import org.webharvest.definition.ScraperConfiguration;
import org.webharvest.runtime.Scraper;
public class WebHarvestTest {
public static void main(String[] args) throws Exception {
ScraperConfiguration config = new ScraperConfiguration("webharvest-config.xml");
Scraper scraper = new Scraper(config, "./work-dir/");
scraper.addVariableToContext("langClassification", new ExampleLangClassification());
scraper.setDebug(true);
scraper.execute();
}
}
O objecto ExampleLangClassification passará assim a poder ser utilizado em qualquer expressão dada como parte de um processador no ficheiro de configuração do Web-harvest.
<var-def name="language">
<template>
${langClassification.getWrappedObject().
classify("texto de exemplo");}
</template>
</var-def>
Em alternativa, o Web-harvest também permite a chamada a métodos Java através de um processador que permite a utilização de linguagens de scripting. Mais informações poderão ser obtidas na documentação da ferramenta Web-harvest.
Links:
- Introduction to Text Mining - Tutorial at EDBT 2006 ( http://www.edbt2006.de/edbt-share/IntroductionToTextMining.pdf )
- Information Extraction: Distilling Structured Data from Unstructured Text ( http://www.acmqueue.org/modules.php?name=Content&pa=showpage&pid=350 )