KWT-2024/lab/lab_11.ipynb
2024-05-25 14:53:24 +02:00

418 lines
21 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Komputerowe wspomaganie tłumaczenia"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Zajęcia 11 - urównoleglanie"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Na poprzednich zajęciach poznaliśmy techniki pozyskiwania tekstu z Internetu. Jeśli uda nam się w ten sposób pozyskać tekst w jednym języku oraz jego tłumaczenie na inny język, jesteśmy tylko o krok od uzyskania najbardziej przydatnego zasobu z punktu widzenia wspomagania tłumaczenia - pamięci tłumaczeń. Krokiem tym jest automatyczne urównoleglanie tekstu."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Automatyczne urównoleglanie tekstu składa się z dwóch kroków:\n",
"1. Podziału tekstu źródłowego oraz docelowego na zdania.\n",
"2. Dopasowaniu zdań źródłowych do docelowych."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Zdania, o których mowa w punkcie 1., powinniśmy rozumieć jako segmenty, tj. niekoniecznie kompletne zdania w sensie gramatycznym. Standardowym sposobem podziału tekstu na segmenty jest dzielenie po znaku nowej linii lub zaraz po kropce, o ile jest ona częścią sekwencji: \".[spacja][Wielka litera]\""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Ćwiczenie 1: Zaimplementuj podstawowy algorytm segmentacji tekstu. Użyj odpowiedniego wyrażenia regularnego, łapiącego wielkie litery w dowolnym języku, np. \"Ż\" (użyj klasy unikodowej). Zwróć listę segmentów."
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"['To ', 'Jest', 'Żywy.przykład', 'Żeby', 'Ładnie ', 'Zademonstrować', 'Segmentację']\n"
]
}
],
"source": [
"import regex\n",
"\n",
"def sentence_split(text):\n",
" pattern = r'(?=\\p{Lu})'\n",
" segments = regex.split(pattern, text)\n",
" \n",
" segments = [segment for segment in segments if segment]\n",
" return segments\n",
" \n",
"text = \"To JestŻywy.przykładŻebyŁadnie ZademonstrowaćSegmentację\"\n",
"segments = sentence_split(text)\n",
"print(segments)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Ćwiczenie 2: Uruchom powyższy algorytm na treści wybranej przez siebie strony internetowej (do ściągnięcia treści strony wykorzystaj kod z laboratoriów nr 7). Zidentyfikuj co najmniej dwa wyjątki od ogólnej reguły podziału na segmenty i ulepsz algorytm."
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"-\n",
"Dużo mówi się o tym, że to pszczoły miodne zagrażają dzikim pszczołom.\n",
"Tak przewrotnie postawione pytanie zmusza do zastanowienia, czy negatywna interakcja w drugą stronę jest możliwa - mówi dr\n",
"Jacek\n",
"Wendzonka.\n",
"I dodaje: -\n",
"Niestety, odpowiedź pozostaje ciągle taka sama.\n",
"Pszczoły, i dzikie i miodne, ewoluowały i współwystępowały razem przez miliony lat.\n",
"Oczywiście konkurowały one o zasoby pokarmowe, co doprowadzało do tworzenia rozmaitych strategii oraz specjalizacji i było jedną z sił napędowych ewolucji.\n",
"Pszczoła miodna (\n",
"Apis mellifera) jako gatunek społeczny, magazynujący zapasy i potrafiący wielokrotnie zimować w gnieździe jako rodzina, jest na szczycie drabiny ewolucyjnej.\n",
"Daje to szereg korzyści takich jak lepsza obrona przed wrogami, korzystanie z zapasów w okresach niedostatków, regulacja temperatury gniazda itp.\n",
"Niestety (dla dalszych rozważań), rodzina taka licząca nawet 30 50 tys. osobników, ma duże zapotrzebowanie energetyczne i wymaga odpowiedniej ilości pokarmu.\n",
"Przekłada się to bezpośrednio na odpowiednią liczbę kwiatów i powierzchnię terenu.\n",
"W praktyce oznacza to, że w środowisku naturalnym gniazda takie nie mogą istnieć w dużym zagęszczeniu i muszą być rozproszone tak, aby uniknąć konkurencji między rodzinami.\n",
"Rozproszenie to nie wpływało negatywnie na kondycję gatunków samotnych.\n",
"Sytuacja zmieniła się wraz z pojawieniem się człowieka i wykorzystywaniem pszczół miodnych.\n",
"Na początku był to zwykły rabunek miodu, z czasem połączony z opieką polegającą na ochronie pszczół przed konkurencją np. niedźwiedziami.\n",
"Kolejnymi etapami było bartnictwo i pszczelarstwo współczesne, które to w przeciągu ostatniego stulecia doprowadziło do diametralnych przetasowań na pszczelej szachownicy zależności ekologicznych.\n",
"Przede wszystkim powstały pasieki, czyli doszło do dużego zagęszczenia rodzin pszczelich na danej jednostce powierzchni.\n",
"Współcześnie, za pasiekę opłacalną, średniej wielkości, uważa się taką, liczącą ok. 20 rodzin.\n",
"To tworzy bardzo duży lokalny nacisk ekologiczny, który bez pomocy pszczelarzy (okresowe dokarmianie cukrem, leczenie itp.) zagrażałby samym pszczołom miodnym.\n",
"A przecież na tej samej powierzchni żyją także liczne gatunki pszczół dzikich, w większości nieprzekraczających kilku milimetrów, a więc \"niewidocznych\" dla przeciętnego człowieka.\n",
"Przy takim zagęszczeniu pszczoły miodnej nie mają one szansy na uczciwą, ekologiczną rywalizację i ich liczebność spada, a nawet giną: bezgłośnie i niewidocznie bezproblemowo!\n",
"Całą sytuację można by porównać do meczu piłkarskiego, gdzie po jednej stronie jest ekipa 11 kumpli z osiedla, a po drugiej drużyna z ekstraklasy z zapleczem finansowym, trenerskim, medycznym i ławką rezerwowych na 2 równorzędne drużyny.\n",
"Każdy od razu powie, że to nie pieniądze grają i że wszystko jest możliwe.\n",
"Faktycznie, raz na jakiś czas romantyczny heroizm jest górą.\n",
"Jednakże w przyrodzie, gdzie stawką jest życie nie tyle osobników, ale całych gatunków, na częstotliwości takich wyczynów nie można polegać.\n",
"Wynik rywalizacji jest przesądzony.\n",
"Jeżeli mamy poważnie podchodzić do ochrony dzikich zapylaczy, to uregulowanie kwestii kontroli zagęszczenia uli (napszczelenia) staje się zadaniem najważniejszym, także na poziomie legislacyjnym.\n",
"W świadomości społecznej pszczoła miodna jest uznawana za najważniejszego, wręcz jedynego zapylacza całkowicie wystarczającego do zapylania wszystkiego, co nie jest prawdą.\n",
"Najważniejsze, o czym musimy pamiętać, to to, że jest to tylko pojedynczy gatunek i nie jest nieśmiertelny.\n",
"Dalsze osłabianie poprzez hodowlę czy wybuch globalnej pandemii nowej nieznanej choroby (skąd to znamy?), może doprowadzić do wyginięcia gatunku.\n",
"I co wtedy?\n",
"Miodu nie będzie, to fakt, ale dzikie pszczoły poradzą sobie z zapylaniem.\n",
"Trzeba \"tylko\" dopilnować, żeby w dobrej kondycji dotrwały do tego momentu.\n",
"Zapylanie przez pszczoły jest procesem naturalnym, darmowym.\n",
"Człowiek jak za coś nie zapłaci, to nie zawsze potrafi to docenić czy uszanować.\n",
"Właśnie w tym aspekcie musi się dokonać największa zmiana w ludzkiej mentalności, czego wszystkim pszczołom w ich dniu życzę - dodaje naukowiec z\n",
"U\n",
"A\n",
"M.\n",
"Fot.\n",
"Adrian\n",
"Wykrota\n"
]
}
],
"source": [
"import requests\n",
"from bs4 import BeautifulSoup\n",
"import regex\n",
"\n",
"url = 'https://amu.edu.pl/dla-mediow/komunikaty-prasowe/czy-dzikie-pszczoly-zagrazaja-pszczolom-miodnym'\n",
"\n",
"def sentence_split(text):\n",
" pattern = r'(?=\\p{Lu})'\n",
" segments = regex.split(pattern, text)\n",
" segments = [segment.strip() for segment in segments if segment.strip()]\n",
" return segments\n",
"\n",
"page = requests.get(url)\n",
"soup = BeautifulSoup(page.content, 'html.parser')\n",
"\n",
"article_content = soup.find('div', {'class': 'news__body'}).get_text()\n",
"\n",
"segments = sentence_split(article_content)\n",
"\n",
"for i, segment in enumerate(segments, 1):\n",
" print(segment)"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Dużo mówi się o tym, że to pszczoły miodne zagrażają dzikim pszczołom.\n",
"Tak przewrotnie postawione pytanie zmusza do zastanowienia, czy negatywna interakcja w drugą stronę jest możliwa - mówi dr Jacek Wendzonka.\n",
"I dodaje: - Niestety, odpowiedź pozostaje ciągle taka sama.\n",
"Pszczoły, i dzikie i miodne, ewoluowały i współwystępowały razem przez miliony lat.\n",
"Oczywiście konkurowały one o zasoby pokarmowe, co doprowadzało do tworzenia rozmaitych strategii oraz specjalizacji i było jedną z sił napędowych ewolucji.\n",
"Pszczoła miodna (Apis mellifera) jako gatunek społeczny, magazynujący zapasy i potrafiący wielokrotnie zimować w gnieździe jako rodzina, jest na szczycie drabiny ewolucyjnej.\n",
"Daje to szereg korzyści takich jak lepsza obrona przed wrogami, korzystanie z zapasów w okresach niedostatków, regulacja temperatury gniazda itp.\n",
"Niestety (dla dalszych rozważań), rodzina taka licząca nawet 30 50 tys. osobników, ma duże zapotrzebowanie energetyczne i wymaga odpowiedniej ilości pokarmu.\n",
"Przekłada się to bezpośrednio na odpowiednią liczbę kwiatów i powierzchnię terenu.\n",
"W praktyce oznacza to, że w środowisku naturalnym gniazda takie nie mogą istnieć w dużym zagęszczeniu i muszą być rozproszone tak, aby uniknąć konkurencji między rodzinami.\n",
"Rozproszenie to nie wpływało negatywnie na kondycję gatunków samotnych.\n",
"Sytuacja zmieniła się wraz z pojawieniem się człowieka i wykorzystywaniem pszczół miodnych.\n",
"Na początku był to zwykły rabunek miodu, z czasem połączony z opieką polegającą na ochronie pszczół przed konkurencją np. niedźwiedziami.\n",
"Kolejnymi etapami było bartnictwo i pszczelarstwo współczesne, które to w przeciągu ostatniego stulecia doprowadziło do diametralnych przetasowań na pszczelej szachownicy zależności ekologicznych.\n",
"Przede wszystkim powstały pasieki, czyli doszło do dużego zagęszczenia rodzin pszczelich na danej jednostce powierzchni.\n",
"Współcześnie, za pasiekę opłacalną, średniej wielkości, uważa się taką, liczącą ok. 20 rodzin.\n",
"To tworzy bardzo duży lokalny nacisk ekologiczny, który bez pomocy pszczelarzy (okresowe dokarmianie cukrem, leczenie itp.) zagrażałby samym pszczołom miodnym.\n",
"A przecież na tej samej powierzchni żyją także liczne gatunki pszczół dzikich, w większości nieprzekraczających kilku milimetrów, a więc \"niewidocznych\" dla przeciętnego człowieka.\n",
"Przy takim zagęszczeniu pszczoły miodnej nie mają one szansy na uczciwą, ekologiczną rywalizację i ich liczebność spada, a nawet giną: bezgłośnie i niewidocznie bezproblemowo! Całą sytuację można by porównać do meczu piłkarskiego, gdzie po jednej stronie jest ekipa 11 kumpli z osiedla, a po drugiej drużyna z ekstraklasy z zapleczem finansowym, trenerskim, medycznym i ławką rezerwowych na 2 równorzędne drużyny.\n",
"Każdy od razu powie, że to nie pieniądze grają i że wszystko jest możliwe.\n",
"Faktycznie, raz na jakiś czas romantyczny heroizm jest górą.\n",
"Jednakże w przyrodzie, gdzie stawką jest życie nie tyle osobników, ale całych gatunków, na częstotliwości takich wyczynów nie można polegać.\n",
"Wynik rywalizacji jest przesądzony.\n",
"Jeżeli mamy poważnie podchodzić do ochrony dzikich zapylaczy, to uregulowanie kwestii kontroli zagęszczenia uli (napszczelenia) staje się zadaniem najważniejszym, także na poziomie legislacyjnym.\n",
"W świadomości społecznej pszczoła miodna jest uznawana za najważniejszego, wręcz jedynego zapylacza całkowicie wystarczającego do zapylania wszystkiego, co nie jest prawdą.\n",
"Najważniejsze, o czym musimy pamiętać, to to, że jest to tylko pojedynczy gatunek i nie jest nieśmiertelny.\n",
"Dalsze osłabianie poprzez hodowlę czy wybuch globalnej pandemii nowej nieznanej choroby (skąd to znamy?), może doprowadzić do wyginięcia gatunku.\n",
"I co wtedy? Miodu nie będzie, to fakt, ale dzikie pszczoły poradzą sobie z zapylaniem.\n",
"Trzeba \"tylko\" dopilnować, żeby w dobrej kondycji dotrwały do tego momentu.\n",
"Zapylanie przez pszczoły jest procesem naturalnym, darmowym.\n",
"Człowiek jak za coś nie zapłaci, to nie zawsze potrafi to docenić czy uszanować.\n",
"Właśnie w tym aspekcie musi się dokonać największa zmiana w ludzkiej mentalności, czego wszystkim pszczołom w ich dniu życzę - dodaje naukowiec z UAM.\n",
"Fot.\n"
]
}
],
"source": [
"def sentence_split_enhanced(text):\n",
" pattern = r'(?<!\\w)(\\p{Lu}.*?\\.)(?=\\s*\\p{Lu}|\\s*$)'\n",
" segments = regex.findall(pattern, text, regex.DOTALL)\n",
" segments = [segment.strip() for segment in segments if segment.strip()]\n",
" return segments\n",
"\n",
"\n",
"article_content = soup.find('div', {'class': 'news__body'}).get_text()\n",
"segments = sentence_split_enhanced(article_content)\n",
"\n",
"for i, segment in enumerate(segments, 1):\n",
" print(segment)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Po podziale tekstu na segmenty po stronie źródłowej oraz docelowej, możemy przystąpić do kroku drugiego - dopasowania segmentów. Głównym wyzwaniem tego kroku jest fakt, iż po stronie źródłowej może być inna liczba segmentów, niż po stronie docelowej. Takie rozbieżności są bardzo częste, a wynikają między innymi z:\n",
"* tłumaczenia jednego zdania źródłowego przy użyciu więcej niż jednego zdania\n",
"* tłumaczenia więcej niż jednego zdania źródłowego przy użyciu jednego zdania\n",
"* pominięcia zdania podczas tłumaczenia\n",
"* rozbieżności pomiędzy wersjami tekstu źródłowego i docelowego (np. tekst źródłowy mógł być modyfikowany po przetłumaczeniu i tłumaczenie nie zostało zaktualizowane)\n",
"* przetłumaczenia tekstu źródłowego tylko częściowo"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Problemy te rozwiązwyane są na różne sposoby. Najpopularniejszym programem do przeprowadzania urównoleglania jest [Hunalign](https://github.com/danielvarga/hunalign). Wejściem do programu są dwa pliki, zawierające po jednym segmencie w linii. Wyjściem - plik urównoleglony w wewnętrznym formacie hunaligna."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Ćwiczenie 3: Odnajdź dowolną stronę, która jest dostępna w wielu językach. Pobierz z tej strony tekst oryginalny (tylko ze strony głównej) oraz przetłumaczony na dowolny inny język. Przy użyciu Pythona przygotuj pliki dla Hunaligna i uruchom go."
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"import requests\n",
"from bs4 import BeautifulSoup\n",
"\n",
"def fetch_and_save_text(url, filename):\n",
" response = requests.get(url)\n",
" response.raise_for_status()\n",
" \n",
" soup = BeautifulSoup(response.content, 'html.parser')\n",
" text = soup.get_text()\n",
" \n",
" with open(filename, 'w', encoding='utf-8') as file:\n",
" file.write(text)\n",
"\n",
"def create_hunalign_file(file1, file2, output):\n",
" with open(file1, 'r', encoding='utf-8') as f1, open(file2, 'r', encoding='utf-8') as f2:\n",
" text1 = f1.read().strip().split('\\n')\n",
" text2 = f2.read().strip().split('\\n')\n",
" \n",
" with open(output, 'w', encoding='utf-8') as out:\n",
" for line1, line2 in zip(text1, text2):\n",
" out.write(f\"{line1}\\n{line2}\\n\")\n",
"\n",
"fetch_and_save_text('https://wolften.pl/pl/', 'wolften_pl.txt')\n",
"fetch_and_save_text('https://wolften.pl/cs/', 'wolften_cs.txt')\n",
"\n",
"create_hunalign_file('wolften_pl.txt', 'wolften_cs.txt', 'hunalign_format')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Wyjściem z Hunaligna jest plik w specjalnym formacie Hunaligna. Problem jednak w tym, że niestety nie można go w prosty sposób zaimportować do jakiegokolwiek narzędzia typu CAT. Potrzebna jest konwersja do któregoś z bardziej popularnych formatów, np. XLIFF."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"XLIFF jest formatem do przechowywania pamięci tłumaczeń, który opiera się na XML-u. Przykładowy plik XLIFF wygląda następująco:"
]
},
{
"cell_type": "raw",
"metadata": {},
"source": [
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",
"<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" version=\"1.2\">\n",
" <file datatype=\"plaintext\" original=\"self\" source-language=\"en\" target-language=\"es\">\n",
" <header>\n",
" <sxmd:metadata xmlns:sxmd=\"urn:x-sap:mlt:xliff12:metadata:1.0\" xmlns=\"urn:x-sap:mlt:tsmetadata:1.0\">\n",
" <object-name>sample</object-name>\n",
" <collection>KWT</collection>\n",
" <domain>KWT</domain>\n",
" <developer>123</developer>\n",
" <description>sample XLIFF file</description>\n",
" </sxmd:metadata>\n",
" </header>\n",
" <body>\n",
" <trans-unit>\n",
" <source>Hello world!</source>\n",
" <target>Hola mundo!</target>\n",
" </trans-unit>\n",
" <trans-unit>\n",
" <source>File</source>\n",
" <target>Archivo</target>\n",
" </trans-unit>\n",
" <trans-unit>\n",
" <source>New</source>\n",
" <target>Nuevo</target>\n",
" </trans-unit>\n",
" <trans-unit>\n",
" <source>Exit</source>\n",
" <target>Salir</target>\n",
" </trans-unit>\n",
" </body>\n",
" </file>\n",
"</xliff>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Ćwiczenie 4: Napisz konwerter formatu hunaligna na XLIFF."
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"import xml.etree.ElementTree as ET\n",
"\n",
"def convert2xliff(hunalign_file, xliff_file):\n",
" xliff = ET.Element('xliff', {\n",
" 'version': '1.2',\n",
" 'xmlns': 'urn:oasis:names:tc:xliff:document:1.2'\n",
" })\n",
" \n",
" file_elem = ET.SubElement(xliff, 'file', {\n",
" 'source-language': 'pl',\n",
" 'target-language': 'cs',\n",
" 'datatype': 'plaintext',\n",
" 'original': hunalign_file\n",
" })\n",
" \n",
" body = ET.SubElement(file_elem, 'body')\n",
" \n",
" with open(hunalign_file, 'r', encoding='utf-8') as f:\n",
" lines = f.readlines()\n",
" \n",
" for i in range(0, len(lines), 2):\n",
" source_text = lines[i].strip()\n",
" target_text = lines[i + 1].strip()\n",
" \n",
" trans_unit = ET.SubElement(body, 'trans-unit', {\n",
" 'id': str(i // 2 + 1)\n",
" })\n",
" \n",
" source = ET.SubElement(trans_unit, 'source')\n",
" source.text = source_text\n",
" \n",
" target = ET.SubElement(trans_unit, 'target')\n",
" target.text = target_text\n",
" \n",
" tree = ET.ElementTree(xliff)\n",
" with open(xliff_file, 'wb') as f:\n",
" tree.write(f, encoding='utf-8', xml_declaration=True)\n",
"\n",
"convert2xliff('hunalign_format', 'xliff_format')"
]
}
],
"metadata": {
"author": "Rafał Jaworski",
"email": "rjawor@amu.edu.pl",
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"lang": "pl",
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.0"
},
"subtitle": "11. Urównoleglanie",
"title": "Komputerowe wspomaganie tłumaczenia",
"year": "2021"
},
"nbformat": 4,
"nbformat_minor": 5
}