1º semestre
Mini‐Projecto 3 – Entrega a 25/11/2010
Os dois URLs que se listam de seguida correspondem a dois documentos XML
codificando informação sobre programas de televisão. Note‐se que os dois
documentos XML codificam informação semelhante, embora de formas diferentes.
1.
http://gibson.tagus.ist.utl.pt/~bmartins/tv‐shows‐info.xml
2.
http://gibson.tagus.ist.utl.pt/~bmartins/new‐tv‐shows‐info.xml
Utilizando o software para processamento de documentos XML, introduzido nas aulas
de laboratório, resolva os seguintes exercícios práticos.
Exercício 1
Usando os documentos XML de nome tv‐shows‐info.xml e new‐tv‐shows‐info.xml,
resolva as seguintes alíneas:
1.1 – Construa um dicionário com base nos nomes de actores mencionados no
documento tv‐shows‐info.xml, que entraram em mais de um episódio de alguma série.
1.2 ‐ Usando o dicionário da alínea anterior, escreva uma XQuery que, através da
função de extensão de nome java:gti.dictionarychunk(), permita extrair
todos os nomes de actores mencionados nos conteúdos textuais das reviews do
documento new‐tv‐shows‐info.xml.
1.3 ‐ A função de extensão java:gti.dictionarychunk(), descrita nas aulas
de laboratório e construída com base nas funcionalidades disponibilizadas pela API do
LingPipe, corresponde ao método Java cujo código se apresenta na Figura 1.
public static String[] dictionarychunk(String text, String ent) throws Exception { MapDictionary<String> dictionary = new MapDictionary<String>();
for (int i=0; i<ent.length; i++)
dictionary.addEntry(new DictionaryEntry<String>(ent[i],”chunk”,1.0)); ExactDictionaryChunker dictionaryChunkerTT = new
ExactDictionaryChunker(dictionary,
IndoEuropeanTokenizerFactory.INSTANCE, true, true); Chunking chunking = dictionaryChunkerTT.chunk(text);
List<String> results = new ArrayList<String>(); for (Chunk chunk : chunking.chunkSet()) { int start = chunk.start();
int end = chunk.end(); String type = chunk.type(); double score = chunk.score();
String txt = text.substring(start,end); results.add(txt);
}
return results.toArray(new String[0]); }
Figura 1 – Método Java correspondente à função java:gti.dictionarychunk().
Crie uma nova função de extensão, denominada approxdictionarychunk(), que em
lugar de fazer o emparelhamento exacto com todas as entidades mencionadas no
dicionário, permita reconhecer todas as entidades mencionadas que tenham uma
distância de edição inferior a dois em relação às entidades mencionadas no dicionário.
O código Java da função deverá ser apresentado como resolução deste exercício.
Sugestão: Deve consultar a documentação (i.e., os tutoriais e a documentação
Javadoc) da API do LingPipe, que se encontra disponível através do site
http://alias‐
i.com/lingpipe/
. Em particular, deverá ser analisada em detalhe a documentação
disponível para a classe com.aliasi.dict.ApproxDictionaryChunker.
1.4 ‐ Usando o dicionário da alínea anterior, escreva uma XQuery que, através da
função java:gti.approxdictionarychunk() criada na alínea anterior,
permita extrair todos os nomes de actores mencionados nos conteúdos textuais das
reviews do documento new‐tv‐shows‐info.xml.
Exercício 2
Usando os documentos XML de nome tv‐shows‐info.xml e new‐tv‐shows‐info.xml,
resolva as seguintes alíneas:
2.1 – Escreva uma XQuery que, através do uso de um Hidden Markov Model, permita
extrair das reviews do documento new‐tv‐shows‐info.xml os nomes de criativos lá
mencionados. Para treinar o modelo de extracção, deve usar os exemplos anotados
que se encontram no URL
http://gibson.tagus.ist.utl.pt/~bmartins/persons.xml
.
2.2 – Com base nos criativos associados aos programas de televisão que se encontram
descritos nos documentos tv‐shows‐info.xml e new‐tv‐shows‐info.xml, escreva uma
XQuery que permita associar, a cada um dos nomes de criativos extraídos na alínea
anterior, um URL para uma página Web contendo informação detalhada sobre a
carreira da pessoa. Os criativos extraídos que não tenham um URL associado deverão
ser removidos da resposta produzida neste exercício.
Exercício 3
Usando os documentos XML tv‐shows‐info.xml e new‐tv‐shows‐info.xml, resolva as
seguintes alíneas:
3.1 – Utilizando as funções de extensão relacionadas com classificação de documentos,
introduzidas nas aulas de laboratório, treine um modelo de classificação que aprenda a
classificar reviews de programas de televisão como positivas ou negativas. Como dados
de treino, deverá utilizar as reviews que se encontram já classificadas desta forma no
documento tv‐shows‐info.xml.
3.2 – Utilizando o modelo de classificação desenvolvido na alínea anterior, classifique
as reviews que se encontram no documento new‐tv‐shows‐info.xml.
3.3 – Avalie a qualidade dos resultados do classificador produzido na alínea anterior
com base nas métricas de Precisão e Cobertura. Considere que todas as reviews com
pontuação de 6 estrelas ou mais deveriam ser classificadas como positivas, e que as
restantes reviews deveriam ser classificadas como negativas.
Exercício 4
Considere o seguinte Hidden Markov Model, M=(A,B,p), desenhado para identificar
ocorrências de nomes de programas de televisão em sequências de palavras.
Os estados considerados no modelo correspondem a etiquetas do tipo Show (i.e.,
Show_INICIO, Show_MEIO, Show_FIM) ou NÃO_Show, em que os vários estados
associados à etiqueta Filme pretendem capturar o início de um nome de um filme, o
meio de um nome de filme, e o fim de um nome de filme.
MATRIZ A
Show_INICIO Show_MEIO
Show_FIM
NÃO_Show
Show_INICIO (I)
0,15
0,25
0,30
0,30
Show_MEIO (M)
0,00
0,30
0,70
0,00
Show_FIM (F)
0,20
0,00
0,00
0,80
NÃO_Show (N)
0,30
0,00
0,00
0,70
MATRIZ B
Show_INICIO Show_MEIO
Show_FIM
NÃO_Show
Laurie (1)
0,05
0,01
0,05
0,20
Stars (2)
0,08
0,01
0,02
0,11
Mr. (3)
0,10
0,05
0,00
0,13
House (4)
0,32
0,15
0,25
0,01
Adder (5)
0,10
0,25
0,45
0,04
Black (6)
0,23
0,22
0,10
0,02
<other_words> (7) 0,12
0,26
0,13
0,39
<pontuation> (8)
0,00
0,05
0,00
0,10
PROBABILIDADES INICIAIS (p)
Show_INICIO
Show_MEIO
Show_FIM
NÃO_Show
0,20
0,00
0,00
0,80
No modelo apresentado, A é a matriz de transição entre estados, B é a probabilidade
de gerar cada símbolo em cada estado e p é a probabilidade inicial de cada estado.
4.1 ‐ Represente graficamente a máquina de estados correspondente ao modelo M.
4.2 ‐ Calcule a sequência de estados mais provável de ter gerado a frase: “Mr. Laurie
stars in Black Adder and in House.”. Apresente os cálculos efectuados em cada passo.
4.3 ‐ Sugira duas modificações ao modelo que pudessem melhorar o seu desempenho.
Justifique as suas respostas.
Exercício 5
Utilizando os documentos XML de nome tv‐shows‐info.xml e new‐tv‐shows‐info.xml,
resolva as seguintes alíneas:
5.1 – Defina um formato de representação comum, através de um XML Schema, para
as duas fontes de dados correspondentes aos documentos tv‐shows‐info.xml e new‐tv‐
shows‐info.xml. O formato de representação deve tentar preservar, ao máximo, a
informação que se encontra em cada uma das fontes de dados distintas.
5.2 – Escreva duas funções em XQuery (i.e., dois wrappers) que permitam,
respectivamente, converter os dados dos documentos tv‐shows‐info.xml e new‐tv‐
shows‐info.xml para o formato de representação comum. Cada um dos wrappers deve
produzir um documento XML válido de acordo com o XML Schema da alínea anterior.
5.3 – Escreva uma função em XQuery (i.e., um mediador) que permita integrar a
informação retornada pelos dois wrappers desenvolvidos na alínea anterior. Neste
exercício, não é necessário levar em consideração a eliminação de programas de
televisão potencialmente duplicados nas duas fontes. O mediador deve produzir um
documento XML válido de acordo com o XML Schema da primeira alínea.
Entrega do terceiro mini‐projecto
A resolução do mini‐projecto deve ser entregue via Fénix sob a forma de um ficheiro
com a extensão .zip, até às 08:00 do dia estipulado para a entrega (i.e., antes da aula
teórica da disciplina de Gestão e Tratamento de Informação).
O ficheiro .zip deve conter os ficheiros de texto com as soluções (e.g., documentos
XML, XSD, XSLT ou ficheiros de texto com as interrogações XPath/XQuery) para cada
uma das perguntas/alíneas individuais deste enunciado.
Na aula teórica da data de entrega, deve ainda ser entregue um relatório impresso
com a resolução das várias perguntas, segundo o template fornecido na página da
disciplina. O relatório deve ter uma folha de rosto ou um cabeçalho identificando
claramente qual o número do grupo e quais os números de aluno dos 3 elementos.
Para cada pergunta, e além de listar a respectiva solução para o problema, o relatório
deve ainda indicar claramente qual o nome do ficheiro que contém a sua resolução.
Não serão aceites trabalhos entregues via e‐mail, nem trabalhos onde o relatório
não obedece às regras estipuladas.
Boa sorte na realização do mini‐projecto!
Resolução do mini‐projecto 3
Pergunta 1.1
declare namespace ns="http://gibson.tagus.ist.utl.pt/~bmartins/namespace-tvshows"
let $doc := doc("http://gibson.tagus.ist.utl.pt/~bmartins/tv-shows-info.xml") let $dic := distinct-values($doc//ns:actor[@episodes>1]/@name)
return $dic
Pergunta 1.2
declare namespace ns = "http://gibson.tagus.ist.utl.pt/~bmartins/namespace-tvshows"; declare namespace gti = "java:gti";
let $doc := doc("http://gibson.tagus.ist.utl.pt/~bmartins/tv-shows-info.xml") let $dict := distinct-values($doc//ns:actor[@episodes>1]/@name)
let $doc2 := doc("http://gibson.tagus.ist.utl.pt/~bmartins/new-tv-shows-info.xml") let $revs := string-join(data($doc2//show-reviews) , " ")
return distinct-values(gti:dictionarychunk($revs,$dict))
Pergunta 1.3
import com.aliasi.tokenizer.IndoEuropeanTokenizerFactory; import com.aliasi.chunk.*; import com.aliasi.dict.*; import com.aliasi.spell.*; import java.util.*;public class ApproximateChunk {
public static String[] approxdictionarychunk(String text,
String ent[]) throws Exception { TrieDictionary<String> dictionary = new TrieDictionary<String>();
for (int i = 0; i < ent.length; i++) {
dictionary.addEntry(new DictionaryEntry<String>(ent[i], "chunk", 1.0)); }
ApproxDictionaryChunker dChunkerTT = new ApproxDictionaryChunker(dictionary, IndoEuropeanTokenizerFactory.INSTANCE,
new FixedWeightEditDistance(0,-1,-1,-1,Double.NaN), 1.0);
Chunking chunking = dChunkerTT.chunk(text); List<String> results = new ArrayList<String>(); for (Chunk chunk : chunking.chunkSet()) { int start = chunk.start();
int end = chunk.end(); String type = chunk.type(); double score = chunk.score();
String txt = text.substring(start, end); results.add(txt);
}
return results.toArray(new String[0]); }
}
Pergunta 1.4
declare namespace ns = "http://gibson.tagus.ist.utl.pt/~bmartins/namespace-tvshows"; declare namespace appx = "java:ApproximateChunk";
let $doc := doc("http://gibson.tagus.ist.utl.pt/~bmartins/tv-shows-info.xml") let $dict := distinct-values($doc//ns:actor[@episodes>1]/@name)
let $doc2 := doc("http://gibson.tagus.ist.utl.pt/~bmartins/new-tv-shows-info.xml") let $revs := string-join(data($doc2//show-reviews) , " ")
return distinct-values(appx:approxdictionarychunk($revs,$dict))
Pergunta 2.1
declare namespace gti = "java:gti";
let $doc := doc("http://gibson.tagus.ist.utl.pt/~bmartins/new-tv-shows-info.xml") let $train := doc("http://gibson.tagus.ist.utl.pt/~bmartins/persons.xml")
let $revs := string-join( data($doc//show-reviews) , " ") return distinct-values(gti:mlchunk($revs,$train))
Pergunta 2.2
declare namespace ns = "http://gibson.tagus.ist.utl.pt/~bmartins/namespace-tvshows"; declare namespace gti = "java:gti";
let $doc := doc("http://gibson.tagus.ist.utl.pt/~bmartins/new-tv-shows-info.xml") let $train := doc("http://gibson.tagus.ist.utl.pt/~bmartins/persons.xml")
let $revs := string-join( data($doc//show-reviews) , " ")
let $doc2 := doc("http://gibson.tagus.ist.utl.pt/~bmartins/tv-shows-info.xml") for $creat in distinct-values(gti:mlchunk($revs,$train))
let $ids := distinct-values(($doc2//ns:actor[data(@name)=$creat]/data(@id) , $doc2//ns:writer[data(@name)=$creat]/data(@id) , $doc2//ns:director[data(@name)=$creat]/data(@id) , $doc//creative[data(@name)=$creat]/data(@id))) where string-length($ids[1])>0
return <creative name="{$creat}" id="{$ids[1]}"/>
Pergunta 3.1
declare namespace gti = "java:gti";
declare namespace ns2 = "http://gibson.tagus.ist.utl.pt/~bmartins/namespace-reviews"; let $doc := doc("http://gibson.tagus.ist.utl.pt/~bmartins/tv-shows-info.xml") let $model := gti:classify_train( $doc//ns2:review/ns2:text/text(),
$doc//ns2:review/string(@sentiment-analysis) ) return $model
Pergunta 3.2
declare namespace gti = "java:gti";
declare namespace ns2 = "http://gibson.tagus.ist.utl.pt/~bmartins/namespace-reviews"; let $doc := doc("http://gibson.tagus.ist.utl.pt/~bmartins/tv-shows-info.xml") let $model := gti:classify_train( $doc//ns2:review/ns2:text/text(),
$doc//ns2:review/string(@sentiment-analysis) ) let $doc2 := doc("http://gibson.tagus.ist.utl.pt/~bmartins/new-tv-shows-info.xml") return
<reviews> {
for $review in $doc2//review return <review show="{$review/../../@title}" sentiment-analysis="{gti:classify($review/text(),$model)}" score="{$review/@score}">{$review/text()}</review> } </reviews>
Pergunta 3.3
declare namespace gti = "java:gti";
declare namespace ns2 = "http://gibson.tagus.ist.utl.pt/~bmartins/namespace-reviews"; let $doc := doc("http://gibson.tagus.ist.utl.pt/~bmartins/tv-shows-info.xml") let $model := gti:classify_train( $doc//ns2:review/ns2:text/text(),
$doc//ns2:review/string(@sentiment-analysis) ) let $doc2 := doc("http://gibson.tagus.ist.utl.pt/~bmartins/new-tv-shows-info.xml") let $resuls := <reviews>{
for $review in $doc2//review return <review show="{$review/../../@title}"
sentiment-analysis="{gti:classify($review/text(),$model)}" score="{$review/@score}">{$review/text()}</review>
}</reviews>
let $crr_pos := count($resuls//review[data(@score) >= 6 and
data(@sentiment-analysis)="pos"]) let $crr_neg := count($resuls//review[data(@score) < 6 and
data(@sentiment-analysis)="neg"]) let $cnt_pos := count($resuls//review[data(@sentiment-analysis)="pos"]) let $cnt_neg := count($resuls//review[data(@sentiment-analysis)="neg"]) let $tot_pos := count($resuls//review[data(@score) >= 6])
let $tot_neg := count($resuls//review[data(@score) < 6]) let $pre_pos:= $crr_pos div $cnt_pos
let $pre_neg:= $crr_neg div $cnt_neg let $rec_pos:= $crr_pos div $tot_pos let $rec_neg:= $crr_neg div $tot_neg
return <results precision_pos="{$pre_pos}" recall_pos="{$rec_pos}" precision_neg="{$pre_neg}" recall_neg="{$rec_neg}"/>
Pergunta 4.1
Pergunta 4.2
Em casa posição k da sequência de tokens, o algoritmo de Viterbi calcula a probabilidade do estado q
kassumir um dado valor si, a probabilidade de termos atingido um estado qk seguindo um caminho desde
q1 ... qk‐1, e a probabilidade de termos gerado uma sequência de observações o1 ... ok. O algoritmo de
Viterbi calcula as probabilidades de uma forma recursiva.
δ1(i) = πi * bi(o1)
δ
k+1(j) = max
1 ≤ i ≤ n(δ
k(i) * a
ij) * b
j(o
t+1)
O algoritmo também nos permite descobrir a sequencia de estados mais provável, através de uma
matriz I tal como definida abaixo:
I[j,1] = 0
I[j,k] = argmax1 ≤ i ≤ n δk‐1(i) * aij
A matriz I permite‐nos reconstruir a sequência de estados mais provável através de backtracking.
Pergunta 4.3
Várias alterações seriam possíveis:
•
Alterar a matriz com as probabilidades de geração de símbolos, por forma a considerar um número
de símbolos maior (e.g., decompondo o símbolo other_words, uma vez que estas palavras podem
pertencer tanto a locais como a não locais). As próprias probabilidades desta matriz poderiam ser re‐
estimadas com base em dados de treino, possibilitando‐se desta forma uma melhor adequação a
sequencias de símbolos reais.
•
Considerar um número de estados maior no modelo (e.g., decompondo o estado NAO_SHOW em
NAO_SHOW_INICIO, NAO_SHOW_MEIO e NAO_SHOW_FIM), possibilitando assim uma melhor
modelação das transições entre os diferentes estados.
Pergunta 5.1
Um possível formato de representação comum para as duas fontes de dados seria o formato XML que
utilizado no documento tv-shows-info.xml, uma vez que este já considera todos os campos de
informação usados nas duas fontes de dados. Um XML Schema para este formato de representação foi
já definido na pergunta 1 do primeiro mini-projecto da disciplina de GTI.
Perguntas 5.2 e 5.3
declare namespace gti = "java:gti";
declare namespace ns1 = "http://gibson.tagus.ist.utl.pt/~bmartins/namespace-tvshows"; declare namespace ns2 = "http://gibson.tagus.ist.utl.pt/~bmartins/namespace-reviews"; declare function local:wrapper1 () {
let $doc := doc("http://gibson.tagus.ist.utl.pt/~bmartins/tv-shows-info.xml") return $doc
};
declare function local:wrapper2 () { <ns1:tvshows>
{
for $d in doc("http://gibson.tagus.ist.utl.pt/~bmartins/new-tv-shows-info.xml")//tvshow return <ns1:tvshow>
<ns1:show-title>{data($d/@title)}</ns1:show-title> <ns1:companies>{for $a in $d//company return
<ns1:company name="{data($a)}" id="{$a/@id}"/>} </ns1:companies>
<ns1:creators>{for $a in $d//creative[@title="creator"] return <ns1:creator name="{$a/@name}" id="{$a/@id}" />} </ns1:creators>
<ns1:directors>{for $a in $d//creative[@title="director"] return <ns1:director name="{$a/@name}" id="{$a/@id}" />} </ns1:directors>
<ns1:writers>{for $a in $d//creative[@title="writer"] return <ns1:writer name="{$a/@name}" id="{$a/@id}"/>} </ns1:writers>
<ns1:actors>{for $a in $d//creative[@title="actor"] return <ns1:actor name="{$a/@name}" id="{$a/@id}" />} </ns1:actors>
<ns1:sinopsis>{$d/summary/text()}</ns1:sinopsis> <ns1:genres>{for $a in $d//show-genre return <ns1:genre name="{$a/@name}" />} </ns1:genres>
<ns2:reviews>{for $a in $d//review return <ns2:review score="{$a/@score}"
sentiment-analysis="{if($a/@score > 5) then ("pos") else ("neg")}"> <ns2:author reviewer-id="{$a/@reviewer-id}"> {data($a/@reviewer-name)} </ns2:author> <ns2:text>{data($a)}</ns2:text> </ns2:review>} </ns2:reviews> </ns1:tvshow> } </ns1:tvshows> };
declare function local:mediador () {
<ns1:tvshows>{ local:wrapper1()//ns1:tvshow union local:wrapper2()//ns1:tvshow}</ns1:tvshows>
};
local:mediador()