Ziua 4 - Chatbots
Descrierea proiectului
În Colab: Chatbot
ELIZA este unul dintre primii chatboți. Dezvoltat în anii 60, Eliza funcționa pe baza unor reguli simple și substituții în discuția cu utilizatorul.
Puteți vorbi cu Eliza aici: https://psych.fullerton.edu/mbirnbaum/psych101/eliza.htm
În acest curs vom încerca să ne facem propriul chatbot psihoterapeut în Python. Vom începe de la un scenariu simplu: Eliza se prezintă, apoi răspunde la fiecare prompt pe care îl scrii cu un text general valabil până când vede cuvântul "bye". Dacă i-ai scris "bye" va răspunde cu "Thank you for talking with me. Good bye!"
Dicționare
Dicționarele reprezintă un set de perechi de chei și valori asociate. Cheile sunt unice în dicționar și trebuie să fie de tip immutable (pot fi stringuri, numere, tupluri etc., dar nu pot fi liste).
Pentru a crea un dicționar vid, folosim:
d = {}
Pentru a adăuga chei noi în dicționar, putem pur și simplu să le atribuinduim o valoare. Sintaxa este: dictionar[cheie] = valoare.
d["a"] = 100
d["b"] = 200
d["c"] = 300
print(d)
Output: {'a': 100, 'b': 200, 'c': 300}
Pentru a itera prin cheile unui dicționar putem folosi operatorul in:
for k in d:
print(k, d[k])
Output:
a 100
b 200
c 300
Pentru a verifica dacă o cheie se găsește într-un dicționar, putem folosi același operator:
print("a" in d)
print(100 in d)
Output:
True
False
sau să folosim metoda items() care returnează o listă cu tupluri de forma (cheie, valoare):
for k, v in d.items():
print(k, v)
Output:
a 100
b 200
c 300
Pentru a obține lista de chei putem folosi metoda keys() iar pentru lista de valori metoda values().
print(d.keys())
Output: dict_keys(['a', 'b', 'c'])
print(d.values())
Output: dict_values([100, 200, 300])
Pentru mai multe funcții pe dicționare: https://docs.python.org/3/tutorial/datastructures.html#dictionaries
my_dict = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
print("My first dictionary: ", my_dict)
my_second_dict = dict(name = "John", age = 36)
print("My second dictionary: ", my_second_dict)
print()
my_second_dict["country"] = "Norway"
print("We can easily add new fields: ", my_second_dict)
my_second_dict["country"] = "Italy"
print("Or modify them: ", my_second_dict)
Output:
My first dictionary: {'brand': 'Ford', 'model': 'Mustang', 'year': 1964}
My second dictionary: {'name': 'John', 'age': 36}
We can easily add new fields: {'name': 'John', 'age': 36, 'country': 'Norway'}
Or modify them: {'name': 'John', 'age': 36, 'country': 'Italy'}
Exercițiu
Scrie un meniu de cumparaturi. Pe ecran se va afisa o lista de produse si se va deschide un input in care utilizatorul va scrie ce produs isi doreste sa cumpere.
Pentru input gresit se va afisa mesaj de eroare.
Pentru input corect se utilizatorul va fi intrebat cate produse isi doreste si va fi acceptat doar input numeric in intervalul 1-100.
Programul se va opri la citirea inputului "exit" si va afisa lista de cumparaturi si pretul total al acestora.
# Rezolvă aici
Preprocesări text
Preprocesări
Cum curățăm un text? Chiar avem nevoie de toate cuvintele și caracterele prezente? Care ar fi o listă de acțiuni pe care le-am putea face asupra unui text ca să păstreze informațiile relevante pentru a le folosi mai departe?
Pași preprocesare:
- lowercase - transformarea literelor în minuscule
- tokenizare - împărțirea textelor în propoziții, cuvinte sau tokens
- punctuatie - eliminare sau înlocuire cu un tag [PUNCT]
- hashtags - eliminare, împărțire în cuvinte sau înlocuire cu un tag [HASHTAG]
- linkuri - eliminare sau înlocuire cu un tag [LINK]
- mentions - eliminare sau înlocuire cu un tag [MENTION]
- emoticoane - eliminare, înlocuire cu ce reprezintă sau înlocuire cu un tag [EMOTICON]
- emojis - eliminare, înlocuire cu ce reprezintă sau înlocuire cu un tag [EMOJI]
- lematizare / stemming - reducerea cuvintelor la cea mai simplă formă a lor
Cheat sheet preprocesări: Introducere în Procesare de Text
Wordnet
Wordnet este o baza de date lexicala a limbii engleze. Cuprinde definitii, exemple, sinonime etc.
import nltk
nltk.download('wordnet')
from nltk.corpus import wordnet as wn
Synset = synonym set = multime de sinonime; contine informatii despre un anumit sens al unui anumit cuvant.
Spre exemplu, cuvantul school are asociate mai multe intelesuri, si deci mai multe synseturi.
synsets = wn.synsets("school")
print(synsets)
Output: [Synset('school.n.01'), Synset('school.n.02'), Synset('school.n.03'), Synset('school.n.04'), Synset('school.n.05'), Synset('school.n.06'), Synset('school.n.07'), Synset('school.v.01'), Synset('educate.v.03'), Synset('school.v.03')]
Definitiile cuvantului school:
[syn.definition() for syn in synsets]
Output:
['an educational institution',
'a building where young people receive education',
'the process of being formally educated at a school',
'a body of creative artists or writers or thinkers linked by a similar style or by similar teachers',
'the period of instruction in a school; the time period when school is in session',
"an educational institution's faculty and students",
'a large group of fish',
'educate in or as if in a school',
'teach or refine to be discriminative in taste or judgment',
'swim in or form a large group of fish']
Relații posibile
-
Substantive:
- hypernyms, hyponyms: Spunem că sensul s_1 este un hiperonim al sensului s_2 dacă s_1 înglobează sensul lui s_2. Hiponimia este opusul relației de hiperonimie (s_2 este un hiponim pentru s_1).
- meronims, holonyms: Spunem că sensul s_1 este un holonim al sensului s_2 daca s_1 îl "conține" pe s_2. Spunem că s_2 este un meronim pentru s_1.
-
Verbe:
- hypernyms, hyponyms: ca mai sus
- entailment: Definește ce acțiuni trebuie să aibă loc pentru ca o anumită acțiune să se întâmple.
-
Adjective:
- antonime, sinonime: În timp ce antonimele se determină la nivel de synset, sinonimele se determină la nivel de lemă.
-
Adverbe:
- antonime
-
Tipuri diferite:
- relatia atributiva (attributes, pentru substantive și adjective): Această relație leagă un synset s_1 al unui substantiv cu un synset s_2 al unui adjectiv dacă "s_2 poate fi o valoare pentru s_1".
- pertainyms (pentru adjective și adverbe): Returnează concepte care se referă la calitățile descrise de adjective/adverbe.
Cheat sheet wordnet: WordNet
Regex
Un RegEx reprezintă o Expresie Regulată (codificarea unei secvențe de caractere). Poate fi folosit pentru a identifica secvențe de caractere într-un șir, pentru a înlocui secvențe sau pentru a separa un șir în funcție de diferite metrici. O secvență de căutare arată așa:
import re
txt = "The rain in Spain stays mainly in the plain"
x = re.search("Spain", txt)
if x:
print("Cuvântul există în șir")
else:
print("Cuvântul nu există în șir")
Output: Cuvântul există în șir
Există o serie de reguli și simboluri pe care le putem folosi pentru a descrie secvența de caractere căutată. O să modificăm exemplul original pentru a ne uita la câteva exemple.
Putem pune . în pozițiile în care poate fi orice caracter, ^ este caracterul început de șir și $ este caracterul pentru final de șir.
print(re.findall("Sp.in", txt))
print(re.findall("^The rain in Spain stays mainly in the plain$", txt))
Output:
['Spain']
['The rain in Spain stays mainly in the plain']
Dacă punem + după un caracter acela trebuie să apară minim o dată. Dacă punem * după un caracter, acela poate să apară de oricâte ori, chiar și 0. Simbolurile pot fi combinate: .+ înseamnă că putem avea o listă de caractere oricât de lungă.
x = re.findall(".*ai", txt)
print(x)
['The rain in Spain stays mainly in the plai']
În loc de a folosi .+ putem folosi secvențe specifice:
\didentifică o listă de cifre\D- caractere care nu sunt cifre\s- caracterul spațiu\w- litere mici și mari, cifre și caracterul "_"
Pentru a fi și mai specifici putem folosi seturi:
[ar]- cel puțin unul din caracterele "a" și "r" este prezent[a-n]- orice caracter lowercase din intervalul dat[0-9]- putem aplica intervalele și pentru cifre[a-zA-Z]- sau le putem concatena pentru a accepta caractere mai variate[1-3][7-9]- două seturi unul în continuarea celuilalt funcționează ca orice alte simboluri legate. Exemplul dat caută o secvență de 2 cifre, unde prima cifră este în intervalul 1-3, iar a doua în intervalul 7-9
Putem folosi secvențele de mai sus pentru a identifica toate cuvintele care conțin șirul "ai", de exemplu:
x = re.findall("\w*ai\w", txt)
print(x)
Output: ['rain', 'Spain', 'main', 'plain']
Lista completă de reguli și simboluri se află aici: https://docs.python.org/3/library/re.html
Exercițiu
Creează o funcție de preprocesare a textului: funcția va primi un șir de caractere, îl va împărți în cuvinte și va elimina toate caracterele care nu sunt litere. Modifică funcția astfel încât să păstreze cratimele din cuvinte.
txt = "M-am dus la piata - asta voiam? Vom ajunge repede, cred, acasa!"