Du er ikke logget inn. Så lenge du ikke er logget inn går du glipp av muligheten for å holde styr på din egen progresjon.

Logg inn

Valgte tags:

Filtrering:

Skriv ut:

N-gram (Utfordringsoppgave)

Vanligvis bruker vi nltk sin n-gram-metode (eller tilsvarende), for å slippe å implementere noe selv. Ferdigimplementerte metoder er også ofte mer effektivt implementert enn det vi får til selv. For øvelsens skyld, og fordi det kan være gøy, skal du prøve å implementere n-grammer selv i denne oppgaven.

Et n-gram er en liste med tupler som deler opp en liste (ofte en setning), slik at alle kombinasjoner kommer med. Det lar oss modelere sammenhenger i ord på en grei måte. "n" i n-gram står for et vilkårlig tall. 1-gram kalles også unigram, 2-gram kalles bigram og 3-gram kalles trigram, osv.

Eksempler på uni-,bi- og trigrammer for setningen "Jeg liker å høste poteter ."

[('Jeg',), ('liker',), ('å',), ('høste',), ('poteter',), ('.',)]
[('Jeg', 'liker'), ('liker', 'å'), ('å', 'høste'), ('høste', 'poteter'), ('poteter', '.')]
[('Jeg', 'liker', 'å'), ('liker', 'å', 'høste'), ('å', 'høste', 'poteter'), ('høste', 'poteter', '.')]

Vi tar utgangspunkt i bruken til n-gram-metoden til NLTK. Den tar inn ei liste og et tall, slik:

ngrams(liste,tall)

...og gir oss setninger som i eksempelet over.

Merk at unigrammene ser "rare" ut fordi det er et komma der kun for å vise at det er et tuppel med ett element, det betyr ikke at det er to elementer hvorav ett er et tomt element.

Oppgave 1

Implementer en funksjon som tar inn ei liste, et tall (n) og returnerer ei liste med n-grammer som tupler. Hvis brukeren skriver et tall som er høyere enn antall elementer i lista, skal den returnere ei tom liste.

Oppgave 2

Gitt en vanlig liste med n-grammer har man ikke mulighet til å se hva som kommer først i setningen og hva som kommer midt i, men vi vet at noen ord og typer tegnsetting stort sett forekommer i starten eller slutten av en setning.

Skriv en funksjon padding(liste,tall) som tar inn ei liste og et tall, returnerer ei ny liste med tegnet "$" som padding på hver side av setningen.

Padding av "Jeg liker å høste poteter ." blir derfor:

['$', 'Jeg', 'liker', 'å', 'høste', 'poteter', '.', '$']

Oppgave 3

Kombiner funksjonene fra oppgave 1 og oppgave 2 i en ny funksjon, som tar inn en setning, n-gram-tallet, og antall elementer i padding: n_pad(setning,2,1) vil gi bigrammer (2) med én "$" på hver side (1). Test på teksten under. Teksten er tokenisert, men du må dele den opp. Hver setning skal behandles for seg. Skriv til slutt ut trigrammene til alle setningene i teksten med dobbel padding.

tekst = """En lang kamp for å heve statusen til kvensk språk har fått seg et lite løft .
Regjeringen har omsider starta et arbeid for å finne ut hva som må til for å løfte språket til nivå III i det europeiske språkcharteret .
Men sentrale myndigheter har vært skeptiske . Da kvensk blei anerkjent som eget språk i 2005 blei det vurdert .
Konklusjonen var da at man ikke ville være i stand til å oppfylle forpliktelsene det medfører ."""

Oppgave 4: Grubleoppgave

N-grammer brukes, som nevnt ovenfor, blant annet til å modellere sammenhengen mellom ord. Vi kan for eksempel få med sammenhengen mellom pronomen som kommer foran verb, og adjektiver foran substantiver, og mye mer, med bigrammer. Med trigrammer kan vi få med ting som artikler i lengre nomenfraser, så man kan lære at determinativ + adjektiv + substantiv er en vanlig sammensetning. Allikevel byr dette på problemer. En setning med 8 ord har 8 unigrammer uten padding. Hvor mange bigrammer har den? Hvor mange trigrammer?

