KWT-2024/lab/lab_04-05.ipynb

271 KiB

Logo 1

Komputerowe wspomaganie tłumaczenia

4,5. Klasyfikacja tematyczna (terminologii ciąg dalszy) [laboratoria]

Rafał Jaworski (2021)

Logo 2

Komputerowe wspomaganie tłumaczenia

Zajęcia 4 i 5 - klasyfikacja tematyczna (terminologii ciąg dalszy)

Na poprzednich zajęciach opracowaliśmy nasz własny ekstraktor terminologii. Mówiliśmy również, jak ważna jest ekstrakcja terminów specjalistycznych. Dziś zajmiemy się zagadnieniem, w jaki sposób wyciągnąć z tekstu terminy, które naprawdę są specjalistyczne.

Dlaczego nasze dotychczasowe rozwiązanie mogło nie spełniać tego warunku? Wykonajmy następujące ćwiczenie:

Ćwiczenie 1: Zgromadź korpus w języku angielskim składający się z co najmniej 100 dokumentów, z których każdy zawiera co najmniej 100 zdań. Wykorzystaj stronę https://opus.nlpl.eu/. Dobrze, aby dokumenty pochodziły z różnych dziedzin (np. prawo Unii Europejskiej, manuale programistyczne, medycyna). Ściągnięty korpus zapisz na swoim dysku lokalnym, nie załączaj go do niniejszego notatnika.

Taki korpus pozwoli nam zaobserwować, co się stanie, jeśli do ekstrakcji terminologii będziemy stosowali wyłącznie kryterium częstościowe. Aby wykonać odpowiedni eksperyment musimy uruchomić ekstraktor z poprzednich zajęć.

Ćwiczenie 2: Uruchom ekstraktor terminologii (wykrywacz rzeczowników) z poprzednich zajęć na każdym dokumencie z osobna. Jako wynik ekstraktora w każdym przypadku wypisz 5 najczęściej występujących rzeczowników. Wyniki działania komendy umieść w notatniku.

corpus = []

def extrctCorpus():
    for file in ['local_data/example3/ELRA-W0301.en-pl.en','local_data/example2/ELRC-403-Rights_Arrested.en-pl.en','local_data/example1/ELRC-648-Letter_rights_person.en-pl.en']:
        with open(file, 'r') as f:
            # Read all lines into a list
            # lines = f.readlines()
            lines = f.read()
            print(lines[:10])
            corpus.append(lines)
            # lines = f.read()

extrctCorpus()
            
You have b
Your conse
B. ASSISTA
import spacy

def get_nouns(text):
    nlp = spacy.load("en_core_web_sm")
    doc = nlp(text)
    nouns = [token.lemma_ for token in doc if token.pos_ == "NOUN"]
    return set(nouns)

def getElementsNumbers(dictionary, text):
    termValues = dict()
    lowerText = text.lower()
    nlp = spacy.load("en_core_web_sm")

    splitText = nlp(lowerText)
    for findingWord in dictionary:
         elementNumber = 0

         for word in splitText:
             if word.lemma_ == findingWord:
                elementNumber = elementNumber +1
         
         if elementNumber != 0:
             termValues[findingWord] = elementNumber
   
    return termValues

def extract_terms(text):
    return getElementsNumbers(get_nouns(text), text)

for element in corpus:
    sorted_items = sorted(extract_terms(element).items(), key=lambda x: x[1], reverse=True)
    print(sorted_items[:5])

# for file in ['local_data/example3/ELRA-W0301.en-pl.en','local_data/example2/ELRC-403-Rights_Arrested.en-pl.en','local_data/example1/ELRC-648-Letter_rights_person.en-pl.en']:
#     with open(file, 'r') as f:
#         # Read all lines into a list
#         # lines = f.readlines()
#         lines = f.read()
#         sorted_items = sorted(extract_terms(lines).items(), key=lambda x: x[1], reverse=True)
#         print(sorted_items[:5])
        
            
[('arrest', 6), ('right', 6), ('lawyer', 6), ('police', 5), ('consent', 5)]
[('arrest', 9), ('right', 7), ('lawyer', 6), ('police', 5), ('warrant', 5)]
[('arrest', 25), ('right', 22), ('person', 22), ('police', 14), ('detention', 14)]

