300 likes | 438 Views
INF2820 Datalingvistikk – V2012. Jan Tore Lønning. Litt Python. Hvorfor Pyhton. NLTK – Natural Language Tool Kit : Omgivelser for å eksperimentere med datalingvistikk Diverse datalingvistiske algoritmer Inkluderte språkdata, korpora Vekt på læring
E N D
INF2820 Datalingvistikk – V2012 Jan Tore Lønning
Hvorfor Pyhton • NLTK – Natural LanguageToolKit: • Omgivelser for å eksperimentere med datalingvistikk • Diverse datalingvistiske algoritmer • Inkluderte språkdata, korpora • Vekt på læring • Python var først scripting language: • Styre andre programmer, inkludert NLTK rutiner • Gode redskaper for behandling av tekst • string, list • Intuitiv og lesbar syntaks • som en pseudokode • ”Read-eval-print”-løkke for rask utvikling
Python syntaks • Tilordning: • a = 5 • Python bruker indent som blokkavgrenser: • Andre språk: begin-end, ( ) • Hva tror du blir resultatet av kallene • f(8) • g(8) def f(i): for j in [2,3,4]: i=j+i print i def g(i): for j in [2,3,4]: i=j+i print i
Python datatyper >>> a = "Hello world" >>> a 'Hello world' >>> len(a) 11 >>> a[0] 'H' >>> a[-1] 'd' >>> b = a[3:7] >>> b 'lo w' >>> type(b) <type 'str'> >>>c = 10 >>>e = [3,4,c,c+c,5*c] >>>e [3,4,10,20,50] >>>e[3] = 19 >>>e [3,4,10,19,50] >>>f = e[1:] >>>f [4,10,19,50] >>>e[3]=f >>>e [3,4,10,[4,10,19,50],50] >>>f[2]=0 >>>e ? • integer • float • string: • ”Hello world” • lister: • [3, 4, 5] • [’Hello’, ’world’] • [3, 4, c] • Aksesseres med indekser • ”mutable”
Python er objektorientert • Alt er objekter • Har sine metoder • Eksempler med strenger: • ”Helloworld,”.split() • ”world,”.strip(’,’)
DFA i Python if state in fa.finals: return True: else: return False defrecognize(fa, streng): state = fa.start while True: if len(streng)==0: return state in fa.finalselif (state,streng[0]) not in \fa.edge.keys(): return False else: state = fa.edge[(state,streng[0])] streng = streng[1:] samme som Jurafsky & Martin, fig. 2.13 Enkel Python
DFA i Python - datastruktur defrecognize(fa, streng): state = fa.start while True: if len(streng)==0: return state in fa.finalselif (state,streng[0]) not in \fa.edge.keys(): return False else: state = fa.edge[(state,streng[0])] streng = streng[1:] class DFA: def __init__(self): self.edge = {} self.finals = [] f = DFA() f.start = 0 f.finals.append(4) f.edge[(0,'b')] = 1 f.edge[(1,'a')] = 2 f.edge[(2,'a')] = 3 f.edge[(3,'a')] = 3 f.edge[(3,'!')] = 4 • Denne strukturen for visning på skjerm • Bedre praksis (mer tekst): • Rutiner i klassen som leser inn data og konstruerer objektet • Legg funksjonen som metode i klassen Enkel Python Datastruktur
Rekursjon iterasjon defrecognize(fa, streng): state = fa.startwhile True: if len(streng)==0: return state in fa.finalselif (state,streng[0]) not in \fa.edge.keys(): return False else: state = fa.edge[(state,streng[0])] streng = streng[1:] def recognize3(fa, streng, trace=0): state = fa.startreturn rec(fa, state, streng, trace)def rec(fa, state, streng, trace): if trace > 0: print streng, state if len(streng)==0: return state in fa.finalselif (state, streng[0]) not in \ fa.edge.keys(): return False else: state = fa.edge[(state,streng[0])] return rec(fa, state, streng[1:], trace) Rekursiv Iterativ
Breddeførst søk • JFLAP • Parallellsøk er noe tilsvarende
Dybdeførst søk • m/ Backtracking • Jurafsky og Martin
Husk: rekursiv DFA defrecognize(fa, streng): state = fa.startwhile True: if len(streng)==0: return state in fa.finalselif (state,streng[0]) not in \fa.edge.keys(): return False else: state = fa.edge[(state,streng[0])] streng = streng[1:] def recognize3(fa, streng, trace=0): state = fa.startreturn rec(fa, state, streng, trace)def rec(fa, state, streng, trace): if trace > 0: print streng, state if len(streng)==0: return state in fa.finalselif (state, streng[0]) not in \ fa.edge.keys(): return False else: state = fa.edge[(state,streng[0])] return rec(fa, state, streng[1:], trace) Rekursiv Iterativ
NFA i Python - Backtracking def recognize4(fa, streng, trace=0): state = fa.start return rec(fa, state, streng, trace) def rec(fa, state, streng, trace): if trace > 0: print streng, state if len(streng) == 0: return state in fa.finalselse: states = [e[2] for e in fa.edges if state == e[0] and streng[0] == e[1] ] for state in states: if rec(fa,state, streng[1:], trace): return True return False def recognize3(fa, streng, trace=0): state = fa.start return rec(fa, state, streng, trace)def rec(fa, state, streng, trace): if trace > 0: print streng, state if len(streng)==0: return state in fa.finalselif (state, streng[0]) not in \ fa.edge.keys(): return False else: state = fa.edge[(state,streng[0])] return rec(fa, state, streng[1:], trace) DFA NFA uten -transisjoner
NFA i Python - Datastruktur def recognize4(fa, streng, trace=0): state = fa.start return rec(fa, state, streng, trace) def rec(fa, state, streng, trace): if trace > 0: print streng, state if len(streng) == 0: return state in fa.finalselse: states = [e[2] for e in fa.edges if state == e[0] and streng[0] == e[1] ] for state in states: if rec(fa,state, streng[1:], trace): return True return False class NFA: def __init__(self): self.edges = [] self.finals = [] … f = NFA(…) f.start = 0 f.finals.append(4) f.edges= [ (0,'b',1), (1,'a',2), (2,'a',3), (3,'a',3), (3,'!',4) ] g=NFAFromFile('template.nfa') NFA uten -transisjoner
Python: ”list comprehension” edges = [e for e in fa.edges if state == e[0] and streng[0] == e[1] ] edges = [] for e in fa.edges: if state == e[0] and streng[0] ==e[1]: edges.append(e)
Python: ”list comprehension” states = [e[2] for e in fa.edges if state == e[0] and streng[0] == e[1] ] states = [e[2] for e in fa.edges if state==e[0] and streng[0]==e[1] ] states = [] for e in fa.edges: if state==e[0] and streng[0]==e[1]: states.append(e[2])
Jurafsky og Martins algoritme Strengt tatt: nøytral mht. Dybde-førstvsbredde-først Bruker løkke+agenda i stedet for rekursjon
Egenskaper ved algoritmene • Både • dybde-førstm/backtracking • breddeførst vil i verste fall ha eksponentielt tidsforbruk proporsjonalt med • kn, der • n= |w|, lengden av input • k2 er maks antall kanter fra en node merket med samme symbol • Med epsilontransisjoner • Kan risikere ikke terminerer! • Men vi vet jo at hvis vi først lager DFA får vi linjært tidsforbruk!
En raskere algoritme • En konfigurasjon består av: • En mengde tilstander • Resten av strengen • Start: • Q0 = E({q0}) • (E er epsillontillukning) • Oppdatering • Gitt konfigurasjon: • w_n = sw’ • Qn={q1, …, qk} • La ny konfigurasjon være • w_n+1 = w’ • Qn+1=E(N(q1,s)N(q2,s)… N(qk,s)) • Akseptering • Konfigurasjonen • w_n = • Qn={q1, …, qk} Aksepterer hvis minst en av q1, …, qk er en sluttilstand.
NFA-anerkjenning i Python (uten ) defrecognize(fa, streng): state = fa.start while True: if len(streng)==0: return state in fa.finalselif(state,streng[0]) not in \fa.edge.keys(): return False else: state = fa.edge[(state,streng[0])]streng = streng[1:] def recognize5(self, streng, trace=0): states = [self.start] while True: if trace > 0: print streng, list(states) if len(streng)==0: successtates = [s for s in states if s in self.finals] return len(successtates)> 0 eliflen(states) == 0: return False else: states = set([e[2] for e in self.edges if e[0] in states and streng[0] == e[1] ]) streng = streng[1:] Deterministisk Ikke-deterministisk
Egenskaper • Svarer til underveis å bygge de delene vi trenger av DFA-ene som svarer til denne NFA-en. • Algoritmen er linjær i |w|=n. • Men kvadratisk i antall tilstander: m • O(n m**2) • Terminerer
Implementasjonon av NFA-er Oppsummering: • DFA-algoritmen: • Konstruer en ekvivalent DFA • (Minimaliser denne) • Bruk DFA-en • NFA-algoritmen: • Som simulerer DFA underveis For 1: Teoretisk raskere Mot 1: • DFA-en kan få 2n tilstander der n er tilstander i NFA-en: • Tar mye plass • Kan i praksis ta lengre tid å slå opp i DFA-en Hvilken algoritme som er best: • Er et empirisk spørsmål • Avhenger av oppgaven
Regulære uttrykk – to tilnærminger Teoretisk Praktisk ”RegEx” Unix (grep/egrep), Perl, Emacs, … Tilstreber effektiv i bruk Spesialsymboler, div. forkortelser. MEN: kan inneholde muligheter som går ut over de regulære språkene! • Sett på så langt • Oprinnelig (1950-tallet) • J&M seksj 2.3 • Tilstreber: • Minst mulig notasjon for å definere klassen • Formelt meget veldefinert
Forskjeller til teoretiske RE • Vi beskriver ikke et språk men søker etter substrenger av et språk • Ankere • ^ begynnelsen av linjen • $ slutten av linjen • Går ut over rene RE • Muligheten til å referere tilbake til hele grupper: • Går utover regulære språk • Kan ikke uten videre bruke DFA som algoritme
Implementasjon av regex • Backtracking: • En prøver å matche regex direkte mot (et segment av) strengen • Leser regex fra venstre mot høyre • (tilpasset for * + …) • Ser om en kan utvide strengsegmentet til å matche neste symbol i regex • Hvis ikke: backtrack – gå tilbake på tidligere valg SØK: finn et delsegment av strengen som matcher OBS: Regex går også utover kontekstfrie språk
Implementasjon av regex • Hvis ekte regulært uttrykk: • Gjør om til NFA • Bruk algoritme 1 eller 2 • Hvis regex går utover regulære uttrykk er det vanlige • Bruk algoritme av type 3
Ta med hjem: • Gitt en NFA: N som beskriver et språk L=L(N) • Da finnes det en DFA: D som beskriver samme språk, L=L(D) • Skal vi implementere N, kan vi enten konstruere D (forrige gang) • Eller prosessere direkte med N (som om det var D) • Uansett er prosedyren • Ikke flertydig • Deterministisk • Tidsforbruket er linjært i input