Segundo Trabalho Prático de GTI Resolução Exercício 1 Escreva as expressões regulares correspondentes a cada uma das seguintes situações: Aceitar um inteiro positivo com um máximo de 5 dígitos entre 0 e 32768 (sem zeros na esquerda) Aceitar um número real positivo ou negativo. Aceitar uma password entre 4 e 8 caracteres, que comece com uma letra e tenha pelo menos um dígito. Aceitar um URL bem formado. Aceitar uma data no formato “MONTH_NAME DD, YYYY” Exercício 1 1) [0-9]|[1-9][0-9]{1,3}|[1-2][0-9]{4}|3[0-1][0-9]{3}|32[0-6][0-9]{2}|327[0-5][09]|3276[0-8] 2) [+-]?[0-9]*\.?[0-9]+ 3) [A-Za-z](?=.*\d).{3,7} 4) ((ht)|f)tp(s)?://([a-zA-Z0-9]+\.)+((pt)|(com))(/[a-zA-Z0-9_\.]*)+(\?([a-zA-Z00_]+=[a-zA-Z0-0_])(\&([a-zA-Z0-9_]+=[a-zA-Z0-9_]))*)? 5) (([Jj]aneiro)|([Ff]evereiro)|([Mm]arço)|([Aa]bril)|([Mm]aio)|([Jj]unho)|([Jj]ulho)|([ Aa]gosto)|([Ss]etembro)|([Oo]utubro)|([Nn]ovembro)|([Dd]ezembro))((0?[19])|([1-2][0-9)]|(3[0-1])) [0-9]{1-4} Exercício 2 Escreva um ficheiro de configuração para a ferramenta Web-harvest que permita aceder à página Web com endereço http://www.ist.utl.pt/information.php?boardId=7557 e extrair do seu conteúdo todas as noticias. A saída do processo de extracção deverá obedecer ao formato RSS. Na resolução deve constar o ficheiro de configuração do Web-harvest, o documento RSS usado como entrada e o resultado de saída. Exercício 2 <?xml version="1.0" encoding="UTF-8"?> <config charset="UTF-8"> <var-def name="url">http://www.ist.utl.pt/information.php?boardId=7557</var-def> <file action="write" path="data/data.xml" charset="UTF-8"> <![CDATA[ <rss version="2.0"> <channel> <title>Noticias do IST</title> <description>Noticias extraidas do site do IST</description> <link>]]><var name="url"/><![CDATA[</link>]]> Exercício 2 <xquery> <xq-param name="doc"> <html-to-xml outputtype="pretty"> <http url="${url}"/> </html-to-xml> </xq-param> <xq-expression><![CDATA[ declare variable $doc as node() external; for $i in 1 to count($doc//h3) let $title := data($doc//h3[@class='mtop2'])[$i] let $description := data($doc//div[@class='ann'])[$i] let $date := data($doc//p[@class='post_date'])[$i] let $author := data($doc//div[@class='ann']/p[@class='grey_bright']/a)[$i] Exercício 2 return <item> <title>{normalize-space($title)}</title> <description>{normalize-space($description)}</description> <pubDate>{normalize-space($date)}</pubDate> <author>{normalize-space($author)}</author> </item> ]]></xq-expression> </xquery> <![CDATA[ </channel> </rss>]]> </file> </config> Exercício 3 Escreva um programa Java que, utilizando o LingPipe, faça a extracção de todas as datas mencionadas no ficheiro RSS obtido como saída no Exercício 2. Na resolução deve constar o código Java e o resultado da extracção. Exercício 3 import com.aliasi.chunk.*; import java.util.*; import java.io.*; import javax.xml.xpath.*; import javax.xml.parsers.*; import javax.xml.transform.*; import org.w3c.dom.*; import org.xml.sax.*; public class RecognizeDates { private static final String CHUNK_TYPE = "date"; Exercício 3 private static final String regexp1 = "[0-9][0-9]( de)? ((Janeiro)|(Fevereiro)|(Março)|(Maio)|(Abril)|(Maio)|(Junho)|(Julho)|(Agosto)|(Setembro)|( Outubro)|(Novembro)|(Dezembro)) [0-9][0-9][0-9][0-9]"; private static final double score1 = 1.0; private RegExChunker chunker1; private static final String regexp2 = "((jan)|(fev)|(mar)|(mai)|(abr)|(mai)|(jun)|(jul)|(ago)|(set)|(out)|(nov)|(dez))(\\.)?( de)? [0-9][0-9][0-9][0-9]"; private static final double score2 = 0.8; private RegExChunker chunker2; Exercício 3 public RecognizeDates() { chunker1 = new RegExChunker(regexp1,CHUNK_TYPE,score1); chunker2 = new RegExChunker(regexp2,CHUNK_TYPE,score2); } Exercício 3 private void printChunks ( Chunker chunker, String text ) { Chunking chunking = chunker.chunk(text); 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 stext = text.substring(start,end); System.out.println("chunk="+chunk+" text="+stext); } } Exercício 3 public static void main ( String args[] ) throws Exception { RecognizeDates recognizer = new RecognizeDates(); DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); Document doc = builder.parse("data/data.xml"); XPath xp = XPathFactory.newInstance().newXPath(); XPathExpression expr = xp.compile("//item"); NodeList nodes = (NodeList)expr.evaluate(doc,XPathConstants.NODESET); Exercício 3 for (int i=0; i<nodes.getLength(); i++) { Node item = nodes.item(i); String text = (String) xp.compile("pubDate").evaluate(item, XPathConstants.STRING) + " - " + (String)xp.compile("description").evaluate(item, XPathConstants.STRING); System.out.println("*** Texto"); System.out.println(text); System.out.println("*** Resultados para o item " + i); recognizer.printChunks(recognizer.chunker1,text); recognizer.printChunks(recognizer.chunker2,text); System.out.println("***"); } }} Exercício 4 Escreva um programa que, utilizando a ferramenta LingPipe, faça a extracção de todos os nomes de departamentos do IST a partir do ficheiro RSS obtido como saída no Exercício 2. Pretende-se que a cada notícia seja associada a lista de departamentos nela mencionados. Deverá ser considerada a seguinte lista de departamentos do IST: Departamento de Engenharia Civil e Arquitectura (DECivil) Departamento de Engenharia Electrotécnica e de Computadores (DEEC) etc. Exercício 4 import com.aliasi.chunk.*; import com.aliasi.dict.*; import com.aliasi.tokenizer.*; import java.util.*; import java.io.*; import javax.xml.xpath.*; import javax.xml.parsers.*; import javax.xml.transform.*; import org.w3c.dom.*; import org.xml.sax.*; Exercício 4 public class RecognizeDepartments { private MapDictionary dictionary; private ExactDictionaryChunker chunker; public RecognizeDepartments() { dictionary = new MapDictionary(); Exercício 4 dictionary.addEntry(new DictionaryEntry("Departamento de Engenharia Civil e Arquitectura","DECivil",1.0)); dictionary.addEntry(new DictionaryEntry("Departamento de Engenharia Civil","DECivil",0.8)); dictionary.addEntry(new DictionaryEntry("DECivil","DECivil",0.8)); dictionary.addEntry(new DictionaryEntry("Engenharia Civil","DECivil",0.4)); dictionary.addEntry(new DictionaryEntry("Civil","DECivil",0.1)); dictionary.addEntry(new DictionaryEntry("Departamento de Engenharia Informática","DEI",1.0)); dictionary.addEntry(new DictionaryEntry("DEI","DEI",0.5)); dictionary.addEntry(new DictionaryEntry("Engenharia Informática","DEI",0.4)); dictionary.addEntry(new DictionaryEntry("Informática","DEI",0.1)); // Repetir para os restantes departamentos Exercício 4 chunker = new ExactDictionaryChunker(dictionary,IndoEuropeanTokenizerFactory.FACTORY, true, true); } Exercício 4 public String recognizeDepartments ( String text ) { StringBuffer aux = new StringBuffer(); Set result = new HashSet(); Chunking chunking = chunker.chunk(text); Set chunkSet = chunking.chunkSet(); Iterator it = chunkSet.iterator(); while (it.hasNext()) { Chunk chunk = (Chunk) it.next(); if(aux.length()!=0) aux.append(","); aux.append(chunk.type()); } return aux.toString(); } Exercício 4 public static void main ( String args[] ) throws Exception { RecognizeDepartments chunker = new RecognizeDepartments(); DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); Document doc = builder.parse("data/data.xml"); XPath xp = XPathFactory.newInstance().newXPath(); XPathExpression expr = xp.compile("//item"); NodeList nodes = (NodeList)expr.evaluate(doc,XPathConstants.NODESET); Exercício 4 for (int i=0; i<nodes.getLength(); i++) { Node item = nodes.item(i); String text = (String) xp.compile("title").evaluate(item, XPathConstants.STRING) + " - " + (String) xp.compile("description").evaluate(item, XPathConstants.STRING); String result = chunker.recognizeDepartments(text); System.out.println("*** Texto"); System.out.println(text); System.out.println("Resultado para o item " + i + " : " + result); System.out.println("***"); } }} Exercício 5 Responda às seguintes alíneas: Indique dois algoritmos de aprendizagem automática (Machine Learning) suportados pelo LingPipe. Com que finalidade pode cada um deles ser utilizado? Explique sucintamente o algoritmo de classificação Naive Bayes. Explique qual a assunção feita por um classificador Naive Bayes em relação aos termos individuais (i.e. explicar porque se diz que o classificador é “Naive”). Exercício 5 O LingPipe suporta os algoritmos de classificação Naive Bayes e Language Modeling (LMClassifier). Ambos se baseiam em processos estatísticos que assentam no teorema de Bayes, diferindo no facto de considerarem ou não a independência entre os termos. Outras respostas possíveis seriam um classificador baseado em redes neuronais (PerceptronClassifier) ou um classificador "vizinho mais próximo" (KNNClassifier). Um classificador Naive Bayes usa um processo estatístico baseado no teorema de Bayes, calculando a probabilidade do documento a classificar pertencer a uma dada classe (i.e. a classe de maior probabilidade é a escolhida para classificar o documento). O teorema de Bayes permite inverter o calculo desta probabilidade, podendo a mesma ser obtida a partir da probabilidade de ocorrência de um dado documento tendo-se a classe (esta podem ser estimada a partir da ocorrência de termos individuais num conjunto de treino) e da probabilidade de ocorrência de uma dada classe (que também pode ser estimada a partir de um conjunto de treino) Exercício 5 Um classificador Naive Bayes assume a independência entre os termos (e.g. a ocorrência de uma palavra num texto é independente da ocorrência de outras palavras) para efeitos de simplificação do calculo das probabilidades condicionais.