Bruk n-gram-funksjonen uten padding til å telle ut hvor mange n-grammer det blir i spennet fra n=1 til n=10 i setninger som er 10 ord lange, inkludert tegnsetting. Skriv resultatene "pent" til terminalen. Hva ser du? Tror du det er lett for en statistisk basert modell å lære sammenhengen i lengre n-grammer?

Spørsmålet lar seg besvare utifra testen over, men hvis du vil ha en mer praktisk sjekk, så kan du ta en lengre tekst, og telle de mest frekvente n-grammene. Hva ser du der?

Vis løsningsforslag

Løsningsforslag

Oppgave 1

def ngram(liste,n):
    newlist = []
    for i in range(len(liste) - (n - 1)):
        newlist.append(tuple(liste[i:i+n]))
     return newlist

Eksempel på kjøring

setning = ['Jeg', 'liker', 'å', 'høste', 'poteter', '.']

print(ngram(setning,1))
print(ngram(setning,2))
print(ngram(setning,3))
print(ngram(setning,7))

>>>[('Jeg',), ('liker',), ('å',), ('høste',), ('poteter',), ('.',)]
>>>[('Jeg', 'liker'), ('liker', 'å'), ('å', 'høste'), ('høste', 'poteter'), ('poteter', '.')]
>>>[('Jeg', 'liker', 'å'), ('liker', 'å', 'høste'), ('å', 'høste', 'poteter'), ('høste', 'poteter', '.')]
>>>[]

Oppgave 2

def padding(liste,n):
    listekopi = liste[:] #for å slippe å endre den opprinnelige lista
    for i in range(n):
        listekopi.insert(0,"$")
        listekopi.append("$")
    return listekopi

Eksempel på kjøring:

setning = ['Jeg', 'liker', 'å', 'høste', 'poteter', '.']

print("Padding",padding(setning,1))
print("Padding",padding(setning,2))

Padding ['$', 'Jeg', 'liker', 'å', 'høste', 'poteter', '.', '$']
Padding ['$', '$', 'Jeg', 'liker', 'å', 'høste', 'poteter', '.', '$', '$']

Oppgave 3

def n_pad(setning,n,pad_n):
    nysent = padding(setning,pad_n)
    return ngram(nysent,n)

Eksempel på kjøring med teksten:

tekst = """En lang kamp for å heve statusen til kvensk språk har fått seg et lite løft .
Regjeringen har omsider starta et arbeid for å finne ut hva som må til for å løfte språket til nivå III i det europeiske språkcharteret .
Men sentrale myndigheter har vært skeptiske . Da kvensk blei anerkjent som eget språk i 2005 blei det vurdert .
Konklusjonen var da at man ikke ville være i stand til å oppfylle forpliktelsene det medfører ."""

setninger = tekst.split("\n")

for setning in setninger:
    setning = setning.split(" ")
    print(n_pad(setning,3,2))

Utskrift:

Ekstra linjeskift er satt inn mellom hver setning for å øke lesbarheten.

[('$', '$', 'En'), ('$', 'En', 'lang'), ('En', 'lang', 'kamp'), ('lang', 'kamp', 'for'), ('kamp', 'for', 'å'), ('for', 'å', 'heve'), ('å', 'heve', 'statusen'), ('heve', 'statusen', 'til'), ('statusen', 'til', 'kvensk'), ('til', 'kvensk', 'språk'), ('kvensk', 'språk', 'har'), ('språk', 'har', 'fått'), ('har', 'fått', 'seg'), ('fått', 'seg', 'et'), ('seg', 'et', 'lite'), ('et', 'lite', 'løft'), ('lite', 'løft', '.'), ('løft', '.', '$'), ('.', '$', '$')]