Czy wyniki uzyskane w ten sposób to zawsze terminy specjalistyczne? Niestety może zdarzyć się, że w wynikach pojawią się rzeczowniki, które są po prostu częste w języku, a niekoniecznie charakterystyczne dla przetwarzanych przez nas tekstów. Aby wyniki ekstrakcji były lepsze, konieczne jest zastosowanie bardziej wyrafinowanych metod.

Jedną z tych metod jest znana z dyscypliny Information Retrieval technika zwana TF-IDF. Jej nazwa wywodzi się od Term Frequency Inverted Document Frequency. Według tej metody, dla każdego odnalezionego przez nas termu powinniśmy obliczyć czynnik TF-IDF, a następnie wyniki posortować malejąco po wartości tego czynnika.

Jak obliczyć czynnik TF-IDF? Czym jest TF, a czym jest IDF?

Zacznijmy od TF, bo ten czynnik już znamy. Jest to nic innego jak częstość wystąpienia terminu w tekście, który przetwarzamy. Idea TF-IDF skupia się na drugim czynniku - IDF. Słowo _inverted oznacza, że czynnik ten będzie odwrócony, czyli trafi do mianownika. W związku z tym TF-IDF to w istocie: $\frac{TF}{DF}$

Czym zatem jest document frequency? Jest to liczba dokumentów, w których wystąpił dany termin. Dokumenty w tym przypadku są rozumiane jako jednostki, na które podzielony jest korpus, nad którym pracujemy (dokładnie taki, jak korpus z ćwiczenia pierwszego).

Zastanówmy się nad sensem tego czynnika. Pamiętajmy, że naszym zadaniem jest ekstracja terminów z tylko jednego dokumentu na raz. Mamy jednak do dyspozycji wiele innych dokumentów, zawierających wiele innych słów i termów. Wartość TF-IDF jest tym większa, im częściej termin występuje w dokumencie, na którym dokonujemy ekstrakcji. Czynnik ten jednak zmniejsza się, jeśli słowo występuje w wielu różnych dokumentach. Zatem, popularne słowa będą miały wysoki czynnik DF i niski TF-IDF. Natomiast najwyższą wartość TF-IDF będą miały terminy, które są częste w przetwarzanym przez nas dokumencie, ale nie występują nigdzie indziej.

Ćwiczenie 3: Zaimplementuj czynnik TF-IDF i dokonaj ekstrakcji terminologii za jego pomocą, używając korpusu z ćwiczenia nr 1. Czy wyniki różnią się od tych uzyskanych tylko za pomocą TF?

import math
from collections import Counter

def tfidf(term, document, corpus):
    # Oblicz TF (Term Frequency) dla danego termu w dokumencie
    term_freq = document.count(term) / len(document)
    
    # Oblicz IDF (Inverse Document Frequency) dla danego termu w korpusie
    doc_freq = sum(1 for doc in corpus if term in doc)
    idf = math.log(len(corpus) / (1 + doc_freq))
    
    # Oblicz TF-IDF dla danego termu w dokumencie
    return term_freq * idf

def tfidf_extract(corpus):
    # Zbierz wszystkie unikalne termy z korpusu
    all_terms = set(term for doc in corpus for term in doc)
    
    # Oblicz TF-IDF dla każdego termu we wszystkich dokumentach
    tfidf_scores = {term: sum(tfidf(term, doc, corpus) for doc in corpus) for term in all_terms}
    
    # Wybierz top N termów z najwyższymi wartościami TF-IDF
    top_terms = sorted(tfidf_scores.items(), key=lambda x: x[1], reverse=True)[:5]
    
    return [term for term, score in top_terms]




# def extract_terminology(corpus, top_n=10):
    

#trzeba to zmienić wczytywanie
terminology = tfidf_extract([cor.split() for cor in corpus ])

print("Ekstrahowana terminologia:")
print(terminology)
Ekstrahowana terminologia:
['•', 'person', 'are', 'In', 'detained']

