KWT-2024/lab/lab_02.ipynb

486 lines
15 KiB
Plaintext

{
"cells": [
{
"cell_type": "markdown",
"id": "aggregate-listing",
"metadata": {},
"source": [
"Wiemy już, do czego służy pamięć tłumaczeń. Spróbujmy przeprowadzić mały research, którego celem będzie odkrycie, w jaki sposób do pamięci tłumaczeń podchodzą najwięksi producenci oprogramowania typu CAT.\n"
]
},
{
"cell_type": "markdown",
"id": "golden-turkish",
"metadata": {},
"source": [
"### Ćwiczenie 1: Wykonaj analizę funkcjonalności pamięci tłumaczeń w programach SDL Trados Studio 2021 oraz Kilgray memoQ. Dla obu programów wypisz funkcje, które są związane z TM oraz zaznacz, które funkcje są wspólne dla obu programów oraz których funkcji Tradosa brakuje w memoQ oraz odwrotnie."
]
},
{
"cell_type": "markdown",
"id": "retired-burke",
"metadata": {},
"source": [
"Odpowiedź:"
]
},
{
"cell_type": "markdown",
"id": "existing-approval",
"metadata": {},
"source": [
"Jedną z funkcji dostępnych we wszystkich większych programach do wspomagania tłumaczenia jest znajdowanie bardzo pewnych dopasowań w pamięci tłumaczeń. Są one zwane **ICE** (In-Context Exact match) lub 101% match. Są to takie dopasowania z pamięci tłumaczeń, dla których nie tylko zdanie źródłowe z TM jest identyczne z tłumaczonym, ale także poprzednie zdanie źródłowe z TM zgadza się z poprzednim zdaniem tłumaczonym oraz następne z TM z następnym tłumaczonym."
]
},
{
"cell_type": "markdown",
"id": "decimal-electricity",
"metadata": {},
"source": [
" Rozważmy przykładową pamięć tłumaczeń z poprzednich zajęć (można do niej dorzucić kilka przykładów):"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "confident-prison",
"metadata": {},
"outputs": [],
"source": [
"translation_memory = [\n",
" ('Wciśnij przycisk Enter', 'Press the ENTER button'), \n",
" ('Sprawdź ustawienia sieciowe', 'Check the network settings'),\n",
" ('Drukarka jest wyłączona', 'The printer is switched off'),\n",
" ('Wymagane ponowne uruchomienie komputera', 'System restart required')\n",
" ]"
]
},
{
"cell_type": "markdown",
"id": "informal-breakdown",
"metadata": {},
"source": [
"### Ćwiczenie 2: Zaimplementuj funkcję ice_lookup, przyjmującą trzy parametry: aktualnie tłumaczone zdanie, poprzednio tłumaczone zdanie, następne zdanie do tłumaczenia. Funkcja powinna zwracać dopasowania typu ICE. Nie pozwól, aby doszło do błędów podczas sprawdzania pierwszego i ostatniego przykładu w pamięci (ze względu na brak odpowiednio poprzedzającego oraz następującego przykładu)."
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "continental-submission",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"['Wciśnij przycisk Enter']"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def tm_lookup(sentence):\n",
" return [entry[1] for entry in translation_memory if entry[0].lower() == sentence.lower()]\n",
"\n",
"def ice_lookup(sentence, prev_sentence, next_sentence):\n",
" if (not prev_sentence) or (not next_sentence):\n",
" return 'no context'\n",
" \n",
" if not sentence:\n",
" return 'enter your sentence'\n",
" \n",
" #Dobrze prawie ale tutaj zwracane są listy. wszystko okey, gdy zdanie poprzedzające i następne mają tamą ilość słów. JEST zdecydowanie błędny gdy zdania mają różną ilość słów!\n",
" if tm_lookup(prev_sentence) and tm_lookup(next_sentence):\n",
" return [entry[0] for entry in translation_memory if entry[0].lower() == sentence.lower()]\n",
" else:\n",
" return \"\"\n",
" \n",
"ice_lookup('Wciśnij przycisk Enter','Sprawdź ustawienia sieciowe','Drukarka jest wyłączona')"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "ecb19925-7467-4e8a-bfdf-9adee52a5894",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'no context'"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"ice_lookup('Wciśnij przycisk Enter','Sprawdź ustawienia sieciowe','')"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "cf60a398-ae06-4ca8-b658-e011632cdb33",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'enter your sentence'"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"ice_lookup('','Sprawdź ustawienia sieciowe','Drukarka jest wyłączona')"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "d34415a4-d853-435e-b093-fabc4629ff26",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'no context'"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"ice_lookup('Wciśnij przycisk Enter','','Drukarka jest wyłączona')"
]
},
{
"cell_type": "markdown",
"id": "figured-server",
"metadata": {},
"source": [
"Inną powszechnie stosowaną techniką przeszukiwania pamięci tłumaczeń jest tzw. **fuzzy matching**. Technika ta polega na wyszukiwaniu zdań z pamięci, które są tylko podobne do zdania tłumaczonego. Na poprzednich zajęciach wykonywaliśmy funkcję tm_lookup, która pozwalała na różnicę jednego słowa."
]
},
{
"cell_type": "markdown",
"id": "beautiful-fancy",
"metadata": {},
"source": [
"Zazwyczaj jednak funkcje fuzzy match posiadają znacznie szersze możliwości. Ich działanie opiera się na zdefiniowaniu funkcji $d$ dystansu pomiędzy zdaniami $x$ i $y$. Matematycznie, funkcja dystansu posiada następujące właściwości:\n",
"1. $\\forall_{x,y} d(x,y)\\geqslant 0$\n",
"2. $\\forall_{x,y} d(x,y)=0 \\Leftrightarrow x=y$\n",
"3. $\\forall_{x,y} d(x,y)=d(y,x)$\n",
"4. $\\forall_{x,y,z} d(x,y) + d(y,z)\\geqslant d(x,z)$"
]
},
{
"cell_type": "markdown",
"id": "square-usage",
"metadata": {},
"source": [
"Rozważmy następującą funkcję:"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "fourth-pillow",
"metadata": {},
"outputs": [],
"source": [
"def sentence_distance(x,y):\n",
" return abs(len(y) - len(x))"
]
},
{
"cell_type": "markdown",
"id": "mediterranean-cosmetic",
"metadata": {},
"source": [
"### Ćwiczenie 3: Czy to jest poprawna funkcja dystansu? Które warunki spełnia?"
]
},
{
"cell_type": "markdown",
"id": "graduate-theorem",
"metadata": {},
"source": [
"### Odpowiedź:\n",
"- 1. **spełnia warunek**: dzięki zastosowaniu funkcji `abs()`\n",
"- 3. **spełnia warunek**: przemienność w tym przypadku również zawdzięczamy funkcj `abs()`\n",
"- 4. **spełnia warunek**:(z uproszczeniem że x i y i z to len(z danej zmiennej) -> |y-x| + |z-y| >= |z-x| =\n",
"- = |y - y - x + z| >= |z-x| = |z-x| >= |z-x|\n",
"\n",
"2 nie jest spełnione, ponieważ x i y muszą być tymi samymi zdaniami aby odległość była równa 0. A wyżej wymieniona funckja spełnia ten warunek dla wszytskich zdań które mają taką samą ilość znaków."
]
},
{
"cell_type": "markdown",
"id": "native-amber",
"metadata": {},
"source": [
"A teraz spójrzmy na taką funkcję:"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "continued-christopher",
"metadata": {},
"outputs": [],
"source": [
"def sentence_distance(x,y):\n",
" if (x == y):\n",
" return 0\n",
" else:\n",
" return 3"
]
},
{
"cell_type": "markdown",
"id": "every-surveillance",
"metadata": {},
"source": [
"### Ćwiczenie 4: Czy to jest poprawna funkcja dystansu? Które warunki spełnia?"
]
},
{
"cell_type": "markdown",
"id": "metallic-leave",
"metadata": {},
"source": [
"### Odpowiedź:\n",
"- 1. **spełnia warunek**, ponieważ zwróci wartość 0 lub 3 które są >= 0\n",
"- 2. **spełnia waurenk**, ponieważ gdy zdanie x jest takie samo jak y = to odległość jest zwracana jako 0\n",
"- 3. **spełnia warunek**, ponieważ sprawdzenia wygląda w taki sposób, że porównujemy czy x == y (co jest tożsame z y == x) w przeciwnym wypadku zawsze zwracamy tą samą wartość\n",
"- 4. **spełnia warunek**, ponieważ gdy xyz są takie same to mamy 0>=0 | gdy wszystkie są różne to mamy 6>=3 | gdy jedna para się różni 6>=0 lub 3>=0"
]
},
{
"cell_type": "markdown",
"id": "executed-baptist",
"metadata": {},
"source": [
"Wprowadźmy jednak inną funkcję dystansu - dystans Levenshteina. Dystans Levenshteina pomiędzy dwoma łańcuchami znaków definiuje się jako minimalną liczbę operacji edycyjnych, które są potrzebne do przekształcenia jednego łańcucha znaków w drugi. Wyróżniamy trzy operacje edycyjne:\n",
"* dodanie znaku\n",
"* usunięcie znaku\n",
"* zamiana znaku na inny"
]
},
{
"cell_type": "markdown",
"id": "square-brown",
"metadata": {},
"source": [
"### Ćwiczenie 5: Czy dystans Levenshteina jest poprawną funkcją dystansu? Uzasadnij krótko swoją odpowiedź sprawdzając każdy z warunków."
]
},
{
"cell_type": "markdown",
"id": "bibliographic-stopping",
"metadata": {},
"source": [
"### Odpowiedź: Jest funckją dystansu\n",
"- 1. **spełnia warunek** Liczba wymaganych operacji edycyjnych nie może być mniejsza niż zero. W przypadku gdy zdania są sobie równe d(x,y) = 0\n",
"- 2. **spełnia warunek** Gdy zdania są sobie równe d(x,y) = 0\n",
"- 3. **spełnia warunek** nie ważne czy zrobimy d(x,y) czy d(y,x) nadal liczba operacji edycyjnych będzie taka sama pa->papa (+2) | papa -> pa (-2)\n",
"- 4. **spełnia warunek**: (z uproszczeniem że x i y i z to liczba wymaganych zmian -> |y?x| + |z?y| >= |z?x| =\n",
"- = x + y >= x"
]
},
{
"cell_type": "markdown",
"id": "attended-channels",
"metadata": {},
"source": [
"W Pythonie dostępna jest biblioteka zawierająca implementację dystansu Levenshteina. Zainstaluj ją w swoim systemie przy użyciu polecenia:\n",
"\n",
"`pip3 install python-Levenshtein`\n",
"\n",
"I wypróbuj:"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "727b188d-eedd-4d19-9cbf-efcce71e145c",
"metadata": {},
"outputs": [
{
"ename": "SyntaxError",
"evalue": "invalid syntax (2143622881.py, line 1)",
"output_type": "error",
"traceback": [
"\u001b[0;36m Cell \u001b[0;32mIn [8], line 1\u001b[0;36m\u001b[0m\n\u001b[0;31m pip3 install python-Levenshtein\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n"
]
}
],
"source": [
"pip3 install python-Levenshtein"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "secondary-wrist",
"metadata": {},
"outputs": [],
"source": [
"from Levenshtein import distance as levenshtein_distance\n",
"\n",
"levenshtein_distance(\"kotek\", \"kotki\")\n"
]
},
{
"cell_type": "markdown",
"id": "concrete-satellite",
"metadata": {},
"source": [
"Funkcja ta daje nam możliwość zdefiniowania podobieństwa pomiędzy zdaniami:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "associate-tuner",
"metadata": {},
"outputs": [],
"source": [
"def levenshtein_similarity(x,y):\n",
" return 1 - levenshtein_distance(x,y) / max(len(x), len(y))"
]
},
{
"cell_type": "markdown",
"id": "built-michael",
"metadata": {},
"source": [
"Przetestujmy ją!"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "focal-pathology",
"metadata": {},
"outputs": [],
"source": [
"levenshtein_similarity('Program jest uruchomiony', 'Program jest uruchamiany')"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "roman-ceiling",
"metadata": {},
"outputs": [],
"source": [
"levenshtein_similarity('Spróbuj wyłączyć i włączyć komputer', 'Spróbuj włączyć i wyłączyć komputer')"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "invisible-cambodia",
"metadata": {},
"outputs": [],
"source": [
"levenshtein_similarity('Spróbuj wyłączyć i włączyć komputer', 'Nie próbuj wyłączać i włączać drukarki')"
]
},
{
"cell_type": "markdown",
"id": "administrative-phoenix",
"metadata": {},
"source": [
"### Ćwiczenie 6: Napisz funkcję fuzzy_lookup, która wyszuka w pamięci tłumaczeń wszystkie zdania, których podobieństwo Levenshteina do zdania wyszukiwanego jest większe lub równe od ustalonego progu."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "genetic-cradle",
"metadata": {},
"outputs": [],
"source": [
"def fuzzy_lookup(sentence, threshold):\n",
" \n",
" answer = []\n",
" \n",
" for entry in translation_memory:\n",
" if levenshtein_similarity(sentence.lower(),entry[0].lower()) >= threshold:\n",
" answer.append(entry[1])\n",
" \n",
" return answer"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "cc0544a4-a515-4515-a116-f13b96e92812",
"metadata": {},
"outputs": [],
"source": [
"#'Wciśnij przycisk Enter'\n",
"fuzzy_lookup('KlikNiJ przycisK EnTeR', 0.86)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e2b8ff91-a103-45a4-a746-8ce3e9470c4c",
"metadata": {},
"outputs": [],
"source": [
"#'Sprawdź ustawienia sieciowe'\n",
"fuzzy_lookup('Sprawdź ustawienia sieci', 0.885)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "df759469-b92e-490c-a672-96bd4c0d76b2",
"metadata": {},
"outputs": [],
"source": []
}
],
"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.9.2"
},
"subtitle": "2. Zaawansowane użycie pamięci tłumaczeń",
"title": "Komputerowe wspomaganie tłumaczenia",
"year": "2021"
},
"nbformat": 4,
"nbformat_minor": 5
}