[('$', '$', 'Regjeringen'), ('$', 'Regjeringen', 'har'), ('Regjeringen', 'har', 'omsider'), ('har', 'omsider', 'starta'), ('omsider', 'starta', 'et'), ('starta', 'et', 'arbeid'), ('et', 'arbeid', 'for'), ('arbeid', 'for', 'å'), ('for', 'å', 'finne'), ('å', 'finne', 'ut'), ('finne', 'ut', 'hva'), ('ut', 'hva', 'som'), ('hva', 'som', 'må'), ('som', 'må', 'til'), ('må', 'til', 'for'), ('til', 'for', 'å'), ('for', 'å', 'løfte'), ('å', 'løfte', 'språket'), ('løfte', 'språket', 'til'), ('språket', 'til', 'nivå'), ('til', 'nivå', 'III'), ('nivå', 'III', 'i'), ('III', 'i', 'det'), ('i', 'det', 'europeiske'), ('det', 'europeiske', 'språkcharteret'), ('europeiske', 'språkcharteret', '.'), ('språkcharteret', '.', '$'), ('.', '$', '$')]

[('$', '$', 'Men'), ('$', 'Men', 'sentrale'), ('Men', 'sentrale', 'myndigheter'), ('sentrale', 'myndigheter', 'har'), ('myndigheter', 'har', 'vært'), ('har', 'vært', 'skeptiske'), ('vært', 'skeptiske', '.'), ('skeptiske', '.', 'Da'), ('.', 'Da', 'kvensk'), ('Da', 'kvensk', 'blei'), ('kvensk', 'blei', 'anerkjent'), ('blei', 'anerkjent', 'som'), ('anerkjent', 'som', 'eget'), ('som', 'eget', 'språk'), ('eget', 'språk', 'i'), ('språk', 'i', '2005'), ('i', '2005', 'blei'), ('2005', 'blei', 'det'), ('blei', 'det', 'vurdert'), ('det', 'vurdert', '.'), ('vurdert', '.', '$'), ('.', '$', '$')]

[('$', '$', 'Konklusjonen'), ('$', 'Konklusjonen', 'var'), ('Konklusjonen', 'var', 'da'), ('var', 'da', 'at'), ('da', 'at', 'man'), ('at', 'man', 'ikke'), ('man', 'ikke', 'ville'), ('ikke', 'ville', 'være'), ('ville', 'være', 'i'), ('være', 'i', 'stand'), ('i', 'stand', 'til'), ('stand', 'til', 'å'), ('til', 'å', 'oppfylle'), ('å', 'oppfylle', 'forpliktelsene'), ('oppfylle', 'forpliktelsene', 'det'), ('forpliktelsene', 'det', 'medfører'), ('det', 'medfører', '.'), ('medfører', '.', '$'), ('.', '$', '$')]

Oppgave 4

setning = "Denne lange setningen har hele ti ord i seg .".split(" ")

for i in range(1,11):
    print("Antall {}-grammer i setningen: {}".format(i,len(ngram(setning,i))))

Utskrift:

Antall 1-grammer i setningen: 10
Antall 2-grammer i setningen: 9
Antall 3-grammer i setningen: 8
Antall 4-grammer i setningen: 7
Antall 5-grammer i setningen: 6
Antall 6-grammer i setningen: 5
Antall 7-grammer i setningen: 4
Antall 8-grammer i setningen: 3
Antall 9-grammer i setningen: 2
Antall 10-grammer i setningen: 1

Man kan se at antallet mulige n-grammer synker etter hvert som n øker. I tillegg til at det er færre mulige tilfeller, vil man også kunne se at antallet like n-grammer synker drastisk for høyere tall. I en større tekstsamling kan vi finne ganske mange like bigrammer, men det er færre trigrammer som er like, og enda færre med høyere n. Det gjør at en eventuell statistisk modell ikke vil ha nok data til å klare å generalisere for veldig høye n-verdier.