Teraz potrafimy już w lepszy sposób wyciągać terminy z dokumentów. Spróbujmy jeszcze czegoś widowiskowego - wygenerujmy tzw. chmurę słów z tekstu przy użyciu biblioteki WordCloud dla artykułu z BBC News (https://www.bbc.com/news/world-europe-56530714):

sudo pip install wordcloud

from wordcloud import WordCloud
text = """"This is where it happened," says Felipe Luis Codesal, opening the gate to a three-hectare field on his farm in Zamora, north-west Spain.

One night last November, a pack of wolves got through the fence surrounding the field and attacked Mr Codesal's sheep, many of which were pregnant. When he arrived the next morning, he found 11 animals had been killed. Over the following days, he says, another 36 sheep died from injuries sustained in that attack and miscarriages it triggered.

Mr Codesal fears that such attacks will become even more commonplace if a proposed change to laws protecting the Iberian wolf comes into force.

The leftist coalition government plans to prevent the Iberian wolf from being hunted anywhere by categorising it as an endangered species. The reform is yet to be implemented and could see changes.

Iberian wolves from the Iberian Wolf Centre in Robledo de Sanabria on February 21, 2020 in Zamora, Spain
image captionSpain has Europe's biggest wolf population: These Iberian wolves are kept at Zamora's Iberian wolf centre
"It's like in a nightclub when there's a fire," says Mr Codesal of the wolf attack. "There's a stampede and people get trodden on and hurt. This is the same."

He was not entitled to any compensation and estimates that the financial losses he suffered from this incident totalled around €12-14,000

"It's not even about the money," he says. "It's emotional, because the animals are part of my family."

A 'historic' change?
The region of Castilla y León is the habitat for most of Spain's wolves. Figures gathered by the local government showed that they killed 3,774 sheep and cows in the region in 2019.

Felipe Luis Codesal's farm is just north of the Duero river, which marks a natural border between north-west Spain and the rest of the country. Until now, it has been legal to hunt wolves north of the Duero, under a strict quota system, because that is where they are most prevalent.

South of the river they have been protected.

Conservationist groups have welcomed the government plan. When it was unveiled in February, the Ecologistas en Acción organisation hailed it as a "historic day".

But Mr Codesal, who is a member of the UPA association of smallholder farmers, warns the reform will ruin livestock owners by allowing the wolf population to spiral out of control and roam uncontrolled. The UPA is unconvinced by measures included in the plan to subsidise the installation of fences and the use of guard dogs in livestock farming areas.

Biggest wolf numbers in Europe
The Iberian wolf was close to being wiped out in the middle of the 20th Century. But it enjoyed a resurgence on the back of new hunting regulations introduced in the 1970s and the migration of Spaniards away from rural areas also encouraged its spread down from the north-western corner of the country.

In recent years, wolves have moved into areas such as the Guadarrama mountains north of Madrid and near the city of Ávila, to the west of the capital.

There are now some 2,500 Iberian wolves: around 2,000 are in Spain - the largest wolf population in western Europe - and the rest in Portugal.
"""

wordcloud = WordCloud(background_color="white", max_words=5000, contour_width=3, contour_color='steelblue')
wordcloud.generate(text)
wordcloud.to_image()

Ćwiczenie 4: Wykonaj chmurę słów dla całego korpusu z ćwiczenia nr 1.

def my_word_cloud():
    wordcloud = WordCloud(background_color="white", max_words=5000, contour_width=3, contour_color='steelblue')
    wordcloud.generate(' '.join(corpus))
    return wordcloud

my_word_cloud().to_image()

Zastanówmy się nad jeszcze jednym zagadnieniem - jak pogrupować te terminy ze względu na dziedzinę? Zagadnienie to nosi nazwę klasyfikacji tematycznej. A dzięki pewnemu XIX-wiecznemu niemieckiemu matematykowi możliwe jest przeprowadzenie tego procesu automatycznie. Matematyk ten nosił nazwisko Peter Gustav Lejeune Dirichlet, a metoda klasyfikacji nazywa się LDA (Latent Dirichlet Allocation).

Ćwiczenie 5: Wykonaj tutorial dostępny pod https://towardsdatascience.com/end-to-end-topic-modeling-in-python-latent-dirichlet-allocation-lda-35ce4ed6b3e0. Wklej do notatnika wyniki.