├── .DS_Store ├── 02 - Operare su file di testo con Python ├── .DS_Store ├── .ipynb_checkpoints │ └── operare_sulle_stringhe-checkpoint.ipynb ├── data │ ├── .DS_Store │ ├── articolo_ai.pdf │ ├── articolo_dl.html │ ├── articolo_ml.docx │ ├── proverbi.txt │ └── riddles_reviews_feb2019.csv ├── operare_su_csv.ipynb ├── operare_su_html.ipynb ├── operare_su_pdf.ipynb ├── operare_su_txt.ipynb ├── operare_su_wordx.ipynb └── operare_sulle_stringhe.ipynb ├── 03 - Le espressioni regolari └── espressioni_regolari.ipynb ├── 04 - Preprocessing del testo ├── .DS_Store ├── codifica_testo.ipynb ├── text_preprocessing_nltk.ipynb └── text_preprocessing_spacy.ipynb ├── 05 - Analisi del testo ├── named_entity_recognition.ipynb └── pos_tagging.ipynb ├── 06 - Sentiment Analysis ├── .DS_Store ├── classifier_nltk.ipynb ├── classifier_sklearn.ipynb ├── data │ ├── .DS_Store │ └── hifit_reviews.csv └── vader_nltk.ipynb ├── 07 - Topic modelling ├── .DS_Store ├── topic_modelling_article_sklearn.ipynb ├── topic_modelling_title_gensim.ipynb └── topic_modelling_title_sklearn.ipynb ├── 08 - Deep Learning e Chatbot ├── .DS_Store ├── chatbot_keras.ipynb ├── chatbot_seq2seq.ipynb └── data │ ├── .DS_Store │ └── model.json ├── 09 - Word embedding e Word2Vec ├── .DS_Store ├── glove.ipynb ├── word2vec.ipynb └── word_embedding.ipynb ├── 10 - Reti Ricorrenti e Text Generation ├── .DS_Store ├── commedia.txt ├── dante_RNN.ipynb └── model │ ├── .DS_Store │ └── dante_500.h5 ├── 11- Seq2Seq e Machine Translation ├── .DS_Store ├── machine_translation.ipynb └── model │ ├── .DS_Store │ ├── translator_500.h5 │ ├── translator_decoder_500.h5 │ └── translator_encoder_500.h5 ├── README.md └── X - Workspace └── Untitled9.ipynb /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProfAI/nlp00/bb5e60ccc24e536a0927f544d4f903df03624b85/.DS_Store -------------------------------------------------------------------------------- /02 - Operare su file di testo con Python/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProfAI/nlp00/bb5e60ccc24e536a0927f544d4f903df03624b85/02 - Operare su file di testo con Python/.DS_Store -------------------------------------------------------------------------------- /02 - Operare su file di testo con Python/.ipynb_checkpoints/operare_sulle_stringhe-checkpoint.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "colab_type": "text", 7 | "id": "view-in-github" 8 | }, 9 | "source": [ 10 | "\"Open" 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "metadata": { 16 | "colab_type": "text", 17 | "id": "I1PPWriTtctt" 18 | }, 19 | "source": [ 20 | "# Operare sulle stringhe in Python\n", 21 | "\n", 22 | "In questo notebook vederemo alcune funzioni utili che Python ci mette a disposizione per operare sulle stringhe.\n", 23 | "
\n", 24 | "\n", 25 | "## Il tipo String\n", 26 | "In Python una stringa è una sequenza di caratteri immutabile, cosa vuol dire questo ? Che possiamo accedere a elementi e sotto-sequenze di una stringa utilizzando **l'indexing** e lo **slicing** ma non possiamo modificarne i valori." 27 | ] 28 | }, 29 | { 30 | "cell_type": "code", 31 | "execution_count": null, 32 | "metadata": {}, 33 | "outputs": [], 34 | "source": [ 35 | "string = \"Ciao\"\n", 36 | "string." 37 | ] 38 | }, 39 | { 40 | "cell_type": "code", 41 | "execution_count": 0, 42 | "metadata": { 43 | "colab": { 44 | "base_uri": "https://localhost:8080/", 45 | "height": 120 46 | }, 47 | "colab_type": "code", 48 | "id": "kAlcRiXLtakM", 49 | "outputId": "fdc063c0-5cdf-4c21-a26f-8244132aae93" 50 | }, 51 | "outputs": [ 52 | { 53 | "name": "stdout", 54 | "output_type": "stream", 55 | "text": [ 56 | "ProfessionAI spacca\n", 57 | "P\n", 58 | "a\n", 59 | "Pro\n", 60 | "fe\n", 61 | "ProfessionAI spac\n" 62 | ] 63 | } 64 | ], 65 | "source": [ 66 | "# Definiamo una stringa\n", 67 | "my_string =\"ProfessionAI spacca\"\n", 68 | "print(my_string)\n", 69 | "\n", 70 | "# Stampiamo solo il primo carattere\n", 71 | "print(my_string[0]) # indexing\n", 72 | "\n", 73 | "# Stampiamo solo l'ultimo carattere\n", 74 | "print(my_string[-1])\n", 75 | "\n", 76 | "# Stampiamo i primi 3 caratteri\n", 77 | "print(my_string[:3]) # slicing\n", 78 | "\n", 79 | "# Stampiamo 4 e 5 carattere\n", 80 | "print(my_string[3:5])\n", 81 | "\n", 82 | "# Stampiam tutto tranne gli ultimi due caratteri\n", 83 | "print(my_string[:-2])\n" 84 | ] 85 | }, 86 | { 87 | "cell_type": "markdown", 88 | "metadata": { 89 | "colab_type": "text", 90 | "id": "9TRFu4i4vkiI" 91 | }, 92 | "source": [ 93 | "Il tenativo di modificare uno o più caratteri di una stringa genererà un'eccezione." 94 | ] 95 | }, 96 | { 97 | "cell_type": "code", 98 | "execution_count": 0, 99 | "metadata": { 100 | "colab": { 101 | "base_uri": "https://localhost:8080/", 102 | "height": 164 103 | }, 104 | "colab_type": "code", 105 | "id": "JrdcLVJUvbJR", 106 | "outputId": "ebc36961-ad41-475c-9177-43ed760697eb" 107 | }, 108 | "outputs": [ 109 | { 110 | "ename": "TypeError", 111 | "evalue": "ignored", 112 | "output_type": "error", 113 | "traceback": [ 114 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 115 | "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", 116 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mmy_string\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m\"F\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", 117 | "\u001b[0;31mTypeError\u001b[0m: 'str' object does not support item assignment" 118 | ] 119 | } 120 | ], 121 | "source": [ 122 | "my_string[0] = \"F\"" 123 | ] 124 | }, 125 | { 126 | "cell_type": "markdown", 127 | "metadata": { 128 | "colab_type": "text", 129 | "id": "hw5z5MS_wSeL" 130 | }, 131 | "source": [ 132 | "Trattandosi di una sequenza possiamo conoscere il numero di elementi, e quindi di caratteri, che compongono una stringa utilizzando la funzione *len*." 133 | ] 134 | }, 135 | { 136 | "cell_type": "code", 137 | "execution_count": 0, 138 | "metadata": { 139 | "colab": { 140 | "base_uri": "https://localhost:8080/", 141 | "height": 34 142 | }, 143 | "colab_type": "code", 144 | "id": "8a34C420wX_M", 145 | "outputId": "dcb7db29-e43e-4fa6-fcc3-d02bb1cc2b2f" 146 | }, 147 | "outputs": [ 148 | { 149 | "data": { 150 | "text/plain": [ 151 | "19" 152 | ] 153 | }, 154 | "execution_count": 3, 155 | "metadata": { 156 | "tags": [] 157 | }, 158 | "output_type": "execute_result" 159 | } 160 | ], 161 | "source": [ 162 | "len(my_string)" 163 | ] 164 | }, 165 | { 166 | "cell_type": "markdown", 167 | "metadata": { 168 | "colab_type": "text", 169 | "id": "0rfqOZD7wCUx" 170 | }, 171 | "source": [ 172 | "## Metodi utili" 173 | ] 174 | }, 175 | { 176 | "cell_type": "markdown", 177 | "metadata": { 178 | "colab_type": "text", 179 | "id": "4a46K1ravujC" 180 | }, 181 | "source": [ 182 | "Come tutte i tipi buil-in di Python, le stringhe sono oggetti e quindi hanno dei metodi, puoi trovare la lista completa dei metodi [a questo link](https://www.w3schools.com/python/python_ref_string.asp), vediamo insieme i più utili. \n", 183 | "

\n", 184 | "Possiamo convertire i caratteri di una stringa in minuscolo/maiuscolo utilizzando i metodi *lower/upper*." 185 | ] 186 | }, 187 | { 188 | "cell_type": "code", 189 | "execution_count": 0, 190 | "metadata": { 191 | "colab": { 192 | "base_uri": "https://localhost:8080/", 193 | "height": 51 194 | }, 195 | "colab_type": "code", 196 | "id": "m6VLxFjYvtVS", 197 | "outputId": "336c4941-bcb1-4ffd-c8dd-59d9ea65ad7e" 198 | }, 199 | "outputs": [ 200 | { 201 | "name": "stdout", 202 | "output_type": "stream", 203 | "text": [ 204 | "Tutto minuscolo: professionai spacca\n", 205 | "Tutto maiuscolo: PROFESSIONAI SPACCA\n" 206 | ] 207 | } 208 | ], 209 | "source": [ 210 | "my_string =\"ProfessionAI spacca\"\n", 211 | "\n", 212 | "my_string_lower = my_string.lower()\n", 213 | "print(\"Tutto minuscolo: %s\" % my_string_lower)\n", 214 | "\n", 215 | "my_string_upper = my_string.upper()\n", 216 | "print(\"Tutto maiuscolo: %s\" % my_string_upper)" 217 | ] 218 | }, 219 | { 220 | "cell_type": "markdown", 221 | "metadata": { 222 | "colab_type": "text", 223 | "id": "ZgjxCGIiwxAs" 224 | }, 225 | "source": [ 226 | "Possiamo dividere le parole in una stringa utilizzando il metodo *split()*, il risultato sarà una lista con le singole parole." 227 | ] 228 | }, 229 | { 230 | "cell_type": "code", 231 | "execution_count": 3, 232 | "metadata": { 233 | "colab": { 234 | "base_uri": "https://localhost:8080/", 235 | "height": 71 236 | }, 237 | "colab_type": "code", 238 | "id": "RDeS4Q9Twnpo", 239 | "outputId": "3ec1cf8a-b4d2-439e-a95b-107de45a6cdb" 240 | }, 241 | "outputs": [ 242 | { 243 | "name": "stdout", 244 | "output_type": "stream", 245 | "text": [ 246 | "['Oggi', 'è', 'una', 'stupenda', 'giornata', 'per', 'studiare', 'Natural', 'Language', 'Processing']\n", 247 | "\n" 248 | ] 249 | } 250 | ], 251 | "source": [ 252 | "my_string = \"Oggi è una stupenda giornata per studiare Natural Language Processing\"\n", 253 | "\n", 254 | "words_list = my_string.split()\n", 255 | "print(words_list)\n", 256 | "print(type(words_list))" 257 | ] 258 | }, 259 | { 260 | "cell_type": "markdown", 261 | "metadata": { 262 | "colab_type": "text", 263 | "id": "nyZtTQ2Dy0S4" 264 | }, 265 | "source": [ 266 | "Come possiamo fare la trasformazione inversa ? Cioè passare da una lista di parole ad una stringa ? Lo possiamo fare usando il metodo *join()* che prende in input una lista di stringhe e genera un'unica stringa i cui elementi della lista sono separati dalla stringa (più facile a farsi che a dirsi)." 267 | ] 268 | }, 269 | { 270 | "cell_type": "code", 271 | "execution_count": 5, 272 | "metadata": { 273 | "colab": { 274 | "base_uri": "https://localhost:8080/", 275 | "height": 34 276 | }, 277 | "colab_type": "code", 278 | "id": "2xdMaC04yzqd", 279 | "outputId": "c9039186-227a-44e3-e349-4bdd50fd8e11" 280 | }, 281 | "outputs": [ 282 | { 283 | "name": "stdout", 284 | "output_type": "stream", 285 | "text": [ 286 | "Oggi è una stupenda giornata per studiare Natural Language Processing\n" 287 | ] 288 | } 289 | ], 290 | "source": [ 291 | "my_string = \" \".join(words_list)\n", 292 | "print(my_string)" 293 | ] 294 | }, 295 | { 296 | "cell_type": "code", 297 | "execution_count": 6, 298 | "metadata": { 299 | "colab": { 300 | "base_uri": "https://localhost:8080/", 301 | "height": 71 302 | }, 303 | "colab_type": "code", 304 | "id": "OINRIKJIzo5d", 305 | "outputId": "3c62408a-ef23-4a17-8ac7-dca414dfd458" 306 | }, 307 | "outputs": [ 308 | { 309 | "name": "stdout", 310 | "output_type": "stream", 311 | "text": [ 312 | "Oggi_è_una_stupenda_giornata_per_studiare_Natural_Language_Processing\n", 313 | "Oggi-PASSO-è-PASSO-una-PASSO-stupenda-PASSO-giornata-PASSO-per-PASSO-studiare-PASSO-Natural-PASSO-Language-PASSO-Processing\n" 314 | ] 315 | } 316 | ], 317 | "source": [ 318 | "my_string = \"_\".join(words_list)\n", 319 | "print(my_string)\n", 320 | "\n", 321 | "my_string = \"-PASSO-\".join(words_list)\n", 322 | "print(my_string)" 323 | ] 324 | }, 325 | { 326 | "cell_type": "markdown", 327 | "metadata": { 328 | "colab_type": "text", 329 | "id": "k0KOn9j_zhGN" 330 | }, 331 | "source": [ 332 | "In questo caso abbiamo (ovviamente) usato uno spazio per separare le stringhe, ma avremmo potuto fare la stessa cosa con qualsiasi carattere o stringa." 333 | ] 334 | }, 335 | { 336 | "cell_type": "markdown", 337 | "metadata": { 338 | "colab_type": "text", 339 | "id": "tculJJpnxRdO" 340 | }, 341 | "source": [ 342 | "Possiamo anche dividere le stringhe per un **pattern** definito da noi, semplicemente passano tale pattern come argomento del metdo *split(pattern)*, ad esempio possiamo dividerla per frasi passando un punto." 343 | ] 344 | }, 345 | { 346 | "cell_type": "code", 347 | "execution_count": 0, 348 | "metadata": { 349 | "colab": { 350 | "base_uri": "https://localhost:8080/", 351 | "height": 51 352 | }, 353 | "colab_type": "code", 354 | "id": "yqCmMOMAxKs9", 355 | "outputId": "51ae56c6-36c2-4064-a441-dd41f0385e7f" 356 | }, 357 | "outputs": [ 358 | { 359 | "name": "stdout", 360 | "output_type": "stream", 361 | "text": [ 362 | "['Oggi è una stupenda giornata per studiare Natural Language Processing', \" Poi c'è Giuseppe che è davvero bravo\", ' Peccato che è antipatico']\n", 363 | "\n" 364 | ] 365 | } 366 | ], 367 | "source": [ 368 | "my_string = \"Oggi è una stupenda giornata per studiare Natural Language Processing. Poi c'è Giuseppe che è davvero bravo. Peccato che è antipatico\"\n", 369 | "sentences_list = my_string.split(\".\")\n", 370 | "\n", 371 | "print(sentences_list)\n", 372 | "print(type(sentences_list))" 373 | ] 374 | }, 375 | { 376 | "cell_type": "markdown", 377 | "metadata": { 378 | "colab_type": "text", 379 | "id": "MscgTf7I00tL" 380 | }, 381 | "source": [ 382 | "Possiamo contare il numero di volte che una sotto-stringa compare in una stringa usando il metodo *count(substring)*" 383 | ] 384 | }, 385 | { 386 | "cell_type": "code", 387 | "execution_count": 0, 388 | "metadata": { 389 | "colab": { 390 | "base_uri": "https://localhost:8080/", 391 | "height": 34 392 | }, 393 | "colab_type": "code", 394 | "id": "Y3O4h2c806li", 395 | "outputId": "c0e05fd9-730d-4b08-8bc2-799d90596f11" 396 | }, 397 | "outputs": [ 398 | { 399 | "name": "stdout", 400 | "output_type": "stream", 401 | "text": [ 402 | "La parola 'è' compare 4 volte\n" 403 | ] 404 | } 405 | ], 406 | "source": [ 407 | "sub_count = my_string.count('è')\n", 408 | "print(\"La parola 'è' compare %d volte\" % sub_count)" 409 | ] 410 | }, 411 | { 412 | "cell_type": "markdown", 413 | "metadata": { 414 | "colab_type": "text", 415 | "id": "nZFWfvTfyh8p" 416 | }, 417 | "source": [ 418 | "Possiamo sostituire una parola o una sotto-stringa della stringa utilizzando il metodo *replace(old, new)*, passandogli la sotto-stringa da sostituire e quella con la quale effettuare la sostituzione. Possiamo utilizzare questo stesso metodo per rimuovere una sotto-stringa dalla stringa passando una stringa vuota come secondo argomento." 419 | ] 420 | }, 421 | { 422 | "cell_type": "code", 423 | "execution_count": 0, 424 | "metadata": { 425 | "colab": { 426 | "base_uri": "https://localhost:8080/", 427 | "height": 51 428 | }, 429 | "colab_type": "code", 430 | "id": "zj061ESBzGkA", 431 | "outputId": "270ebe9d-2e7c-4ba0-9740-5ad4ad735bc2" 432 | }, 433 | "outputs": [ 434 | { 435 | "name": "stdout", 436 | "output_type": "stream", 437 | "text": [ 438 | "Oggi è una stupenda giornata per studiare Natural Language Processing. E c'è Giuseppe è davvero bravo. Peccato è antipatico\n", 439 | "Oggi è una stupenda giornata per studiare Natural Language Processing. E c'è Giuseppe è davvero bravo. Peccato è antipatico\n" 440 | ] 441 | } 442 | ], 443 | "source": [ 444 | "# sostuiamo la parola 'Poi' con 'E'\n", 445 | "# per tutte le occorrenze di 'Poi' nella stringa\n", 446 | "my_string = my_string.replace(\"Poi\",\"E\")\n", 447 | "print(my_string)\n", 448 | "\n", 449 | "# Rimuoviamo tutte le occorrenze di 'che'\n", 450 | "my_string = my_string.replace(\" che\",\"\") # rimuoviamo anche lo spazio prima della parola\n", 451 | "print(my_string)" 452 | ] 453 | }, 454 | { 455 | "cell_type": "markdown", 456 | "metadata": { 457 | "colab_type": "text", 458 | "id": "vgfBKkEiyBFz" 459 | }, 460 | "source": [ 461 | "Possiamo effettuare la ricerca di una parola o di una sotto-stringa utilizzando il metodo *find()* questo ritornerà l'indice della prima occorrenza del risultato, oppure -1 se non trova nulla. Possiamo utilizzare tale metodo in combinazione con lo slicing per estrarre una sottostringa dalla stringa." 462 | ] 463 | }, 464 | { 465 | "cell_type": "code", 466 | "execution_count": 0, 467 | "metadata": { 468 | "colab": { 469 | "base_uri": "https://localhost:8080/", 470 | "height": 68 471 | }, 472 | "colab_type": "code", 473 | "id": "b6BcHQ-9x0Y_", 474 | "outputId": "38ffcf6e-5499-4080-d53f-bd6eedbddbea" 475 | }, 476 | "outputs": [ 477 | { 478 | "name": "stdout", 479 | "output_type": "stream", 480 | "text": [ 481 | "Occorrenza di 'E' trovata in posizione 71\n", 482 | "E c'è Giuseppe è davvero bravo. Peccato è antipatico\n", 483 | "E c'è Giuseppe è davvero bravo\n" 484 | ] 485 | } 486 | ], 487 | "source": [ 488 | "start_index = my_string.find(\"E\")\n", 489 | "print(\"Occorrenza di 'E' trovata in posizione %d\" % start_index)\n", 490 | "\n", 491 | "my_substring = my_string[start_index:]\n", 492 | "print(my_substring)\n", 493 | "\n", 494 | "end_index = my_substring.find(\".\")\n", 495 | "my_substring = my_substring[:end_index]\n", 496 | "print(my_substring)" 497 | ] 498 | }, 499 | { 500 | "cell_type": "markdown", 501 | "metadata": { 502 | "colab_type": "text", 503 | "id": "Y-8uEfS13dmg" 504 | }, 505 | "source": [ 506 | "Se invece vogliamo conoscere l'indice dell'ultima occorrenza possiamo usare il metodo *rfind()*." 507 | ] 508 | }, 509 | { 510 | "cell_type": "code", 511 | "execution_count": 0, 512 | "metadata": { 513 | "colab": { 514 | "base_uri": "https://localhost:8080/", 515 | "height": 51 516 | }, 517 | "colab_type": "code", 518 | "id": "bGzU1pfY3lTw", 519 | "outputId": "c2e5fa4b-fcca-4414-8502-57b4662b05be" 520 | }, 521 | "outputs": [ 522 | { 523 | "name": "stdout", 524 | "output_type": "stream", 525 | "text": [ 526 | "18\n", 527 | "28\n" 528 | ] 529 | } 530 | ], 531 | "source": [ 532 | "my_string = \"Occhio per occhio dente per dente\"\n", 533 | "print(my_string.find('dente')) # prima occorrenza\n", 534 | "print(my_string.rfind('dente')) # ultima occorrenza b" 535 | ] 536 | }, 537 | { 538 | "cell_type": "markdown", 539 | "metadata": { 540 | "colab_type": "text", 541 | "id": "iOqyBSP72sWa" 542 | }, 543 | "source": [ 544 | "Gli ultimi metodi, che potrebbero sembrare inutili ma che in realtà sono davvero utili quando operiamo su corpus di testo, sono *lstrip() e strip()*, che rispettivamente rimuovo gli spazi dall'inizio della stringa e dall'inizio e la fine della stringa." 545 | ] 546 | }, 547 | { 548 | "cell_type": "code", 549 | "execution_count": 0, 550 | "metadata": { 551 | "colab": { 552 | "base_uri": "https://localhost:8080/", 553 | "height": 51 554 | }, 555 | "colab_type": "code", 556 | "id": "n6XSw21W0Nvi", 557 | "outputId": "e4122a46-4023-47c6-bb8b-4b7598cf354a" 558 | }, 559 | "outputs": [ 560 | { 561 | "name": "stdout", 562 | "output_type": "stream", 563 | "text": [ 564 | "\"Questo è un test \"\n", 565 | "\"Questo è un test\"\n" 566 | ] 567 | } 568 | ], 569 | "source": [ 570 | "string = \" Questo è un test \"\n", 571 | "print('\"'+string.lstrip()+'\"')\n", 572 | "print('\"'+string.strip()+'\"')\n", 573 | "\n", 574 | "# ricorda di effettuare l'assegnazione\n", 575 | "# per modificare la stringa\n", 576 | "# string = string.strip()" 577 | ] 578 | }, 579 | { 580 | "cell_type": "code", 581 | "execution_count": 1, 582 | "metadata": { 583 | "colab": { 584 | "base_uri": "https://localhost:8080/", 585 | "height": 34 586 | }, 587 | "colab_type": "code", 588 | "id": "atq3UqNRyf-U", 589 | "outputId": "0844075f-fb08-4090-a51e-bc841b84c3a7" 590 | }, 591 | "outputs": [ 592 | { 593 | "data": { 594 | "text/plain": [ 595 | "'-'" 596 | ] 597 | }, 598 | "execution_count": 1, 599 | "metadata": { 600 | "tags": [] 601 | }, 602 | "output_type": "execute_result" 603 | } 604 | ], 605 | "source": [] 606 | }, 607 | { 608 | "cell_type": "code", 609 | "execution_count": 0, 610 | "metadata": { 611 | "colab": {}, 612 | "colab_type": "code", 613 | "id": "Taq9u48Vyi1w" 614 | }, 615 | "outputs": [], 616 | "source": [] 617 | }, 618 | { 619 | "cell_type": "markdown", 620 | "metadata": { 621 | "colab_type": "text", 622 | "id": "yIkfxX7-2JNp" 623 | }, 624 | "source": [ 625 | "## Link utili\n", 626 | "- https://www.w3schools.com/python/python_ref_string.asp" 627 | ] 628 | }, 629 | { 630 | "cell_type": "code", 631 | "execution_count": 0, 632 | "metadata": { 633 | "colab": {}, 634 | "colab_type": "code", 635 | "id": "6ERzMkmm2MtZ" 636 | }, 637 | "outputs": [], 638 | "source": [] 639 | } 640 | ], 641 | "metadata": { 642 | "colab": { 643 | "include_colab_link": true, 644 | "name": "operare_sulle_stringhe.ipynb", 645 | "provenance": [], 646 | "version": "0.3.2" 647 | }, 648 | "kernelspec": { 649 | "display_name": "Python 3", 650 | "language": "python", 651 | "name": "python3" 652 | }, 653 | "language_info": { 654 | "codemirror_mode": { 655 | "name": "ipython", 656 | "version": 3 657 | }, 658 | "file_extension": ".py", 659 | "mimetype": "text/x-python", 660 | "name": "python", 661 | "nbconvert_exporter": "python", 662 | "pygments_lexer": "ipython3", 663 | "version": "3.6.5" 664 | } 665 | }, 666 | "nbformat": 4, 667 | "nbformat_minor": 1 668 | } 669 | -------------------------------------------------------------------------------- /02 - Operare su file di testo con Python/data/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProfAI/nlp00/bb5e60ccc24e536a0927f544d4f903df03624b85/02 - Operare su file di testo con Python/data/.DS_Store -------------------------------------------------------------------------------- /02 - Operare su file di testo con Python/data/articolo_ai.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProfAI/nlp00/bb5e60ccc24e536a0927f544d4f903df03624b85/02 - Operare su file di testo con Python/data/articolo_ai.pdf -------------------------------------------------------------------------------- /02 - Operare su file di testo con Python/data/articolo_dl.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Deep Learning svelato | Giuseppe Gullo 6 | 7 | 8 | 9 | 10 |

11 | Deep Learning svelato: ecco come funzionano le Reti Neurali Artificiali 12 |

13 | 14 |

15 | di Giuseppe Gullo 16 |

17 | 18 |

19 | C’è tanto rumore intorno ai termini Reti Neurali Artificiali (dall’inglese Artificial Neural Network — ANN) e l’apprendimento profondo (dall’inglese Deep Learning, meglio chiamarlo così). 20 | Scrivo questo breve post giusto per farti capire che, in fondo, tutto questo rumore è ben giustificato! 21 | L’intelligenza artificiale sta avanzato in maniera esponenziale, trainata dai progressi nel machine learning che a loro volta derivano per gran parte da un’ unica tipologia di modelli: le reti neurali artificiali. 22 |

23 | 24 |

25 | Una rete neurale artificiale è un modello di machine learning che si ispira al funzionamento del cervello animale, quello che abbiamo anche noi mammiferi intelligenti all’interno della nostra scatola cranica, che può essere utilizzato per risolvere essenzialmente tre tipi di problemi: 26 |

    27 |
  • 28 | Classificazione: in cui la variabile da prevedere è di tipo categorico, cioè una classe (es. abbiamo un insieme di immagini di gatti e le vogliamo usare per riconoscere i gatti in altre foto) 29 |
  • 30 |
  • 31 | Regressione: in cui la variabile da prevedere è di tipo continuo, cioè un numero (es. abbiamo lo storico del valore di FIAT in borsa e vogliamo utilizzarlo per prevedere il valore futuro) 32 |
  • 33 |
  • 34 | Clustering: problema molto simile alla classificazione ma in cui non abbiamo a disposizione delle classi (es. abbiamo un insieme di immagini di tumori, vogliamo riconoscere quali sono maligni e quali benigni) 35 |
  • 36 |
37 | 38 |

39 | 40 |

41 | Come il cervello apprende 42 |

43 | 44 |

45 | Il cervello è composto da centinaia di miliardi di cellule nervose, i neuroni. 46 | Ogni volta che il cervello riceve uno stimolo sensoriale un gruppo di neuroni riceve un segnale, chiamato potenziale d’azione, se il potenziale di azione è abbastanza forte viene propagato ai neuroni vicini tramite dei canali chiamati sinapsi. 47 |

48 | 49 |

50 | Questo processo si ripete a cascata, neuroni attivano altri neuroni, fino a quando il segnale si esaurisce. 51 | I neuroni che si attivano insieme si legano insieme, questo è il concetto alla base dell’apprendimento (apprendimento hebbiano), così i neuroni si uniscono in complessi reticoli che sono proprio le reti neurali, la sede di tutta la nostra conoscenza. 52 |

53 | 54 |

55 | Un'approccio biologico al Machine Learning 56 |

57 | 58 |

59 | Le reti neurali artificiali utilizzano lo stesso approccio per permettere alle macchine di apprendere dai dati, cercando relazioni tra di essi e raggiungendo livelli di astrazione sempre più profondi. 60 | 61 | All’interno di una rete neurale artificiale i neuroni sono disposti su più strati: 62 | 63 |

    64 |
  • 65 | Uno strato di input: che prende in ingresso i dati, ogni neurone di questo strato rappresenta una proprietà del dataset 66 |
  • 67 |
  • 68 | Uno strato di output: che fornisce il risultato della rete neurale 69 |
  • 70 |
  • 71 | Uno o più strati nascosti: che si trovano tra lo strato di input e quello di output. 72 |
  • 73 |
74 | 75 | Il compito degli strati nascosti è di utilizzare le proprietà (features) del dataset per apprendere nuove proprietà. 76 | 77 | Solitamente prima della fase di creazione di un modello di machine learning, il dataset viene analizzato e manipolato per estrarre proprietà significative da quelle di cui già si dispone. Questo processo prende il nome di feature extraction e ha un ruolo fondamentale per la creazione di un modello di machine learning robusto. 78 | 79 | Una rete neurale artificiale automatizza il processo di feature extraction all’interno di ogni strato nascosto, per questo motivo le reti neurali artificiali sono definite modelli end-to-end, appunto perché prendono come input i dati grezzi del dataset per svolgere attività come classificazione, regressione o clustering. 80 | 81 | Una rete è definita “profonda” (dall’inglese deep) quando contiene due o più strati nascosti, in questi casi la rete utilizzerà le proprietà apprese in uno strato nascosto per apprendere ulteriori nuove proprietà ancora più significative nello strato successivo, fino a utilizzarle per eseguire classificazione, regressione o clustering nello strato di output. 82 | 83 | La performance di un modello di machine learning, intesa come precisione o errore, tende a convergere a un valore massimo, al contrario i modelli basati sul deep learning non hanno questa limitazione e migliorano gradualmente all’aumentare del numero di dati disponibili per l’addestramento, proprio grazie alla loro capacità di astrazione e di apprendere nuove proprietà dai dati. 84 | 85 |

86 | 87 |

88 | Istruire una rete neurale artificiale 89 |

90 | 91 |

92 | Le reti neurali artificiali non sono una novità, infatti sono conosciute da più di mezzo secolo, ma sono rimaste chiuse in un cassetto a causa dell’assenza di un metodo efficace ed efficiente per addestrarle. 93 | 94 | Questo è durato fino al 1986, anno in cui Jeff Hinton insieme a David Rumelhart e Ronald J. Williams proposero in questo paper l’utilizzo dell’algoritmo della Retropropagazione (dall’inglese Backpropagation) che ha stabilito la nascita di quello che oggi è il Deep Learning, ovvero l’insieme di metodi utilizzati per addestrare una rete neurale artificiale profonda. 95 | 96 | Ancora oggi, a più di 30 anni di distanza, la Retropropagazione è l’algoritmo più importante del deep learning, grazie Jeff! 97 | 98 |

99 | 100 |

101 | Quando usare il Deep Learning 102 |

103 | 104 |

105 | A differenza di quanto potresti pensare, le reti neurali non sono sempre la soluzione migliore, per due motivi in particolare: 106 |

    107 |
  • 108 | Per essere addestrate richiedono molti, molti (molti) dati, almeno nell’ordine di migliaia. 109 |
  • 110 |
  • 111 | Sono computazionalmente davvero dispendiose e spesso per completare l’addestramento in tempi umani è necessario parallelizzare il lavoro su di un cluster di GPU. 112 |
  • 113 |
114 | Inoltre per molti tipi di problemi relativamente semplici l’intervento di un modello basato sulle reti neurali non è neanche necessario, ma è possibile ottenere ottimi risultati con modelli meno complessi. 115 |

116 | 117 |

118 | Deep Learning nella vita reale 119 |

120 | 121 |

122 | I sistemi di computer vision odierni sono in grado di riconoscere persone, animali e oggetti con una precisione che è addirittura maggiore di quella dell’uomo, questi sistemi usano il Deep Learning. 123 | 124 | Le tecnologie di riconoscimento del parlato di Siri, Alexa e Cortana stanno pian piano raggiungendo lo stato dell’arte, queste tecnologie usano il Deep Learning. 125 | 126 | Nel 2015 AlphaGo è riuscito a battere il campione mondiale di Go Lee Sedolin una partita ufficiale, secondo gli esperti un risultato del genere non sarebbe dovuto arrivare prima di un altro decennio. AlphaGo usa il Deep Learning. 127 | 128 | Google è in assoluto la società che più si serve del Deep Learning e che sta maggiormente contribuendo al suo sviluppo, infatti la maggior parte dei servizi di Google, partendo da Search e passando per Gmail e Translate, utilizzano in un modo o nell’altro le reti neurali artificial e questo ha fortemente inciso sul suo successo su scala globale. 129 |

130 | 131 | 132 | -------------------------------------------------------------------------------- /02 - Operare su file di testo con Python/data/articolo_ml.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProfAI/nlp00/bb5e60ccc24e536a0927f544d4f903df03624b85/02 - Operare su file di testo con Python/data/articolo_ml.docx -------------------------------------------------------------------------------- /02 - Operare su file di testo con Python/data/proverbi.txt: -------------------------------------------------------------------------------- 1 | A buon intenditor, poche parole. 2 | A caval donato non si guarda in bocca. 3 | Anno nuovo, vita nuova. 4 | Bacco, Tabacco e Venere, riducon l’uomo in cenere. 5 | Buon sangue non mente. 6 | Campa cavallo che l’erba cresce. 7 | Can che abbaia non morde. 8 | Chi ben comincia è alla metà dell’opera. 9 | Chi è causa del suo mal, pianga se stesso. 10 | Chi la dura, la vince. 11 | Chiodo scaccia chiodo. 12 | Tanto la va la gatta al lardo che ci lascia lo zampino. -------------------------------------------------------------------------------- /02 - Operare su file di testo con Python/data/riddles_reviews_feb2019.csv: -------------------------------------------------------------------------------- 1 | Package Name,App Version Code,App Version Name,Reviewer Language,Device,Review Submit Date and Time,Review Submit Millis Since Epoch,Review Last Update Date and Time,Review Last Update Millis Since Epoch,Star Rating,Review Title,Review Text,Developer Reply Date and Time,Developer Reply Millis Since Epoch,Developer Reply Text,Review Link 2 | cat.app.lordofriddles,,,it,HWANE,2019-02-01T13:04:45Z,1549026285158,2019-02-01T13:04:45Z,1549026285158,5,,,,,, 3 | cat.app.lordofriddles,93,4.1.14,it,HWVNS-H,2019-02-01T15:05:30Z,1549033530837,2019-02-01T15:05:30Z,1549033530837,5,,,,,, 4 | cat.app.lordofriddles,93,4.1.14,it,v3720,2019-02-01T15:30:57Z,1549035057425,2019-02-01T15:30:57Z,1549035057425,5,,,,,, 5 | cat.app.lordofriddles,93,4.1.14,it,HWDIG-L8940,2019-02-01T15:34:20Z,1549035260011,2019-02-01T15:34:20Z,1549035260011,5,,,,,, 6 | cat.app.lordofriddles,,,it,HWPRA-H,2019-02-01T16:49:17Z,1549039757714,2019-02-01T16:49:17Z,1549039757714,4,,"Applicazione buona, ma indovinelli con soluzioni veramente impensabili. Buon passatempo per tenere la mente impegnata",,,,https://play.google.com/apps/publish?account=4894168828409330111#ReviewDetailsPlace:p=cat.app.lordofriddles&reviewid=gp:AOqpTOEbXXBjyrBS_5lODMJxkVcLF20S6GfQI9YnZfC5rv2IfRNGR5GKFPqZHvpSWP26aIE31L1-EDE7p2_QNDA 7 | cat.app.lordofriddles,93,4.1.14,it,W-P220,2019-02-01T23:03:46Z,1549062226750,2019-02-01T23:03:46Z,1549062226750,5,,,,,, 8 | cat.app.lordofriddles,93,4.1.14,it,HWCOL,2019-02-02T01:07:41Z,1549069661649,2019-02-02T01:07:41Z,1549069661649,5,,,,,, 9 | cat.app.lordofriddles,93,4.1.14,it,j7xelte,2019-02-02T09:15:36Z,1549098936627,2019-02-02T09:15:36Z,1549098936627,5,,,,,, 10 | cat.app.lordofriddles,93,4.1.14,it,HWANE,2019-02-02T19:27:43Z,1549135663644,2019-02-02T19:27:43Z,1549135663644,5,,,,,, 11 | cat.app.lordofriddles,91,4.1.12,it,matissevewifi,2019-02-03T15:49:31Z,1549208971955,2019-02-03T15:49:31Z,1549208971955,4,,ottimo gioco da fare da soli o in compagnia,,,,https://play.google.com/apps/publish?account=4894168828409330111#ReviewDetailsPlace:p=cat.app.lordofriddles&reviewid=gp:AOqpTOHtxMQpLjw73k-GHfoJYBy_8pqoCxg5_OGPjJcPpRpf2QJNFfCk1Ojqswj1xrVhBhAmlNloV3_6aKXX7us 12 | cat.app.lordofriddles,93,4.1.14,it,HWMYA-L6737,2019-02-03T17:25:02Z,1549214702143,2019-02-03T17:25:02Z,1549214702143,5,,,,,, 13 | cat.app.lordofriddles,93,4.1.14,it,HWAUM-Q,2019-02-03T17:27:51Z,1549214871705,2019-02-03T17:27:51Z,1549214871705,4,,,,,, 14 | cat.app.lordofriddles,93,4.1.14,it,HWVTR,2019-02-03T18:34:45Z,1549218885773,2019-02-03T18:34:45Z,1549218885773,5,,,,,, 15 | cat.app.lordofriddles,93,4.1.14,it,HWCAM-H,2019-02-03T19:58:13Z,1549223893452,2019-02-03T19:58:13Z,1549223893452,5,,,,,, 16 | cat.app.lordofriddles,93,4.1.14,it,j5xnlte,2018-02-21T19:16:51Z,1519240611565,2019-02-03T21:46:37Z,1549230397262,5,,bellissima sei un genio,,,,https://play.google.com/apps/publish?account=4894168828409330111#ReviewDetailsPlace:p=cat.app.lordofriddles&reviewid=gp:AOqpTOGI19hkTPn-FqnmBuazceSbEhGy4Fa3ggwQRqnbeKmVy6gX_rfXk690emeh0dnVk0-qjVTTm8ECMEAWTTQ 17 | cat.app.lordofriddles,93,4.1.14,it,j5nlte,2019-02-04T10:46:36Z,1549277196170,2019-02-04T10:46:36Z,1549277196170,5,,non mi piace,,,,https://play.google.com/apps/publish?account=4894168828409330111#ReviewDetailsPlace:p=cat.app.lordofriddles&reviewid=gp:AOqpTOHpm8-uXmSEXqhGjqDcFnW6zk4obvFlCTPjK_--kUq5NYsUmbI-J-luWEL24eAVMnjwq0kTzhaROMJuy8g 18 | cat.app.lordofriddles,93,4.1.14,it,HWEVA,2016-09-27T19:32:25Z,1475004745596,2019-02-04T10:51:24Z,1549277484607,5,,,,,, 19 | cat.app.lordofriddles,93,4.1.14,it,serranolte,2019-02-04T17:18:21Z,1549300701142,2019-02-04T17:18:21Z,1549300701142,5,,,,,, 20 | cat.app.lordofriddles,93,4.1.14,it,dreamlte,2019-02-04T22:00:31Z,1549317631677,2019-02-04T22:00:31Z,1549317631677,5,,,,,, 21 | cat.app.lordofriddles,93,4.1.14,it,HWVNS-H,2019-02-05T14:51:30Z,1549378290105,2019-02-05T14:51:30Z,1549378290105,4,,,,,, 22 | cat.app.lordofriddles,93,4.1.14,it,hwALE-H,2017-02-07T17:29:36Z,1486488576883,2019-02-05T21:48:38Z,1549403318751,4,,,,,, 23 | cat.app.lordofriddles,93,4.1.14,it,HWRNE,2019-02-05T23:54:53Z,1549410893176,2019-02-05T23:54:53Z,1549410893176,5,,,,,, 24 | cat.app.lordofriddles,93,4.1.14,it,j3y17lte,2019-02-06T06:25:25Z,1549434325386,2019-02-06T06:25:25Z,1549434325386,4,,bello,,,,https://play.google.com/apps/publish?account=4894168828409330111#ReviewDetailsPlace:p=cat.app.lordofriddles&reviewid=gp:AOqpTOGCYPQD7RX6lm18ja6HqaWohouaWZYUxnqRM6rY4B-N9vHfduLGMVtOM8HVm78-JJ9i-h1ArsTKLReKDek 25 | cat.app.lordofriddles,93,4.1.14,en,manning,2019-02-06T10:34:03Z,1549449243640,2019-02-06T10:34:03Z,1549449243640,4,,i like the game its a really good game for your brain to think more,,,,https://play.google.com/apps/publish?account=4894168828409330111#ReviewDetailsPlace:p=cat.app.lordofriddles&reviewid=gp:AOqpTOE0qkplPJOT5B2RFLFYdEhroDDsAOUvYWGU4auM99B_ZLwDxSJDcC6XPyoWyYEsnU4M79xwlO6X2ayU6N0 26 | cat.app.lordofriddles,93,4.1.14,it,dreamlte,2019-02-06T11:47:28Z,1549453648893,2019-02-06T11:47:28Z,1549453648893,5,,,,,, 27 | cat.app.lordofriddles,93,4.1.14,it,P4601AN,2019-02-06T15:40:37Z,1549467637375,2019-02-06T15:40:37Z,1549467637375,4,,,,,, 28 | cat.app.lordofriddles,93,4.1.14,it,HWEML,2019-02-06T16:44:25Z,1549471465679,2019-02-06T16:44:25Z,1549471465679,3,,Bellino,,,,https://play.google.com/apps/publish?account=4894168828409330111#ReviewDetailsPlace:p=cat.app.lordofriddles&reviewid=gp:AOqpTOEuTcdZNTlVEGMDiqhTTwfTNaLURTLXXmgyj05WCbFTQFjgDQLz3sxIxoJuVS25EkxdleIHdvGaGxsI90I 29 | cat.app.lordofriddles,93,4.1.14,it,ASUS_X00HD_1,2019-02-08T14:00:03Z,1549634403338,2019-02-08T14:00:03Z,1549634403338,2,,,,,, 30 | cat.app.lordofriddles,93,4.1.14,it,v3720,2019-02-08T15:40:18Z,1549640418984,2019-02-08T15:40:18Z,1549640418984,4,,,,,, 31 | cat.app.lordofriddles,93,4.1.14,it,hero2lte,2019-02-08T16:22:21Z,1549642941508,2019-02-08T16:22:21Z,1549642941508,4,,,,,, 32 | cat.app.lordofriddles,93,4.1.14,it,Pixi4-6_4G,2019-02-08T20:17:41Z,1549657061183,2019-02-08T20:17:41Z,1549657061183,3,,,,,, 33 | cat.app.lordofriddles,93,4.1.14,it,star2lte,2019-02-08T23:20:42Z,1549668042024,2019-02-08T23:20:42Z,1549668042024,3,,bello,,,,https://play.google.com/apps/publish?account=4894168828409330111#ReviewDetailsPlace:p=cat.app.lordofriddles&reviewid=gp:AOqpTOF7JQJ1C3ZuD1SGaXAvhnjbx4Fd_gEcQj9CQuYM2j6jCBbUX_N_kPbUqXGrgNkqI6-40D6XOO-dJ6BtbZs 34 | cat.app.lordofriddles,93,4.1.14,it,gts28lte,2019-02-09T20:36:15Z,1549744575291,2019-02-09T20:36:15Z,1549744575291,4,,,,,, 35 | cat.app.lordofriddles,93,4.1.14,it,a5y17lte,2019-02-10T00:05:54Z,1549757154250,2019-02-10T00:05:54Z,1549757154250,4,,,,,, 36 | cat.app.lordofriddles,93,4.1.14,it,HWWAS-H,2019-02-10T17:04:37Z,1549818277421,2019-02-10T17:04:37Z,1549818277421,5,,,,,, 37 | cat.app.lordofriddles,93,4.1.14,it,OnePlus3,2019-02-11T14:53:11Z,1549896791168,2019-02-11T14:53:11Z,1549896791168,5,,,,,, 38 | cat.app.lordofriddles,93,4.1.14,it,j5y17lte,2019-02-12T15:33:44Z,1549985624701,2019-02-12T15:33:44Z,1549985624701,1,,,,,, 39 | cat.app.lordofriddles,93,4.1.14,it,j5xnlte,2019-02-12T17:23:18Z,1549992198800,2019-02-12T17:23:18Z,1549992198800,1,,,,,, 40 | cat.app.lordofriddles,93,4.1.14,it,HWMYA-L6737,2019-02-12T20:16:12Z,1550002572474,2019-02-12T20:16:12Z,1550002572474,3,,Insomma non molto bello,,,,https://play.google.com/apps/publish?account=4894168828409330111#ReviewDetailsPlace:p=cat.app.lordofriddles&reviewid=gp:AOqpTOHyVcaDjqr_6iXa4NAxRI_PuWs_DOhVk5HdDtK6k5t8LJQbEXvqbtI1QUvCtIQwsOIe84ODeCyDSvxGs1U 41 | cat.app.lordofriddles,93,4.1.14,it,mlv5n,2019-02-12T21:23:01Z,1550006581686,2019-02-12T21:23:01Z,1550006581686,5,,,,,, 42 | cat.app.lordofriddles,93,4.1.14,it,s3ve3g,2019-02-13T11:26:09Z,1550057169927,2019-02-13T11:26:09Z,1550057169927,1,,,,,, 43 | cat.app.lordofriddles,93,4.1.14,it,j5y17lte,2019-02-15T12:36:05Z,1550234165390,2019-02-15T12:36:05Z,1550234165390,5,,,,,, 44 | cat.app.lordofriddles,93,4.1.14,it,j4primelte,2019-02-15T13:01:38Z,1550235698211,2019-02-15T13:01:38Z,1550235698211,5,,,,,, 45 | cat.app.lordofriddles,93,4.1.14,it,j3y17lte,2019-02-15T21:15:51Z,1550265351421,2019-02-15T21:15:51Z,1550265351421,4,,bella,,,,https://play.google.com/apps/publish?account=4894168828409330111#ReviewDetailsPlace:p=cat.app.lordofriddles&reviewid=gp:AOqpTOGt-cXYx6l43t3M3q3ivDMWBgw6r1lIR21Mgzm8HfpWAEoPIEjEiqJuqFStYDuJ1jYiNhsW65-ci3g95QY 46 | cat.app.lordofriddles,93,4.1.14,it,j3y17lte,2019-02-16T01:29:34Z,1550280574260,2019-02-16T01:29:34Z,1550280574260,5,,beĺla app,,,,https://play.google.com/apps/publish?account=4894168828409330111#ReviewDetailsPlace:p=cat.app.lordofriddles&reviewid=gp:AOqpTOGHvNMZk6GIytEXRBDLONNGB0JKQE3xvJssT_haxU1ipZsU9bimUUbQmJa69gGlD1PzWhE7IZ5RrCV8OR4 47 | cat.app.lordofriddles,93,4.1.14,it,HWMYA-L6737,2019-02-16T11:53:22Z,1550318002692,2019-02-16T11:53:22Z,1550318002692,5,,,,,, 48 | cat.app.lordofriddles,93,4.1.14,it,hwALE-H,2019-02-16T12:03:00Z,1550318580145,2019-02-16T12:03:00Z,1550318580145,4,,,,,, 49 | cat.app.lordofriddles,93,4.1.14,it,HWPRA-H,2019-02-16T15:54:36Z,1550332476256,2019-02-16T15:54:36Z,1550332476256,4,,,,,, 50 | cat.app.lordofriddles,93,4.1.14,it,HWPRA-H,2019-02-16T16:05:15Z,1550333115635,2019-02-16T16:05:15Z,1550333115635,5,,,,,, 51 | cat.app.lordofriddles,93,4.1.14,it,j5y17lte,2019-02-16T20:07:13Z,1550347633951,2019-02-16T20:07:13Z,1550347633951,5,,,,,, 52 | cat.app.lordofriddles,93,4.1.14,it,tulip,2019-02-17T09:32:41Z,1550395961991,2019-02-17T09:32:41Z,1550395961991,5,,,,,, 53 | cat.app.lordofriddles,93,4.1.14,it,ASUS_X00T_2,2019-02-17T13:14:46Z,1550409286571,2019-02-17T13:14:46Z,1550409286571,5,,,,,, 54 | cat.app.lordofriddles,93,4.1.14,it,j6lte,2019-02-17T14:03:01Z,1550412181657,2019-02-17T14:03:01Z,1550412181657,5,,,,,, 55 | cat.app.lordofriddles,93,4.1.14,it,HWANE,2019-02-17T20:42:21Z,1550436141101,2019-02-17T20:42:21Z,1550436141101,5,,,,,, 56 | cat.app.lordofriddles,93,4.1.14,it,a9y18qlte,2019-02-17T21:57:04Z,1550440624682,2019-02-17T21:57:04Z,1550440624682,5,,,,,, 57 | cat.app.lordofriddles,93,4.1.14,it,HWLDN-Q,2019-02-18T05:17:45Z,1550467065528,2019-02-18T05:17:45Z,1550467065528,5,,,,,, 58 | cat.app.lordofriddles,93,4.1.14,it,HWANE,2019-02-18T07:34:28Z,1550475268314,2019-02-18T07:34:28Z,1550475268314,5,,,,,, 59 | cat.app.lordofriddles,93,4.1.14,it,HWPOT-H,2019-02-18T12:47:02Z,1550494022242,2019-02-18T12:47:02Z,1550494022242,5,,,,,, 60 | cat.app.lordofriddles,93,4.1.14,it,ysl,2019-02-18T20:58:11Z,1550523491687,2019-02-18T20:58:11Z,1550523491687,1,,,,,, 61 | cat.app.lordofriddles,93,4.1.14,it,star2lte,2019-02-19T01:11:02Z,1550538662114,2019-02-19T01:11:02Z,1550538662114,5,,ben fatto,,,,https://play.google.com/apps/publish?account=4894168828409330111#ReviewDetailsPlace:p=cat.app.lordofriddles&reviewid=gp:AOqpTOEQig8h1liobtVokOU4TOQJL0hvFLImzPt9COnZbGJe_-TBMPJTzMUhmCsPTMz8hTKeT5xhSQdL7E6D0gk 62 | cat.app.lordofriddles,93,4.1.14,it,HWVKY,2019-02-19T15:00:24Z,1550588424694,2019-02-19T15:00:24Z,1550588424694,5,,,,,, 63 | cat.app.lordofriddles,93,4.1.14,it,grandneove3g,2019-02-20T19:23:42Z,1550690622720,2019-02-20T19:23:42Z,1550690622720,1,,,,,, 64 | cat.app.lordofriddles,93,4.1.14,it,j5xnlte,2019-02-20T20:00:28Z,1550692828337,2019-02-20T20:00:28Z,1550692828337,5,,,,,, 65 | cat.app.lordofriddles,93,4.1.14,it,dreamlte,2019-02-20T23:57:55Z,1550707075963,2019-02-20T23:57:55Z,1550707075963,1,,,,,, 66 | cat.app.lordofriddles,93,4.1.14,it,j6lte,2019-02-21T02:17:18Z,1550715438499,2019-02-21T02:17:18Z,1550715438499,3,,,,,, 67 | cat.app.lordofriddles,93,4.1.14,it,HWJSN-H,2019-02-21T13:40:33Z,1550756433390,2019-02-21T13:40:33Z,1550756433390,5,,,,,, 68 | cat.app.lordofriddles,93,4.1.14,it,HWRNE,2019-02-21T21:57:55Z,1550786275803,2019-02-21T21:57:55Z,1550786275803,3,,,,,, 69 | cat.app.lordofriddles,93,4.1.14,it,a5xelte,2019-02-21T22:47:27Z,1550789247670,2019-02-21T22:47:27Z,1550789247670,5,,,,,, 70 | cat.app.lordofriddles,91,4.1.12,it,HWEML,2019-02-22T12:33:24Z,1550838804916,2019-02-22T12:33:24Z,1550838804916,5,,,,,, 71 | cat.app.lordofriddles,93,4.1.14,it,gtel3g,2019-02-22T19:13:29Z,1550862809915,2019-02-22T19:13:29Z,1550862809915,5,,,,,, 72 | cat.app.lordofriddles,93,4.1.14,it,herolte,2019-02-22T20:12:41Z,1550866361476,2019-02-22T20:12:41Z,1550866361476,5,,,,,, 73 | cat.app.lordofriddles,93,4.1.14,it,ASUS_X008_1,2019-02-22T21:33:04Z,1550871184986,2019-02-22T21:33:04Z,1550871184986,4,,"Yes it's pretty ,beautiful",,,,https://play.google.com/apps/publish?account=4894168828409330111#ReviewDetailsPlace:p=cat.app.lordofriddles&reviewid=gp:AOqpTOHJX75gvUAB5yHej_CrlGNhxZnKSy7I73TgFWcW-y32cH89MOvuELHr2vKfSu5wViF1S4do9YLfzlNKI0M 74 | cat.app.lordofriddles,93,4.1.14,it,j3xnlte,2019-02-23T00:05:26Z,1550880326640,2019-02-23T00:05:26Z,1550880326640,5,,è bello ....... Però è complicato perché se non rifletti non ci arrivi,,,,https://play.google.com/apps/publish?account=4894168828409330111#ReviewDetailsPlace:p=cat.app.lordofriddles&reviewid=gp:AOqpTOHaKsxG-kyq9xBKz7z2lPTyRXqYHYYMIYAHHvayi2OlI754HSIcST57oP8KQ9qRloLca0RCawTQ_AWY7vo 75 | cat.app.lordofriddles,93,4.1.14,it,j6lte,2019-02-23T21:35:48Z,1550957748806,2019-02-23T21:35:48Z,1550957748806,5,,bello,,,,https://play.google.com/apps/publish?account=4894168828409330111#ReviewDetailsPlace:p=cat.app.lordofriddles&reviewid=gp:AOqpTOGrif6DuBXd3ZXHJ2N9qCWGX_kOZD-qwLBJ7owJhDvsjKbbf4Lr_Iyrg5C_zBt0z2Zt8nW16e7cnx0DjOU 76 | cat.app.lordofriddles,93,4.1.14,it,HWRNE,2019-02-24T01:59:25Z,1550973565220,2019-02-24T01:59:25Z,1550973565220,5,,,,,, 77 | cat.app.lordofriddles,93,4.1.14,it,HWPRA-H,2019-02-24T03:32:27Z,1550979147749,2019-02-24T03:32:27Z,1550979147749,5,,,,,, 78 | cat.app.lordofriddles,93,4.1.14,it,vince,2019-02-24T17:39:52Z,1551029992033,2019-02-24T17:39:52Z,1551029992033,5,,buona,,,,https://play.google.com/apps/publish?account=4894168828409330111#ReviewDetailsPlace:p=cat.app.lordofriddles&reviewid=gp:AOqpTOGRbO6oLTq8noTO2OdLljjNkhFYeUE9WY82yDBTbqxsSo9kkXNE7kYZLQXhEOTE0S8nBpi4Q8rTObWAaBw 79 | cat.app.lordofriddles,93,4.1.14,it,j6lte,2019-02-25T21:33:22Z,1551130402264,2019-02-25T21:33:22Z,1551130402264,5,,,,,, 80 | cat.app.lordofriddles,93,4.1.14,it,HWVTR,2019-02-25T21:46:26Z,1551131186952,2019-02-25T21:46:26Z,1551131186952,3,,Molto bello,,,,https://play.google.com/apps/publish?account=4894168828409330111#ReviewDetailsPlace:p=cat.app.lordofriddles&reviewid=gp:AOqpTOGpOr-e-52FXIx_falShRNXZjAqj4gLkvLNMC06u_9WRidpfALf-3ONvXx9Twds4fAvxHr9Vffod0svUPQ 81 | cat.app.lordofriddles,93,4.1.14,it,HWCUN-L6735,2019-02-26T07:47:48Z,1551167268978,2019-02-26T07:47:48Z,1551167268978,4,,Un gioco veramente avvincente e molto utile per allenare la mente!,,,,https://play.google.com/apps/publish?account=4894168828409330111#ReviewDetailsPlace:p=cat.app.lordofriddles&reviewid=gp:AOqpTOFs-WijU3NX4JEpgAme6ga2nfAaHl_pu85DSmMe7S7mPe6_R9ZS77xn1Kks0926eBEgqxDsriDeHOkCyMQ 82 | cat.app.lordofriddles,93,4.1.14,it,j5y17lte,2019-02-26T20:04:41Z,1551211481505,2019-02-26T20:04:41Z,1551211481505,4,,,,,, 83 | cat.app.lordofriddles,93,4.1.14,it,a5xelte,2019-02-27T12:01:17Z,1551268877982,2019-02-27T12:01:17Z,1551268877982,5,,,,,, 84 | cat.app.lordofriddles,93,4.1.14,it,HWWAS-H,2019-02-27T12:26:42Z,1551270402976,2019-02-27T12:26:42Z,1551270402976,4,,,,,, 85 | cat.app.lordofriddles,93,4.1.14,it,HWMYA-L6737,2019-02-27T17:34:47Z,1551288887264,2019-02-27T17:34:47Z,1551288887264,5,,bello,,,,https://play.google.com/apps/publish?account=4894168828409330111#ReviewDetailsPlace:p=cat.app.lordofriddles&reviewid=gp:AOqpTOFD7WDDTxaQ84A2H4MiirpreJovvs33eSxZPM4S805fdc4s3L8lAk2xgKA1wt84BOpglBx_sQRKgoqfczI 86 | cat.app.lordofriddles,93,4.1.14,it,HWLLD-H,2019-02-27T19:50:05Z,1551297005799,2019-02-27T19:50:05Z,1551297005799,4,,,,,, 87 | cat.app.lordofriddles,93,4.1.14,it,j3y17lte,2019-02-28T15:04:28Z,1551366268002,2019-02-28T15:04:28Z,1551366268002,5,,,,,, 88 | -------------------------------------------------------------------------------- /02 - Operare su file di testo con Python/operare_sulle_stringhe.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "colab_type": "text", 7 | "id": "view-in-github" 8 | }, 9 | "source": [ 10 | "\"Open" 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "metadata": { 16 | "colab_type": "text", 17 | "id": "I1PPWriTtctt" 18 | }, 19 | "source": [ 20 | "# Operare sulle stringhe in Python\n", 21 | "\n", 22 | "In questo notebook vederemo alcune funzioni utili che Python ci mette a disposizione per operare sulle stringhe.\n", 23 | "
\n", 24 | "\n", 25 | "## Il tipo String\n", 26 | "In Python una stringa è una sequenza di caratteri immutabile, cosa vuol dire questo ? Che possiamo accedere a elementi e sotto-sequenze di una stringa utilizzando **l'indexing** e lo **slicing** ma non possiamo modificarne i valori." 27 | ] 28 | }, 29 | { 30 | "cell_type": "code", 31 | "execution_count": 1, 32 | "metadata": {}, 33 | "outputs": [], 34 | "source": [ 35 | "import time" 36 | ] 37 | }, 38 | { 39 | "cell_type": "code", 40 | "execution_count": null, 41 | "metadata": {}, 42 | "outputs": [], 43 | "source": [ 44 | "time." 45 | ] 46 | }, 47 | { 48 | "cell_type": "code", 49 | "execution_count": 0, 50 | "metadata": { 51 | "colab": { 52 | "base_uri": "https://localhost:8080/", 53 | "height": 120 54 | }, 55 | "colab_type": "code", 56 | "id": "kAlcRiXLtakM", 57 | "outputId": "fdc063c0-5cdf-4c21-a26f-8244132aae93" 58 | }, 59 | "outputs": [ 60 | { 61 | "name": "stdout", 62 | "output_type": "stream", 63 | "text": [ 64 | "ProfessionAI spacca\n", 65 | "P\n", 66 | "a\n", 67 | "Pro\n", 68 | "fe\n", 69 | "ProfessionAI spac\n" 70 | ] 71 | } 72 | ], 73 | "source": [ 74 | "# Definiamo una stringa\n", 75 | "my_string =\"ProfessionAI spacca\"\n", 76 | "print(my_string)\n", 77 | "\n", 78 | "# Stampiamo solo il primo carattere\n", 79 | "print(my_string[0]) # indexing\n", 80 | "\n", 81 | "# Stampiamo solo l'ultimo carattere\n", 82 | "print(my_string[-1])\n", 83 | "\n", 84 | "# Stampiamo i primi 3 caratteri\n", 85 | "print(my_string[:3]) # slicing\n", 86 | "\n", 87 | "# Stampiamo 4 e 5 carattere\n", 88 | "print(my_string[3:5])\n", 89 | "\n", 90 | "# Stampiam tutto tranne gli ultimi due caratteri\n", 91 | "print(my_string[:-2])\n" 92 | ] 93 | }, 94 | { 95 | "cell_type": "markdown", 96 | "metadata": { 97 | "colab_type": "text", 98 | "id": "9TRFu4i4vkiI" 99 | }, 100 | "source": [ 101 | "Il tenativo di modificare uno o più caratteri di una stringa genererà un'eccezione." 102 | ] 103 | }, 104 | { 105 | "cell_type": "code", 106 | "execution_count": 0, 107 | "metadata": { 108 | "colab": { 109 | "base_uri": "https://localhost:8080/", 110 | "height": 164 111 | }, 112 | "colab_type": "code", 113 | "id": "JrdcLVJUvbJR", 114 | "outputId": "ebc36961-ad41-475c-9177-43ed760697eb" 115 | }, 116 | "outputs": [ 117 | { 118 | "ename": "TypeError", 119 | "evalue": "ignored", 120 | "output_type": "error", 121 | "traceback": [ 122 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 123 | "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", 124 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mmy_string\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m\"F\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", 125 | "\u001b[0;31mTypeError\u001b[0m: 'str' object does not support item assignment" 126 | ] 127 | } 128 | ], 129 | "source": [ 130 | "my_string[0] = \"F\"" 131 | ] 132 | }, 133 | { 134 | "cell_type": "markdown", 135 | "metadata": { 136 | "colab_type": "text", 137 | "id": "hw5z5MS_wSeL" 138 | }, 139 | "source": [ 140 | "Trattandosi di una sequenza possiamo conoscere il numero di elementi, e quindi di caratteri, che compongono una stringa utilizzando la funzione *len*." 141 | ] 142 | }, 143 | { 144 | "cell_type": "code", 145 | "execution_count": 0, 146 | "metadata": { 147 | "colab": { 148 | "base_uri": "https://localhost:8080/", 149 | "height": 34 150 | }, 151 | "colab_type": "code", 152 | "id": "8a34C420wX_M", 153 | "outputId": "dcb7db29-e43e-4fa6-fcc3-d02bb1cc2b2f" 154 | }, 155 | "outputs": [ 156 | { 157 | "data": { 158 | "text/plain": [ 159 | "19" 160 | ] 161 | }, 162 | "execution_count": 3, 163 | "metadata": { 164 | "tags": [] 165 | }, 166 | "output_type": "execute_result" 167 | } 168 | ], 169 | "source": [ 170 | "len(my_string)" 171 | ] 172 | }, 173 | { 174 | "cell_type": "markdown", 175 | "metadata": { 176 | "colab_type": "text", 177 | "id": "0rfqOZD7wCUx" 178 | }, 179 | "source": [ 180 | "## Metodi utili" 181 | ] 182 | }, 183 | { 184 | "cell_type": "markdown", 185 | "metadata": { 186 | "colab_type": "text", 187 | "id": "4a46K1ravujC" 188 | }, 189 | "source": [ 190 | "Come tutte i tipi buil-in di Python, le stringhe sono oggetti e quindi hanno dei metodi, puoi trovare la lista completa dei metodi [a questo link](https://www.w3schools.com/python/python_ref_string.asp), vediamo insieme i più utili. \n", 191 | "

\n", 192 | "Possiamo convertire i caratteri di una stringa in minuscolo/maiuscolo utilizzando i metodi *lower/upper*." 193 | ] 194 | }, 195 | { 196 | "cell_type": "code", 197 | "execution_count": 0, 198 | "metadata": { 199 | "colab": { 200 | "base_uri": "https://localhost:8080/", 201 | "height": 51 202 | }, 203 | "colab_type": "code", 204 | "id": "m6VLxFjYvtVS", 205 | "outputId": "336c4941-bcb1-4ffd-c8dd-59d9ea65ad7e" 206 | }, 207 | "outputs": [ 208 | { 209 | "name": "stdout", 210 | "output_type": "stream", 211 | "text": [ 212 | "Tutto minuscolo: professionai spacca\n", 213 | "Tutto maiuscolo: PROFESSIONAI SPACCA\n" 214 | ] 215 | } 216 | ], 217 | "source": [ 218 | "my_string =\"ProfessionAI spacca\"\n", 219 | "\n", 220 | "my_string_lower = my_string.lower()\n", 221 | "print(\"Tutto minuscolo: %s\" % my_string_lower)\n", 222 | "\n", 223 | "my_string_upper = my_string.upper()\n", 224 | "print(\"Tutto maiuscolo: %s\" % my_string_upper)" 225 | ] 226 | }, 227 | { 228 | "cell_type": "markdown", 229 | "metadata": { 230 | "colab_type": "text", 231 | "id": "ZgjxCGIiwxAs" 232 | }, 233 | "source": [ 234 | "Possiamo dividere le parole in una stringa utilizzando il metodo *split()*, il risultato sarà una lista con le singole parole." 235 | ] 236 | }, 237 | { 238 | "cell_type": "code", 239 | "execution_count": 3, 240 | "metadata": { 241 | "colab": { 242 | "base_uri": "https://localhost:8080/", 243 | "height": 71 244 | }, 245 | "colab_type": "code", 246 | "id": "RDeS4Q9Twnpo", 247 | "outputId": "3ec1cf8a-b4d2-439e-a95b-107de45a6cdb" 248 | }, 249 | "outputs": [ 250 | { 251 | "name": "stdout", 252 | "output_type": "stream", 253 | "text": [ 254 | "['Oggi', 'è', 'una', 'stupenda', 'giornata', 'per', 'studiare', 'Natural', 'Language', 'Processing']\n", 255 | "\n" 256 | ] 257 | } 258 | ], 259 | "source": [ 260 | "my_string = \"Oggi è una stupenda giornata per studiare Natural Language Processing\"\n", 261 | "\n", 262 | "words_list = my_string.split()\n", 263 | "print(words_list)\n", 264 | "print(type(words_list))" 265 | ] 266 | }, 267 | { 268 | "cell_type": "markdown", 269 | "metadata": { 270 | "colab_type": "text", 271 | "id": "nyZtTQ2Dy0S4" 272 | }, 273 | "source": [ 274 | "Come possiamo fare la trasformazione inversa ? Cioè passare da una lista di parole ad una stringa ? Lo possiamo fare usando il metodo *join()* che prende in input una lista di stringhe e genera un'unica stringa i cui elementi della lista sono separati dalla stringa (più facile a farsi che a dirsi)." 275 | ] 276 | }, 277 | { 278 | "cell_type": "code", 279 | "execution_count": 5, 280 | "metadata": { 281 | "colab": { 282 | "base_uri": "https://localhost:8080/", 283 | "height": 34 284 | }, 285 | "colab_type": "code", 286 | "id": "2xdMaC04yzqd", 287 | "outputId": "c9039186-227a-44e3-e349-4bdd50fd8e11" 288 | }, 289 | "outputs": [ 290 | { 291 | "name": "stdout", 292 | "output_type": "stream", 293 | "text": [ 294 | "Oggi è una stupenda giornata per studiare Natural Language Processing\n" 295 | ] 296 | } 297 | ], 298 | "source": [ 299 | "my_string = \" \".join(words_list)\n", 300 | "print(my_string)" 301 | ] 302 | }, 303 | { 304 | "cell_type": "code", 305 | "execution_count": 6, 306 | "metadata": { 307 | "colab": { 308 | "base_uri": "https://localhost:8080/", 309 | "height": 71 310 | }, 311 | "colab_type": "code", 312 | "id": "OINRIKJIzo5d", 313 | "outputId": "3c62408a-ef23-4a17-8ac7-dca414dfd458" 314 | }, 315 | "outputs": [ 316 | { 317 | "name": "stdout", 318 | "output_type": "stream", 319 | "text": [ 320 | "Oggi_è_una_stupenda_giornata_per_studiare_Natural_Language_Processing\n", 321 | "Oggi-PASSO-è-PASSO-una-PASSO-stupenda-PASSO-giornata-PASSO-per-PASSO-studiare-PASSO-Natural-PASSO-Language-PASSO-Processing\n" 322 | ] 323 | } 324 | ], 325 | "source": [ 326 | "my_string = \"_\".join(words_list)\n", 327 | "print(my_string)\n", 328 | "\n", 329 | "my_string = \"-PASSO-\".join(words_list)\n", 330 | "print(my_string)" 331 | ] 332 | }, 333 | { 334 | "cell_type": "markdown", 335 | "metadata": { 336 | "colab_type": "text", 337 | "id": "k0KOn9j_zhGN" 338 | }, 339 | "source": [ 340 | "In questo caso abbiamo (ovviamente) usato uno spazio per separare le stringhe, ma avremmo potuto fare la stessa cosa con qualsiasi carattere o stringa." 341 | ] 342 | }, 343 | { 344 | "cell_type": "markdown", 345 | "metadata": { 346 | "colab_type": "text", 347 | "id": "tculJJpnxRdO" 348 | }, 349 | "source": [ 350 | "Possiamo anche dividere le stringhe per un **pattern** definito da noi, semplicemente passano tale pattern come argomento del metdo *split(pattern)*, ad esempio possiamo dividerla per frasi passando un punto." 351 | ] 352 | }, 353 | { 354 | "cell_type": "code", 355 | "execution_count": 0, 356 | "metadata": { 357 | "colab": { 358 | "base_uri": "https://localhost:8080/", 359 | "height": 51 360 | }, 361 | "colab_type": "code", 362 | "id": "yqCmMOMAxKs9", 363 | "outputId": "51ae56c6-36c2-4064-a441-dd41f0385e7f" 364 | }, 365 | "outputs": [ 366 | { 367 | "name": "stdout", 368 | "output_type": "stream", 369 | "text": [ 370 | "['Oggi è una stupenda giornata per studiare Natural Language Processing', \" Poi c'è Giuseppe che è davvero bravo\", ' Peccato che è antipatico']\n", 371 | "\n" 372 | ] 373 | } 374 | ], 375 | "source": [ 376 | "my_string = \"Oggi è una stupenda giornata per studiare Natural Language Processing. Poi c'è Giuseppe che è davvero bravo. Peccato che è antipatico\"\n", 377 | "sentences_list = my_string.split(\".\")\n", 378 | "\n", 379 | "print(sentences_list)\n", 380 | "print(type(sentences_list))" 381 | ] 382 | }, 383 | { 384 | "cell_type": "markdown", 385 | "metadata": { 386 | "colab_type": "text", 387 | "id": "MscgTf7I00tL" 388 | }, 389 | "source": [ 390 | "Possiamo contare il numero di volte che una sotto-stringa compare in una stringa usando il metodo *count(substring)*" 391 | ] 392 | }, 393 | { 394 | "cell_type": "code", 395 | "execution_count": 0, 396 | "metadata": { 397 | "colab": { 398 | "base_uri": "https://localhost:8080/", 399 | "height": 34 400 | }, 401 | "colab_type": "code", 402 | "id": "Y3O4h2c806li", 403 | "outputId": "c0e05fd9-730d-4b08-8bc2-799d90596f11" 404 | }, 405 | "outputs": [ 406 | { 407 | "name": "stdout", 408 | "output_type": "stream", 409 | "text": [ 410 | "La parola 'è' compare 4 volte\n" 411 | ] 412 | } 413 | ], 414 | "source": [ 415 | "sub_count = my_string.count('è')\n", 416 | "print(\"La parola 'è' compare %d volte\" % sub_count)" 417 | ] 418 | }, 419 | { 420 | "cell_type": "markdown", 421 | "metadata": { 422 | "colab_type": "text", 423 | "id": "nZFWfvTfyh8p" 424 | }, 425 | "source": [ 426 | "Possiamo sostituire una parola o una sotto-stringa della stringa utilizzando il metodo *replace(old, new)*, passandogli la sotto-stringa da sostituire e quella con la quale effettuare la sostituzione. Possiamo utilizzare questo stesso metodo per rimuovere una sotto-stringa dalla stringa passando una stringa vuota come secondo argomento." 427 | ] 428 | }, 429 | { 430 | "cell_type": "code", 431 | "execution_count": 0, 432 | "metadata": { 433 | "colab": { 434 | "base_uri": "https://localhost:8080/", 435 | "height": 51 436 | }, 437 | "colab_type": "code", 438 | "id": "zj061ESBzGkA", 439 | "outputId": "270ebe9d-2e7c-4ba0-9740-5ad4ad735bc2" 440 | }, 441 | "outputs": [ 442 | { 443 | "name": "stdout", 444 | "output_type": "stream", 445 | "text": [ 446 | "Oggi è una stupenda giornata per studiare Natural Language Processing. E c'è Giuseppe è davvero bravo. Peccato è antipatico\n", 447 | "Oggi è una stupenda giornata per studiare Natural Language Processing. E c'è Giuseppe è davvero bravo. Peccato è antipatico\n" 448 | ] 449 | } 450 | ], 451 | "source": [ 452 | "# sostuiamo la parola 'Poi' con 'E'\n", 453 | "# per tutte le occorrenze di 'Poi' nella stringa\n", 454 | "my_string = my_string.replace(\"Poi\",\"E\")\n", 455 | "print(my_string)\n", 456 | "\n", 457 | "# Rimuoviamo tutte le occorrenze di 'che'\n", 458 | "my_string = my_string.replace(\" che\",\"\") # rimuoviamo anche lo spazio prima della parola\n", 459 | "print(my_string)" 460 | ] 461 | }, 462 | { 463 | "cell_type": "markdown", 464 | "metadata": { 465 | "colab_type": "text", 466 | "id": "vgfBKkEiyBFz" 467 | }, 468 | "source": [ 469 | "Possiamo effettuare la ricerca di una parola o di una sotto-stringa utilizzando il metodo *find()* questo ritornerà l'indice della prima occorrenza del risultato, oppure -1 se non trova nulla. Possiamo utilizzare tale metodo in combinazione con lo slicing per estrarre una sottostringa dalla stringa." 470 | ] 471 | }, 472 | { 473 | "cell_type": "code", 474 | "execution_count": 0, 475 | "metadata": { 476 | "colab": { 477 | "base_uri": "https://localhost:8080/", 478 | "height": 68 479 | }, 480 | "colab_type": "code", 481 | "id": "b6BcHQ-9x0Y_", 482 | "outputId": "38ffcf6e-5499-4080-d53f-bd6eedbddbea" 483 | }, 484 | "outputs": [ 485 | { 486 | "name": "stdout", 487 | "output_type": "stream", 488 | "text": [ 489 | "Occorrenza di 'E' trovata in posizione 71\n", 490 | "E c'è Giuseppe è davvero bravo. Peccato è antipatico\n", 491 | "E c'è Giuseppe è davvero bravo\n" 492 | ] 493 | } 494 | ], 495 | "source": [ 496 | "start_index = my_string.find(\"E\")\n", 497 | "print(\"Occorrenza di 'E' trovata in posizione %d\" % start_index)\n", 498 | "\n", 499 | "my_substring = my_string[start_index:]\n", 500 | "print(my_substring)\n", 501 | "\n", 502 | "end_index = my_substring.find(\".\")\n", 503 | "my_substring = my_substring[:end_index]\n", 504 | "print(my_substring)" 505 | ] 506 | }, 507 | { 508 | "cell_type": "markdown", 509 | "metadata": { 510 | "colab_type": "text", 511 | "id": "Y-8uEfS13dmg" 512 | }, 513 | "source": [ 514 | "Se invece vogliamo conoscere l'indice dell'ultima occorrenza possiamo usare il metodo *rfind()*." 515 | ] 516 | }, 517 | { 518 | "cell_type": "code", 519 | "execution_count": 0, 520 | "metadata": { 521 | "colab": { 522 | "base_uri": "https://localhost:8080/", 523 | "height": 51 524 | }, 525 | "colab_type": "code", 526 | "id": "bGzU1pfY3lTw", 527 | "outputId": "c2e5fa4b-fcca-4414-8502-57b4662b05be" 528 | }, 529 | "outputs": [ 530 | { 531 | "name": "stdout", 532 | "output_type": "stream", 533 | "text": [ 534 | "18\n", 535 | "28\n" 536 | ] 537 | } 538 | ], 539 | "source": [ 540 | "my_string = \"Occhio per occhio dente per dente\"\n", 541 | "print(my_string.find('dente')) # prima occorrenza\n", 542 | "print(my_string.rfind('dente')) # ultima occorrenza b" 543 | ] 544 | }, 545 | { 546 | "cell_type": "markdown", 547 | "metadata": { 548 | "colab_type": "text", 549 | "id": "iOqyBSP72sWa" 550 | }, 551 | "source": [ 552 | "Gli ultimi metodi, che potrebbero sembrare inutili ma che in realtà sono davvero utili quando operiamo su corpus di testo, sono *lstrip() e strip()*, che rispettivamente rimuovo gli spazi dall'inizio della stringa e dall'inizio e la fine della stringa." 553 | ] 554 | }, 555 | { 556 | "cell_type": "code", 557 | "execution_count": 0, 558 | "metadata": { 559 | "colab": { 560 | "base_uri": "https://localhost:8080/", 561 | "height": 51 562 | }, 563 | "colab_type": "code", 564 | "id": "n6XSw21W0Nvi", 565 | "outputId": "e4122a46-4023-47c6-bb8b-4b7598cf354a" 566 | }, 567 | "outputs": [ 568 | { 569 | "name": "stdout", 570 | "output_type": "stream", 571 | "text": [ 572 | "\"Questo è un test \"\n", 573 | "\"Questo è un test\"\n" 574 | ] 575 | } 576 | ], 577 | "source": [ 578 | "string = \" Questo è un test \"\n", 579 | "print('\"'+string.lstrip()+'\"')\n", 580 | "print('\"'+string.strip()+'\"')\n", 581 | "\n", 582 | "# ricorda di effettuare l'assegnazione\n", 583 | "# per modificare la stringa\n", 584 | "# string = string.strip()" 585 | ] 586 | }, 587 | { 588 | "cell_type": "code", 589 | "execution_count": 1, 590 | "metadata": { 591 | "colab": { 592 | "base_uri": "https://localhost:8080/", 593 | "height": 34 594 | }, 595 | "colab_type": "code", 596 | "id": "atq3UqNRyf-U", 597 | "outputId": "0844075f-fb08-4090-a51e-bc841b84c3a7" 598 | }, 599 | "outputs": [ 600 | { 601 | "data": { 602 | "text/plain": [ 603 | "'-'" 604 | ] 605 | }, 606 | "execution_count": 1, 607 | "metadata": { 608 | "tags": [] 609 | }, 610 | "output_type": "execute_result" 611 | } 612 | ], 613 | "source": [] 614 | }, 615 | { 616 | "cell_type": "code", 617 | "execution_count": 0, 618 | "metadata": { 619 | "colab": {}, 620 | "colab_type": "code", 621 | "id": "Taq9u48Vyi1w" 622 | }, 623 | "outputs": [], 624 | "source": [] 625 | }, 626 | { 627 | "cell_type": "markdown", 628 | "metadata": { 629 | "colab_type": "text", 630 | "id": "yIkfxX7-2JNp" 631 | }, 632 | "source": [ 633 | "## Link utili\n", 634 | "- https://www.w3schools.com/python/python_ref_string.asp" 635 | ] 636 | }, 637 | { 638 | "cell_type": "code", 639 | "execution_count": 0, 640 | "metadata": { 641 | "colab": {}, 642 | "colab_type": "code", 643 | "id": "6ERzMkmm2MtZ" 644 | }, 645 | "outputs": [], 646 | "source": [] 647 | } 648 | ], 649 | "metadata": { 650 | "colab": { 651 | "include_colab_link": true, 652 | "name": "operare_sulle_stringhe.ipynb", 653 | "provenance": [], 654 | "version": "0.3.2" 655 | }, 656 | "kernelspec": { 657 | "display_name": "Python 3", 658 | "language": "python", 659 | "name": "python3" 660 | }, 661 | "language_info": { 662 | "codemirror_mode": { 663 | "name": "ipython", 664 | "version": 3 665 | }, 666 | "file_extension": ".py", 667 | "mimetype": "text/x-python", 668 | "name": "python", 669 | "nbconvert_exporter": "python", 670 | "pygments_lexer": "ipython3", 671 | "version": "3.6.5" 672 | } 673 | }, 674 | "nbformat": 4, 675 | "nbformat_minor": 1 676 | } 677 | -------------------------------------------------------------------------------- /04 - Preprocessing del testo/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProfAI/nlp00/bb5e60ccc24e536a0927f544d4f903df03624b85/04 - Preprocessing del testo/.DS_Store -------------------------------------------------------------------------------- /04 - Preprocessing del testo/codifica_testo.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "name": "codifica_testo.ipynb", 7 | "version": "0.3.2", 8 | "provenance": [], 9 | "include_colab_link": true 10 | }, 11 | "kernelspec": { 12 | "name": "python3", 13 | "display_name": "Python 3" 14 | } 15 | }, 16 | "cells": [ 17 | { 18 | "cell_type": "markdown", 19 | "metadata": { 20 | "id": "view-in-github", 21 | "colab_type": "text" 22 | }, 23 | "source": [ 24 | "\"Open" 25 | ] 26 | }, 27 | { 28 | "cell_type": "markdown", 29 | "metadata": { 30 | "id": "00dbcadfetQ6", 31 | "colab_type": "text" 32 | }, 33 | "source": [ 34 | "# Codifica del testo\n", 35 | "In questo notebook vedremo come implementare le due tecniche principali per la codifica del testo in numeri, **Bag of Words** e **TF-IDF**." 36 | ] 37 | }, 38 | { 39 | "cell_type": "markdown", 40 | "metadata": { 41 | "id": "PI6A9DW7ev_8", 42 | "colab_type": "text" 43 | }, 44 | "source": [ 45 | "## Bag of Words\n", 46 | "Il modello Bag of Words consiste nel creare un vocabolario di tutte le parole presenti all'interno del nostro corpus di testo, per poi contare quante volte ognuna di esse compare all'interno di un documento. Dato che un singolo documento contiene solo una minuscola parte dell'intero vocabolario, il risultato del bag of words sarà una matrice sparsa, cioè una matrice composta per lo più da zeri.\n", 47 | "
\n", 48 | "Definiamo un piccolo corpus di testo che useremo per un'esempio." 49 | ] 50 | }, 51 | { 52 | "cell_type": "code", 53 | "metadata": { 54 | "id": "UkS9h37glx9t", 55 | "colab_type": "code", 56 | "colab": {} 57 | }, 58 | "source": [ 59 | "corpus = [\"la mamma prepara la pasta\", \"la nonna prepara la pizza\", \"papà guarda la mamma\"]" 60 | ], 61 | "execution_count": 0, 62 | "outputs": [] 63 | }, 64 | { 65 | "cell_type": "markdown", 66 | "metadata": { 67 | "id": "Cj3fZzQhwOSr", 68 | "colab_type": "text" 69 | }, 70 | "source": [ 71 | "Definiamo una funzione che estrae i tokens da ogni documento all'interno del corpus." 72 | ] 73 | }, 74 | { 75 | "cell_type": "code", 76 | "metadata": { 77 | "id": "mXxwHSfWwULt", 78 | "colab_type": "code", 79 | "colab": {} 80 | }, 81 | "source": [ 82 | "def corpus_tokenizer(corpus):\n", 83 | " tokens = [sent.split() for sent in corpus] \n", 84 | " return tokens" 85 | ], 86 | "execution_count": 0, 87 | "outputs": [] 88 | }, 89 | { 90 | "cell_type": "markdown", 91 | "metadata": { 92 | "id": "3khXOBc2wWCL", 93 | "colab_type": "text" 94 | }, 95 | "source": [ 96 | "Definiamo una funzione che creerà il dizionario" 97 | ] 98 | }, 99 | { 100 | "cell_type": "code", 101 | "metadata": { 102 | "id": "c1k2ZjoEeQWU", 103 | "colab_type": "code", 104 | "colab": {} 105 | }, 106 | "source": [ 107 | "def build_vocab(corpus_tokens):\n", 108 | " \n", 109 | " # usando un set evitiamo\n", 110 | " # l'inserimento di duplicati\n", 111 | " vocab = set({})\n", 112 | " \n", 113 | " for tokens in corpus_tokens:\n", 114 | " for token in tokens:\n", 115 | " vocab.add(token)\n", 116 | " \n", 117 | " return list(vocab)" 118 | ], 119 | "execution_count": 0, 120 | "outputs": [] 121 | }, 122 | { 123 | "cell_type": "markdown", 124 | "metadata": { 125 | "id": "IwfSJfQiwnKM", 126 | "colab_type": "text" 127 | }, 128 | "source": [ 129 | "Adesso definiamo la funzione per eseguire il bag of words, la matrice risultate avrà un numero di righe pari al numero di documenti e un numero di colonne pari al numero di parole all'interno del vocabolario." 130 | ] 131 | }, 132 | { 133 | "cell_type": "code", 134 | "metadata": { 135 | "id": "ONJeQQ0GfRVl", 136 | "colab_type": "code", 137 | "colab": {} 138 | }, 139 | "source": [ 140 | "def bag_of_words(corpus):\n", 141 | "\n", 142 | " corpus_tokens = corpus_tokenizer(corpus)\n", 143 | " vocab = build_vocab(corpus_tokens)\n", 144 | " \n", 145 | " corpus_bow = []\n", 146 | "\n", 147 | " for tokens in corpus_tokens:\n", 148 | " sent_bow = []\n", 149 | " \n", 150 | " for word in vocab:\n", 151 | " sent_bow.append(tokens.count(word))\n", 152 | " corpus_bow.append(sent_bow)\n", 153 | " \n", 154 | " return corpus_bow, vocab" 155 | ], 156 | "execution_count": 0, 157 | "outputs": [] 158 | }, 159 | { 160 | "cell_type": "code", 161 | "metadata": { 162 | "id": "MRXI5ybUl483", 163 | "colab_type": "code", 164 | "outputId": "8a109100-aa73-4479-ddf7-9b2c2e37825f", 165 | "colab": { 166 | "base_uri": "https://localhost:8080/", 167 | "height": 218 168 | } 169 | }, 170 | "source": [ 171 | "corpus_bow, vocab = bag_of_words(corpus)\n", 172 | "\n", 173 | "print(\"Dizionario:\",vocab)\n", 174 | "print(\"\\n\")\n", 175 | "\n", 176 | "for sent, bow in zip(corpus, corpus_bow):\n", 177 | " print(\"Frase:\", sent)\n", 178 | " print(\"Bag of Words:\", bow)\n", 179 | " print(\"-------\")" 180 | ], 181 | "execution_count": 8, 182 | "outputs": [ 183 | { 184 | "output_type": "stream", 185 | "text": [ 186 | "Dizionario: ['mamma', 'nonna', 'prepara', 'pizza', 'papà', 'pasta', 'guarda', 'la']\n", 187 | "\n", 188 | "\n", 189 | "Frase: la mamma prepara la pasta\n", 190 | "Bag of Words: [1, 0, 1, 0, 0, 1, 0, 2]\n", 191 | "-------\n", 192 | "Frase: la nonna prepara la pizza\n", 193 | "Bag of Words: [0, 1, 1, 1, 0, 0, 0, 2]\n", 194 | "-------\n", 195 | "Frase: papà guarda la mamma\n", 196 | "Bag of Words: [1, 0, 0, 0, 1, 0, 1, 1]\n", 197 | "-------\n" 198 | ], 199 | "name": "stdout" 200 | } 201 | ] 202 | }, 203 | { 204 | "cell_type": "markdown", 205 | "metadata": { 206 | "id": "7cq2CsYsznpo", 207 | "colab_type": "text" 208 | }, 209 | "source": [ 210 | "## Bag of Words con Numpy\n", 211 | "Vediamo ora un'implementazione del bag of words che sfrutta numpy, importiamo la libreria, in questo caso abbiamo creato un vocabolario inverso che mappa una parola al corrispondente indice all'interno del vocabolario tramite un dizionario, così facendo possiamo eseguire la codifica iterando sui token piuttosto che su tutte le parole del vocabolario. Questa tecnica porta un risparmio di tempo notevole quando il vocabolario è di grandi dimensioni." 212 | ] 213 | }, 214 | { 215 | "cell_type": "code", 216 | "metadata": { 217 | "id": "5_LuyXFHzs25", 218 | "colab_type": "code", 219 | "colab": {} 220 | }, 221 | "source": [ 222 | "import numpy as np\n", 223 | "\n", 224 | "def bag_of_words_np(corpus):\n", 225 | "\n", 226 | " corpus_tokens = corpus_tokenizer(corpus)\n", 227 | " \n", 228 | " index_to_word = build_vocab(corpus_tokens)\n", 229 | " word_to_index = dict([(char, i) for i, char in enumerate(index_to_word)]) # creiamo il vocabolario inverso\n", 230 | " \n", 231 | " docs_count = len(corpus)\n", 232 | " vocab_size = len(index_to_word)\n", 233 | " \n", 234 | " corpus_bow = np.zeros((docs_count, vocab_size))\n", 235 | "\n", 236 | " for i, tokens in enumerate(corpus_tokens):\n", 237 | " for token in tokens:\n", 238 | " corpus_bow[i][word_to_index[token]]+=1 # usiamo il vocabolario inverso\n", 239 | " \n", 240 | " return corpus_bow, index_to_word" 241 | ], 242 | "execution_count": 0, 243 | "outputs": [] 244 | }, 245 | { 246 | "cell_type": "markdown", 247 | "metadata": { 248 | "id": "v1obNyd22ErB", 249 | "colab_type": "text" 250 | }, 251 | "source": [ 252 | "Testiamo la funzione, come vedi il risultato è lo stesso di prima." 253 | ] 254 | }, 255 | { 256 | "cell_type": "code", 257 | "metadata": { 258 | "id": "UbvszSfA0mgn", 259 | "colab_type": "code", 260 | "outputId": "36f01344-9e92-42ad-ee14-15a1c2b0afe8", 261 | "colab": { 262 | "base_uri": "https://localhost:8080/", 263 | "height": 218 264 | } 265 | }, 266 | "source": [ 267 | "corpus_bow, vocab = bag_of_words_np(corpus)\n", 268 | "\n", 269 | "print(\"Dizionario:\",vocab)\n", 270 | "print(\"\\n\")\n", 271 | "\n", 272 | "for sent, bow in zip(corpus, corpus_bow):\n", 273 | " print(\"Frase:\", sent)\n", 274 | " print(\"Bag of Words:\", bow)\n", 275 | " print(\"-------\")" 276 | ], 277 | "execution_count": 12, 278 | "outputs": [ 279 | { 280 | "output_type": "stream", 281 | "text": [ 282 | "Dizionario: ['prepara', 'guarda', 'pasta', 'la', 'nonna', 'mamma', 'pizza', 'papà']\n", 283 | "\n", 284 | "\n", 285 | "Frase: la mamma prepara la pasta\n", 286 | "Bag of Words: [1. 0. 1. 2. 0. 1. 0. 0.]\n", 287 | "-------\n", 288 | "Frase: la nonna prepara la pizza\n", 289 | "Bag of Words: [1. 0. 0. 2. 1. 0. 1. 0.]\n", 290 | "-------\n", 291 | "Frase: papà guarda la mamma\n", 292 | "Bag of Words: [0. 1. 0. 1. 0. 1. 0. 1.]\n", 293 | "-------\n" 294 | ], 295 | "name": "stdout" 296 | } 297 | ] 298 | }, 299 | { 300 | "cell_type": "markdown", 301 | "metadata": { 302 | "id": "MDVYEp5nhCrP", 303 | "colab_type": "text" 304 | }, 305 | "source": [ 306 | "## TF-IDF\n", 307 | "Il TF-IDF, abbreviazione di Term Frequency - Inverse Document Frequency è un modello simile al bag of words, ma che tende a penalizzare le parole comuni all'interno del corpus di testo e a dare maggiore importanza a quelle più rare.\n", 308 | "
\n", 309 | "Il TF-IDF è composto dai seguenti elementi:\n", 310 | "- **Term Frequency**: quante volte un termine appare all'interno di un documento.\n", 311 | "- **Document Frequency**: in quanti documenti appare un termine.\n", 312 | "- **Inverse Document Frequency**: è il logaritmo del rapporto tra il numero di documenti e il document frequency, più uno se vogliamo evitare che le parole presenti in ogni documento abbiamo un IDF di 0.\n", 313 | "\n", 314 | "Il TF-IDF è dato dal prodotto del Term Frequency e l'Inverse Document Frequency." 315 | ] 316 | }, 317 | { 318 | "cell_type": "code", 319 | "metadata": { 320 | "id": "yYi2qVJrnvYD", 321 | "colab_type": "code", 322 | "colab": {} 323 | }, 324 | "source": [ 325 | "corpus = [\"la mamma prepara la pasta\", \"la nonna prepara la pizza\", \"papà guarda la mamma\"]" 326 | ], 327 | "execution_count": 0, 328 | "outputs": [] 329 | }, 330 | { 331 | "cell_type": "code", 332 | "metadata": { 333 | "id": "im6FL2cmihsL", 334 | "colab_type": "code", 335 | "colab": {} 336 | }, 337 | "source": [ 338 | "from math import log\n", 339 | "\n", 340 | "def tf_idf(corpus):\n", 341 | " \n", 342 | " corpus_tokens = corpus_tokenizer(corpus)\n", 343 | " vocab = build_vocab(corpus_tokens)\n", 344 | "\n", 345 | " # Document Frequency\n", 346 | " \n", 347 | " df = [0]*len(vocab)\n", 348 | "\n", 349 | " for i,word in enumerate(vocab):\n", 350 | " for tokens in corpus_tokens:\n", 351 | " if(word in tokens):\n", 352 | " df[i]+=1\n", 353 | "\n", 354 | " # Inverse Document frequency\n", 355 | " \n", 356 | " docs_count = len(corpus)\n", 357 | " idf = [log(docs_count/i)+1 for i in df]\n", 358 | "\n", 359 | " # Term Frequency\n", 360 | " \n", 361 | " tf = []\n", 362 | "\n", 363 | " for tokens in corpus_tokens:\n", 364 | " tf_sent = []\n", 365 | " words_count = len(tokens)\n", 366 | " \n", 367 | " for word in vocab:\n", 368 | " tf_sent.append(tokens.count(word)/words_count)\n", 369 | " tf.append(tf_sent)\n", 370 | "\n", 371 | " #TF-IDF\n", 372 | " \n", 373 | " tf_idf = []\n", 374 | "\n", 375 | " for i in range(docs_count):\n", 376 | " tf_idf.append([tf_i*idf_i for tf_i,idf_i in zip(tf[i],idf)])\n", 377 | "\n", 378 | " return tf_idf, vocab" 379 | ], 380 | "execution_count": 0, 381 | "outputs": [] 382 | }, 383 | { 384 | "cell_type": "markdown", 385 | "metadata": { 386 | "id": "9ADfjwM33d9-", 387 | "colab_type": "text" 388 | }, 389 | "source": [ 390 | "Testiamo la nostra implementazione del TF-IDF." 391 | ] 392 | }, 393 | { 394 | "cell_type": "code", 395 | "metadata": { 396 | "id": "2Pn-dpVPmjYg", 397 | "colab_type": "code", 398 | "outputId": "b0154df4-95ed-4cc3-a8e3-d42af8556905", 399 | "colab": { 400 | "base_uri": "https://localhost:8080/", 401 | "height": 218 402 | } 403 | }, 404 | "source": [ 405 | "corpus_tfidf, vocab = tf_idf(corpus)\n", 406 | "\n", 407 | "print(\"Dizionario:\",vocab)\n", 408 | "print(\"\\n\")\n", 409 | "\n", 410 | "for sent, tfidf in zip(corpus, corpus_tfidf):\n", 411 | " print(\"Frase:\", sent)\n", 412 | " print(\"TF-IDF:\", tfidf)\n", 413 | " print(\"-------\")" 414 | ], 415 | "execution_count": 16, 416 | "outputs": [ 417 | { 418 | "output_type": "stream", 419 | "text": [ 420 | "Dizionario: ['prepara', 'guarda', 'pasta', 'la', 'nonna', 'mamma', 'pizza', 'papà']\n", 421 | "\n", 422 | "\n", 423 | "Frase: la mamma prepara la pasta\n", 424 | "TF-IDF: [0.2810930216216329, 0.0, 0.41972245773362205, 0.4, 0.0, 0.2810930216216329, 0.0, 0.0]\n", 425 | "-------\n", 426 | "Frase: la nonna prepara la pizza\n", 427 | "TF-IDF: [0.2810930216216329, 0.0, 0.0, 0.4, 0.41972245773362205, 0.0, 0.41972245773362205, 0.0]\n", 428 | "-------\n", 429 | "Frase: papà guarda la mamma\n", 430 | "TF-IDF: [0.0, 0.5246530721670275, 0.0, 0.25, 0.0, 0.3513662770270411, 0.0, 0.5246530721670275]\n", 431 | "-------\n" 432 | ], 433 | "name": "stdout" 434 | } 435 | ] 436 | }, 437 | { 438 | "cell_type": "markdown", 439 | "metadata": { 440 | "id": "aqU5cFK6qdUc", 441 | "colab_type": "text" 442 | }, 443 | "source": [ 444 | "##TF-IDF con Numpy\n", 445 | "Implementiamo il TF-IDF nuovamente con Numpy, utilizziamo anche in questo caso la tecnica del vocabolario inverso." 446 | ] 447 | }, 448 | { 449 | "cell_type": "code", 450 | "metadata": { 451 | "id": "d9_flwYHpJf9", 452 | "colab_type": "code", 453 | "colab": {} 454 | }, 455 | "source": [ 456 | "def np_tf_idf(corpus):\n", 457 | " \n", 458 | " corpus_tokens = corpus_tokenizer(corpus)\n", 459 | " \n", 460 | " index_to_word = build_vocab(corpus_tokens)\n", 461 | " word_to_index = dict([(char, i) for i, char in enumerate(index_to_word)]) # creiamo il vocabolario inverso\n", 462 | " \n", 463 | " vocab_size = len(index_to_word)\n", 464 | " docs_count = len(corpus)\n", 465 | " \n", 466 | " # Document Frequency\n", 467 | " \n", 468 | " df = np.zeros(vocab_size)\n", 469 | "\n", 470 | " for i,word in enumerate(index_to_word):\n", 471 | " for tokens in corpus_tokens:\n", 472 | " if(word in tokens):\n", 473 | " df[i]+=1\n", 474 | "\n", 475 | " # Inverse Document frequency\n", 476 | " \n", 477 | " idf = np.log(docs_count/df)+1\n", 478 | "\n", 479 | " # Term Frequency\n", 480 | " \n", 481 | " tf = np.zeros((docs_count, vocab_size))\n", 482 | " \n", 483 | " for i, tokens in enumerate(corpus_tokens):\n", 484 | " word_counts = len(tokens)\n", 485 | " for token in tokens:\n", 486 | " tf[i][word_to_index[token]]+=1 # usiamo il vocabolario inverso\n", 487 | " tf[i]/=word_counts\n", 488 | "\n", 489 | " #TF-IDF\n", 490 | " \n", 491 | " tf_idf = tf*idf\n", 492 | "\n", 493 | " return tf_idf, index_to_word" 494 | ], 495 | "execution_count": 0, 496 | "outputs": [] 497 | }, 498 | { 499 | "cell_type": "markdown", 500 | "metadata": { 501 | "id": "KU8wVfUm5Nmb", 502 | "colab_type": "text" 503 | }, 504 | "source": [ 505 | "Testiamo la nostra nuova implementazione." 506 | ] 507 | }, 508 | { 509 | "cell_type": "code", 510 | "metadata": { 511 | "id": "ohwqO7JitMzc", 512 | "colab_type": "code", 513 | "outputId": "43accc17-e7bb-4c92-a013-fdf62e155b51", 514 | "colab": { 515 | "base_uri": "https://localhost:8080/", 516 | "height": 269 517 | } 518 | }, 519 | "source": [ 520 | "corpus_tfidf, vocab = np_tf_idf(corpus)\n", 521 | "\n", 522 | "print(\"Dizionario:\",vocab)\n", 523 | "print(\"\\n\")\n", 524 | "\n", 525 | "for sent, tfidf in zip(corpus, corpus_tfidf):\n", 526 | " print(\"Frase:\", sent)\n", 527 | " print(\"TF-IDF:\", tfidf)\n", 528 | " print(\"-------\")" 529 | ], 530 | "execution_count": 18, 531 | "outputs": [ 532 | { 533 | "output_type": "stream", 534 | "text": [ 535 | "Dizionario: ['prepara', 'guarda', 'pasta', 'la', 'nonna', 'mamma', 'pizza', 'papà']\n", 536 | "\n", 537 | "\n", 538 | "Frase: la mamma prepara la pasta\n", 539 | "TF-IDF: [0.28109302 0. 0.41972246 0.4 0. 0.28109302\n", 540 | " 0. 0. ]\n", 541 | "-------\n", 542 | "Frase: la nonna prepara la pizza\n", 543 | "TF-IDF: [0.28109302 0. 0. 0.4 0.41972246 0.\n", 544 | " 0.41972246 0. ]\n", 545 | "-------\n", 546 | "Frase: papà guarda la mamma\n", 547 | "TF-IDF: [0. 0.52465307 0. 0.25 0. 0.35136628\n", 548 | " 0. 0.52465307]\n", 549 | "-------\n" 550 | ], 551 | "name": "stdout" 552 | } 553 | ] 554 | }, 555 | { 556 | "cell_type": "markdown", 557 | "metadata": { 558 | "id": "yg-U-7Ty5PzB", 559 | "colab_type": "text" 560 | }, 561 | "source": [ 562 | "Il risultato è lo stesso di prima, ma questa implementazione performa meglio nel caso di corpus di testo molto grandi." 563 | ] 564 | } 565 | ] 566 | } -------------------------------------------------------------------------------- /04 - Preprocessing del testo/text_preprocessing_spacy.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "name": "text_preprocessing_spacy.ipynb", 7 | "version": "0.3.2", 8 | "provenance": [], 9 | "include_colab_link": true 10 | }, 11 | "kernelspec": { 12 | "name": "python3", 13 | "display_name": "Python 3" 14 | } 15 | }, 16 | "cells": [ 17 | { 18 | "cell_type": "markdown", 19 | "metadata": { 20 | "id": "view-in-github", 21 | "colab_type": "text" 22 | }, 23 | "source": [ 24 | "\"Open" 25 | ] 26 | }, 27 | { 28 | "metadata": { 29 | "id": "r9lp6Cf0pa2M", 30 | "colab_type": "text" 31 | }, 32 | "cell_type": "markdown", 33 | "source": [ 34 | "# Preprocessing del testo con Spacy\n", 35 | "\n", 36 | "In questo notebook vedremo come possiamo eseguire la tokenizzazione, la rimozione delle stopwords e la lemmatizzazione con [Spacy](https://spacy.io/), una libreria Python per il natural language processing ad alte prestazioni progettata per essere utilizzata in produzione.\n", 37 | "Spacy adotta una politica del tipo \"pochi ma buoni\", cioè implementa solamente la tecnica più peformante per ogni tipo di operazione, per questo motivo spacy non implementa una funzione per lo stemming dato che queste solitamente portano a risultati più scarsi rispetto alla lemmatizzazione. " 38 | ] 39 | }, 40 | { 41 | "metadata": { 42 | "id": "B0MMYiLYt-kH", 43 | "colab_type": "text" 44 | }, 45 | "cell_type": "markdown", 46 | "source": [ 47 | "## Caricare un modello linguistico\n", 48 | "Per utilizzare Spacy dobbiamo prima scaricare e installare il modello per la lingua che vogliamo utilizzare, Spacy supporta oltre 49 lingue, [qui puoi trovare l'elenco completo con i relativi modelli](https://spacy.io/usage/models). Scarichiamo ed installiamo il modello per la lingua inglese." 49 | ] 50 | }, 51 | { 52 | "metadata": { 53 | "id": "-gM65Yu2pWdB", 54 | "colab_type": "code", 55 | "outputId": "8b1bf78d-5ca5-49f2-89c6-7ddb5cad2de6", 56 | "colab": { 57 | "base_uri": "https://localhost:8080/", 58 | "height": 34 59 | } 60 | }, 61 | "cell_type": "code", 62 | "source": [ 63 | "import spacy\n", 64 | "\n", 65 | "nlp = spacy.load(\"en_core_web_sm\")\n", 66 | "type(nlp)" 67 | ], 68 | "execution_count": 1, 69 | "outputs": [ 70 | { 71 | "output_type": "execute_result", 72 | "data": { 73 | "text/plain": [ 74 | "spacy.lang.en.English" 75 | ] 76 | }, 77 | "metadata": { 78 | "tags": [] 79 | }, 80 | "execution_count": 1 81 | } 82 | ] 83 | }, 84 | { 85 | "metadata": { 86 | "id": "lZC5qfmCu0W_", 87 | "colab_type": "text" 88 | }, 89 | "cell_type": "markdown", 90 | "source": [ 91 | "L'output della funzione load è un'oggetto di tipo *Language*, che possiamo utilizzare per processare il nostro testo." 92 | ] 93 | }, 94 | { 95 | "metadata": { 96 | "id": "Ry8GhJMAum-D", 97 | "colab_type": "code", 98 | "outputId": "402bc671-6816-4c0e-b16c-210518de1f9c", 99 | "colab": { 100 | "base_uri": "https://localhost:8080/", 101 | "height": 34 102 | } 103 | }, 104 | "cell_type": "code", 105 | "source": [ 106 | "doc = nlp(\"That's was a great play by you. I hope to play with you again.\")\n", 107 | "type(doc)" 108 | ], 109 | "execution_count": 2, 110 | "outputs": [ 111 | { 112 | "output_type": "execute_result", 113 | "data": { 114 | "text/plain": [ 115 | "spacy.tokens.doc.Doc" 116 | ] 117 | }, 118 | "metadata": { 119 | "tags": [] 120 | }, 121 | "execution_count": 2 122 | } 123 | ] 124 | }, 125 | { 126 | "metadata": { 127 | "id": "G5Ej3mQ7vmWN", 128 | "colab_type": "text" 129 | }, 130 | "cell_type": "markdown", 131 | "source": [ 132 | "doc è un oggetto contentente il testo già processato, cosa vuol dire questo ? Che operazioni come tokenizzazione e lemmatizzazione sono già state eseguite e possiamo utilizzare degli appositi attributi per accedere ai risultati." 133 | ] 134 | }, 135 | { 136 | "metadata": { 137 | "id": "JqIaTSlyv7rf", 138 | "colab_type": "text" 139 | }, 140 | "cell_type": "markdown", 141 | "source": [ 142 | "## Tokenizzazione\n", 143 | "Possiamo accedere ai singoli token utilizzando l'attributo *.text*" 144 | ] 145 | }, 146 | { 147 | "metadata": { 148 | "id": "jdpkGGOnwA0Y", 149 | "colab_type": "code", 150 | "outputId": "12baea65-575a-4730-e66d-1e3cd32676ca", 151 | "colab": { 152 | "base_uri": "https://localhost:8080/", 153 | "height": 377 154 | } 155 | }, 156 | "cell_type": "code", 157 | "source": [ 158 | "print(\"Primo token: %s\" % doc[0].text)\n", 159 | "print(\"Ultimo token: %s\" % doc[-1].text)\n", 160 | "\n", 161 | "print(\"\\n\")\n", 162 | "\n", 163 | "for token in doc:\n", 164 | " print(token.text)" 165 | ], 166 | "execution_count": 3, 167 | "outputs": [ 168 | { 169 | "output_type": "stream", 170 | "text": [ 171 | "Primo token: That\n", 172 | "Ultimo token: .\n", 173 | "\n", 174 | "\n", 175 | "That\n", 176 | "'s\n", 177 | "was\n", 178 | "a\n", 179 | "great\n", 180 | "play\n", 181 | "by\n", 182 | "you\n", 183 | ".\n", 184 | "I\n", 185 | "hope\n", 186 | "to\n", 187 | "play\n", 188 | "with\n", 189 | "you\n", 190 | "again\n", 191 | ".\n" 192 | ], 193 | "name": "stdout" 194 | } 195 | ] 196 | }, 197 | { 198 | "metadata": { 199 | "id": "CGev04zk_t8I", 200 | "colab_type": "text" 201 | }, 202 | "cell_type": "markdown", 203 | "source": [ 204 | "Possiamo accedere alle singoli frasi con l'attributo *.sents*.\n", 205 | "
\n", 206 | "**NOTA BENE:** *.sents* è un generatore, il chè è un'ottima cosa nel caso di testi molto lunghi, per accedere alla singola frase tramite indexing dobbiamo convertirlo in una lista." 207 | ] 208 | }, 209 | { 210 | "metadata": { 211 | "id": "Rswi-e8v_2Om", 212 | "colab_type": "code", 213 | "colab": { 214 | "base_uri": "https://localhost:8080/", 215 | "height": 51 216 | }, 217 | "outputId": "f3744e28-5901-4a7d-860d-303746269d8c" 218 | }, 219 | "cell_type": "code", 220 | "source": [ 221 | "for sent in doc.sents:\n", 222 | " print(sent.text)" 223 | ], 224 | "execution_count": 6, 225 | "outputs": [ 226 | { 227 | "output_type": "stream", 228 | "text": [ 229 | "That's was a great play by you.\n", 230 | "I hope to play with you again.\n" 231 | ], 232 | "name": "stdout" 233 | } 234 | ] 235 | }, 236 | { 237 | "metadata": { 238 | "id": "bghHedW5wx3I", 239 | "colab_type": "text" 240 | }, 241 | "cell_type": "markdown", 242 | "source": [ 243 | "## Lemmatizzazione\n", 244 | "Possiamo accedere al lemma di ogni parola tramite l'attributo *.lemma_*" 245 | ] 246 | }, 247 | { 248 | "metadata": { 249 | "id": "G7pBilBTw5AX", 250 | "colab_type": "code", 251 | "outputId": "c83b438b-99f5-4b68-cc68-2e043d91c5f8", 252 | "colab": { 253 | "base_uri": "https://localhost:8080/", 254 | "height": 326 255 | } 256 | }, 257 | "cell_type": "code", 258 | "source": [ 259 | "print(\"TOKEN\\t\\tLEMMA\")\n", 260 | "\n", 261 | "for token in doc:\n", 262 | " print(\"%s\\t\\t%s\" % (token.text, token.lemma_))" 263 | ], 264 | "execution_count": 7, 265 | "outputs": [ 266 | { 267 | "output_type": "stream", 268 | "text": [ 269 | "TOKEN\t\tLEMMA\n", 270 | "That\t\tthat\n", 271 | "'s\t\tbe\n", 272 | "was\t\tbe\n", 273 | "a\t\ta\n", 274 | "great\t\tgreat\n", 275 | "play\t\tplay\n", 276 | "by\t\tby\n", 277 | "you\t\t-PRON-\n", 278 | ".\t\t.\n", 279 | "I\t\t-PRON-\n", 280 | "hope\t\thope\n", 281 | "to\t\tto\n", 282 | "play\t\tplay\n", 283 | "with\t\twith\n", 284 | "you\t\t-PRON-\n", 285 | "again\t\tagain\n", 286 | ".\t\t.\n" 287 | ], 288 | "name": "stdout" 289 | } 290 | ] 291 | }, 292 | { 293 | "metadata": { 294 | "id": "V45mT4wmxG6h", 295 | "colab_type": "text" 296 | }, 297 | "cell_type": "markdown", 298 | "source": [ 299 | "**NOTA BENE**\n", 300 | "
\n", 301 | "Utilizzando l'attributo *.lemma*, quindi senza trattino basso (_), accediamo agli hash che codificano i lemma all'interno del dizionario di Spacy, non penso che tu avrai mai bisogno degli hash ma ti do questa informazione perché potresti scordarti di inserire il _ e non comprendere cosa sono tutti quei numeri che vengono fuori (esperienza personale :) )" 302 | ] 303 | }, 304 | { 305 | "metadata": { 306 | "id": "6kV10_71vcOc", 307 | "colab_type": "code", 308 | "outputId": "fb4d449f-fb89-4039-86f7-5bed02603a8f", 309 | "colab": { 310 | "base_uri": "https://localhost:8080/", 311 | "height": 326 312 | } 313 | }, 314 | "cell_type": "code", 315 | "source": [ 316 | "print(\"TOKEN\\t\\tLEMMA\\t\\tHASH\")\n", 317 | "\n", 318 | "for token in doc:\n", 319 | " print(\"%s\\t\\t%s\\t\\t%s\" % (token.text, token.lemma_, token.lemma))" 320 | ], 321 | "execution_count": 8, 322 | "outputs": [ 323 | { 324 | "output_type": "stream", 325 | "text": [ 326 | "TOKEN\t\tLEMMA\t\tHASH\n", 327 | "That\t\tthat\t\t4380130941430378203\n", 328 | "'s\t\tbe\t\t10382539506755952630\n", 329 | "was\t\tbe\t\t10382539506755952630\n", 330 | "a\t\ta\t\t11901859001352538922\n", 331 | "great\t\tgreat\t\t8881679497796027013\n", 332 | "play\t\tplay\t\t8228585124152053988\n", 333 | "by\t\tby\t\t16764210730586636600\n", 334 | "you\t\t-PRON-\t\t561228191312463089\n", 335 | ".\t\t.\t\t12646065887601541794\n", 336 | "I\t\t-PRON-\t\t561228191312463089\n", 337 | "hope\t\thope\t\t4429974322456332988\n", 338 | "to\t\tto\t\t3791531372978436496\n", 339 | "play\t\tplay\t\t8228585124152053988\n", 340 | "with\t\twith\t\t12510949447758279278\n", 341 | "you\t\t-PRON-\t\t561228191312463089\n", 342 | "again\t\tagain\t\t4502205900248518970\n", 343 | ".\t\t.\t\t12646065887601541794\n" 344 | ], 345 | "name": "stdout" 346 | } 347 | ] 348 | }, 349 | { 350 | "metadata": { 351 | "id": "kX4RTKLPyTGM", 352 | "colab_type": "text" 353 | }, 354 | "cell_type": "markdown", 355 | "source": [ 356 | "## Stop words\n", 357 | "Anche Spacy ci mette a disposizione un'elenco di stop words, più corposo di quello di NLTK." 358 | ] 359 | }, 360 | { 361 | "metadata": { 362 | "id": "E7NJG1zDxmhZ", 363 | "colab_type": "code", 364 | "outputId": "3290a02f-ff5b-43fe-e4cd-61bacfc7a0e3", 365 | "colab": { 366 | "base_uri": "https://localhost:8080/", 367 | "height": 51 368 | } 369 | }, 370 | "cell_type": "code", 371 | "source": [ 372 | "stopwords = nlp.Defaults.stop_words\n", 373 | "\n", 374 | "print(type(stopwords))\n", 375 | "\n", 376 | "print(\"Stop words totali: %d\" % len(stopwords))" 377 | ], 378 | "execution_count": 9, 379 | "outputs": [ 380 | { 381 | "output_type": "stream", 382 | "text": [ 383 | "\n", 384 | "Stop words totali: 305\n" 385 | ], 386 | "name": "stdout" 387 | } 388 | ] 389 | }, 390 | { 391 | "metadata": { 392 | "id": "ylPkeldSyrUx", 393 | "colab_type": "text" 394 | }, 395 | "cell_type": "markdown", 396 | "source": [ 397 | "Le stop words vengono tornate all'interno di un set, che è un formato conveniente per eseguire operazioni di sottrazione tra insiemi, se vogliamo utilizzare l'indexing per stampare una parte del set dobbiamo convertirlo in una lista. " 398 | ] 399 | }, 400 | { 401 | "metadata": { 402 | "id": "tpKlr8VgypCd", 403 | "colab_type": "code", 404 | "outputId": "45005cd5-9664-4514-b2fe-d401ce13b813", 405 | "colab": { 406 | "base_uri": "https://localhost:8080/", 407 | "height": 54 408 | } 409 | }, 410 | "cell_type": "code", 411 | "source": [ 412 | "print(\"Prime 10 stop words: %s\" % list(stopwords)[:10])" 413 | ], 414 | "execution_count": 10, 415 | "outputs": [ 416 | { 417 | "output_type": "stream", 418 | "text": [ 419 | "Prime 10 stop words: ['though', 'without', 'ever', 'wherever', 'own', 'who', 'always', 'become', 'something', 'seeming']\n" 420 | ], 421 | "name": "stdout" 422 | } 423 | ] 424 | }, 425 | { 426 | "metadata": { 427 | "id": "Xwn-jr-NzJW7", 428 | "colab_type": "text" 429 | }, 430 | "cell_type": "markdown", 431 | "source": [ 432 | "Con Spacy non abbiamo bisogno di effettuare la rimozione delle stop words manualmente, dato che anche questo viene eseguito durante la creazione dell'oggetto *Doc*, possiamo vedere se un token è una stop words con l'attributo *is_stop*." 433 | ] 434 | }, 435 | { 436 | "metadata": { 437 | "id": "OhwU3Epgy7Cg", 438 | "colab_type": "code", 439 | "outputId": "b1b38240-aaba-4022-d139-42732d7e3738", 440 | "colab": { 441 | "base_uri": "https://localhost:8080/", 442 | "height": 326 443 | } 444 | }, 445 | "cell_type": "code", 446 | "source": [ 447 | "print(\"TOKEN\\t\\tIS STOP\")\n", 448 | "\n", 449 | "for token in doc:\n", 450 | " print(\"%s\\t\\t%s\" % (token.text, token.is_stop))" 451 | ], 452 | "execution_count": 11, 453 | "outputs": [ 454 | { 455 | "output_type": "stream", 456 | "text": [ 457 | "TOKEN\t\tIS STOP\n", 458 | "That\t\tFalse\n", 459 | "'s\t\tFalse\n", 460 | "was\t\tTrue\n", 461 | "a\t\tTrue\n", 462 | "great\t\tFalse\n", 463 | "play\t\tFalse\n", 464 | "by\t\tTrue\n", 465 | "you\t\tTrue\n", 466 | ".\t\tFalse\n", 467 | "I\t\tFalse\n", 468 | "hope\t\tFalse\n", 469 | "to\t\tTrue\n", 470 | "play\t\tFalse\n", 471 | "with\t\tTrue\n", 472 | "you\t\tTrue\n", 473 | "again\t\tTrue\n", 474 | ".\t\tFalse\n" 475 | ], 476 | "name": "stdout" 477 | } 478 | ] 479 | }, 480 | { 481 | "metadata": { 482 | "id": "0aFU8F8Szxm-", 483 | "colab_type": "text" 484 | }, 485 | "cell_type": "markdown", 486 | "source": [ 487 | "Quindi per rimuovere le stop words possiamo controllare tale attributo." 488 | ] 489 | }, 490 | { 491 | "metadata": { 492 | "id": "BEasenskzHqa", 493 | "colab_type": "code", 494 | "outputId": "c394c420-a080-48bb-acb0-524c26f94c33", 495 | "colab": { 496 | "base_uri": "https://localhost:8080/", 497 | "height": 34 498 | } 499 | }, 500 | "cell_type": "code", 501 | "source": [ 502 | "tokens_filtered = []\n", 503 | "\n", 504 | "for token in doc:\n", 505 | " if(not token.is_stop):\n", 506 | " tokens_filtered.append(token)\n", 507 | "\n", 508 | "print(tokens_filtered)" 509 | ], 510 | "execution_count": 12, 511 | "outputs": [ 512 | { 513 | "output_type": "stream", 514 | "text": [ 515 | "[That, 's, great, play, ., I, hope, play, .]\n" 516 | ], 517 | "name": "stdout" 518 | } 519 | ] 520 | }, 521 | { 522 | "metadata": { 523 | "id": "dzZPEN7r0rQ-", 524 | "colab_type": "text" 525 | }, 526 | "cell_type": "markdown", 527 | "source": [ 528 | "## Un'esempio in Italiano\n", 529 | "Facciamo adesso un'esempio in italiano. Installiamo il modello per la lingua italiana." 530 | ] 531 | }, 532 | { 533 | "metadata": { 534 | "id": "21xGYssE0-eP", 535 | "colab_type": "code", 536 | "outputId": "98535640-3dca-4ce6-b033-ad1c0936e4be", 537 | "colab": { 538 | "base_uri": "https://localhost:8080/", 539 | "height": 260 540 | } 541 | }, 542 | "cell_type": "code", 543 | "source": [ 544 | "!python -m spacy download it_core_news_sm" 545 | ], 546 | "execution_count": 13, 547 | "outputs": [ 548 | { 549 | "output_type": "stream", 550 | "text": [ 551 | "Collecting it_core_news_sm==2.0.0 from https://github.com/explosion/spacy-models/releases/download/it_core_news_sm-2.0.0/it_core_news_sm-2.0.0.tar.gz#egg=it_core_news_sm==2.0.0\n", 552 | "\u001b[?25l Downloading https://github.com/explosion/spacy-models/releases/download/it_core_news_sm-2.0.0/it_core_news_sm-2.0.0.tar.gz (36.5MB)\n", 553 | "\u001b[K 100% |████████████████████████████████| 36.5MB 8.0MB/s \n", 554 | "\u001b[?25hInstalling collected packages: it-core-news-sm\n", 555 | " Running setup.py install for it-core-news-sm ... \u001b[?25ldone\n", 556 | "\u001b[?25hSuccessfully installed it-core-news-sm-2.0.0\n", 557 | "\n", 558 | "\u001b[93m Linking successful\u001b[0m\n", 559 | " /usr/local/lib/python3.6/dist-packages/it_core_news_sm -->\n", 560 | " /usr/local/lib/python3.6/dist-packages/spacy/data/it_core_news_sm\n", 561 | "\n", 562 | " You can now load the model via spacy.load('it_core_news_sm')\n", 563 | "\n" 564 | ], 565 | "name": "stdout" 566 | } 567 | ] 568 | }, 569 | { 570 | "metadata": { 571 | "id": "4YmRWaFw1FII", 572 | "colab_type": "text" 573 | }, 574 | "cell_type": "markdown", 575 | "source": [ 576 | "e carichiamolo" 577 | ] 578 | }, 579 | { 580 | "metadata": { 581 | "id": "M3-f9goW0HmG", 582 | "colab_type": "code", 583 | "outputId": "0e6a7d3e-676d-4755-eb02-604342d28dd9", 584 | "colab": { 585 | "base_uri": "https://localhost:8080/", 586 | "height": 34 587 | } 588 | }, 589 | "cell_type": "code", 590 | "source": [ 591 | "import spacy\n", 592 | "\n", 593 | "nlp = spacy.load(\"it_core_news_sm\")\n", 594 | "type(nlp)" 595 | ], 596 | "execution_count": 14, 597 | "outputs": [ 598 | { 599 | "output_type": "execute_result", 600 | "data": { 601 | "text/plain": [ 602 | "spacy.lang.it.Italian" 603 | ] 604 | }, 605 | "metadata": { 606 | "tags": [] 607 | }, 608 | "execution_count": 14 609 | } 610 | ] 611 | }, 612 | { 613 | "metadata": { 614 | "id": "LFDrDPoj1ISr", 615 | "colab_type": "text" 616 | }, 617 | "cell_type": "markdown", 618 | "source": [ 619 | "creiamo il documento e vediamo i tokens, i lemma e le stop words." 620 | ] 621 | }, 622 | { 623 | "metadata": { 624 | "id": "HJUit_tf052A", 625 | "colab_type": "code", 626 | "outputId": "a5972244-74d4-4412-e39f-22c9b98390dd", 627 | "colab": { 628 | "base_uri": "https://localhost:8080/", 629 | "height": 326 630 | } 631 | }, 632 | "cell_type": "code", 633 | "source": [ 634 | "doc = nlp(\"Oggi è una giornata afosa. Ho davvero voglia di una granita fresca\")\n", 635 | "\n", 636 | "print(\"FRASI\")\n", 637 | "\n", 638 | "\n", 639 | "print([sent for sent in doc.sents])\n", 640 | "print(\"\\n\")\n", 641 | "\n", 642 | "print(\"TOKEN\\t\\tLEMMA\\t\\tIS STOP\")\n", 643 | "\n", 644 | "\n", 645 | "for token in doc:\n", 646 | " print(\"%s\\t\\t%s\\t\\t%s\" % (token.text, token.lemma_, token.is_stop))" 647 | ], 648 | "execution_count": 23, 649 | "outputs": [ 650 | { 651 | "output_type": "stream", 652 | "text": [ 653 | "FRASI\n", 654 | "[Oggi è una giornata afosa., Ho davvero voglia di una granita fresca]\n", 655 | "\n", 656 | "\n", 657 | "TOKEN\t\tLEMMA\t\tIS STOP\n", 658 | "Oggi\t\tOggi\t\tFalse\n", 659 | "è\t\tessere\t\tFalse\n", 660 | "una\t\tuna\t\tTrue\n", 661 | "giornata\t\tgiornata\t\tFalse\n", 662 | "afosa\t\tafoso\t\tFalse\n", 663 | ".\t\t.\t\tFalse\n", 664 | "Ho\t\tHo\t\tFalse\n", 665 | "davvero\t\tdavvero\t\tFalse\n", 666 | "voglia\t\tvolere\t\tFalse\n", 667 | "di\t\tdi\t\tTrue\n", 668 | "una\t\tuna\t\tTrue\n", 669 | "granita\t\tgranire\t\tFalse\n", 670 | "fresca\t\tfresco\t\tFalse\n" 671 | ], 672 | "name": "stdout" 673 | } 674 | ] 675 | } 676 | ] 677 | } -------------------------------------------------------------------------------- /05 - Analisi del testo/named_entity_recognition.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "name": "named_entity_recognition.ipynb", 7 | "version": "0.3.2", 8 | "provenance": [], 9 | "include_colab_link": true 10 | }, 11 | "kernelspec": { 12 | "name": "python3", 13 | "display_name": "Python 3" 14 | } 15 | }, 16 | "cells": [ 17 | { 18 | "cell_type": "markdown", 19 | "metadata": { 20 | "id": "view-in-github", 21 | "colab_type": "text" 22 | }, 23 | "source": [ 24 | "\"Open" 25 | ] 26 | }, 27 | { 28 | "metadata": { 29 | "id": "qqrTWU73GRdu", 30 | "colab_type": "text" 31 | }, 32 | "cell_type": "markdown", 33 | "source": [ 34 | "# Named Entity Recognition\n", 35 | "La Named Entity Recognition (NER) è l'operazione di livello superiore al POS Tagging e consiste nell'identificare la classe di appartenenza di una determinata parola. Esempi di classi possono essere: persone, organizzazioni, luoghi e quantità.\n", 36 | "

\n", 37 | "Entità è un'altra delle informazioni che Spacy ci restituisce, vediamo come ottenerla.\n", 38 | "Importiamo Spacy e carichiamo il modulo per la lingua inglese." 39 | ] 40 | }, 41 | { 42 | "metadata": { 43 | "id": "AKKRF1qFGOjm", 44 | "colab_type": "code", 45 | "colab": {} 46 | }, 47 | "cell_type": "code", 48 | "source": [ 49 | "import spacy\n", 50 | "\n", 51 | "nlp = spacy.load(\"en_core_web_sm\")" 52 | ], 53 | "execution_count": 0, 54 | "outputs": [] 55 | }, 56 | { 57 | "metadata": { 58 | "id": "jBBpaOhwJ9O5", 59 | "colab_type": "text" 60 | }, 61 | "cell_type": "markdown", 62 | "source": [ 63 | "Creiamo un documento con una che contiene diverse entità, come una persona, un'organizzazione, una cifra e una data." 64 | ] 65 | }, 66 | { 67 | "metadata": { 68 | "id": "cWZtxeGeJqiY", 69 | "colab_type": "code", 70 | "colab": {} 71 | }, 72 | "cell_type": "code", 73 | "source": [ 74 | "doc = nlp(\"Mark Zuckerberg acquired Whatsapp for 15 billions USD on 15 August 2014.\")" 75 | ], 76 | "execution_count": 0, 77 | "outputs": [] 78 | }, 79 | { 80 | "metadata": { 81 | "id": "egG6KwnIGUY4", 82 | "colab_type": "text" 83 | }, 84 | "cell_type": "markdown", 85 | "source": [ 86 | "Adesso possiamo accedere alle entità usando l'attributò *.ents*" 87 | ] 88 | }, 89 | { 90 | "metadata": { 91 | "id": "qsHiXBuoL3NW", 92 | "colab_type": "code", 93 | "colab": { 94 | "base_uri": "https://localhost:8080/", 95 | "height": 34 96 | }, 97 | "outputId": "800647c6-e63a-4b3c-efda-ec2e0a52af63" 98 | }, 99 | "cell_type": "code", 100 | "source": [ 101 | "doc.ents" 102 | ], 103 | "execution_count": 14, 104 | "outputs": [ 105 | { 106 | "output_type": "execute_result", 107 | "data": { 108 | "text/plain": [ 109 | "(Mark Zuckerberg, Whatsapp, 15 billions USD, 15 August 2014)" 110 | ] 111 | }, 112 | "metadata": { 113 | "tags": [] 114 | }, 115 | "execution_count": 14 116 | } 117 | ] 118 | }, 119 | { 120 | "metadata": { 121 | "id": "LdnLdZnTL7zR", 122 | "colab_type": "text" 123 | }, 124 | "cell_type": "markdown", 125 | "source": [ 126 | "Se l'attributo è vuoto, vuol dire che nel nostro testo non è presente (o non è stata rilevata) nessuna entità, possiamo stampare il tipo di entità usando l'attributo *.label_* di ogni entità." 127 | ] 128 | }, 129 | { 130 | "metadata": { 131 | "id": "VHuhsw-8KPHw", 132 | "colab_type": "code", 133 | "colab": { 134 | "base_uri": "https://localhost:8080/", 135 | "height": 103 136 | }, 137 | "outputId": "4612d122-2a65-42b8-b7b2-7966499c40ed" 138 | }, 139 | "cell_type": "code", 140 | "source": [ 141 | "print(\"TOKEN\\t\\tENTITA'\")\n", 142 | "\n", 143 | "for ent in doc.ents:\n", 144 | " print(ent.text+\"\\t\\t\"+ent.label_)" 145 | ], 146 | "execution_count": 15, 147 | "outputs": [ 148 | { 149 | "output_type": "stream", 150 | "text": [ 151 | "TOKEN\t\tENTITA'\n", 152 | "Mark Zuckerberg\t\tPERSON\n", 153 | "Whatsapp\t\tORG\n", 154 | "15 billions USD\t\tMONEY\n", 155 | "15 August 2014\t\tDATE\n" 156 | ], 157 | "name": "stdout" 158 | } 159 | ] 160 | }, 161 | { 162 | "metadata": { 163 | "id": "jawpZz32jwfs", 164 | "colab_type": "text" 165 | }, 166 | "cell_type": "markdown", 167 | "source": [ 168 | "Anche in questo caso possiamo usare la funzione *explain* per ottenere una descrizione dell'entità." 169 | ] 170 | }, 171 | { 172 | "metadata": { 173 | "id": "fYoH16dhj2uy", 174 | "colab_type": "code", 175 | "colab": { 176 | "base_uri": "https://localhost:8080/", 177 | "height": 123 178 | }, 179 | "outputId": "0a6a92f9-b835-47e6-d592-f3494735b170" 180 | }, 181 | "cell_type": "code", 182 | "source": [ 183 | "print(\"TOKEN\\t\\tENTITA'\\t\\tDESCRIZIONE\")\n", 184 | "\n", 185 | "for ent in doc.ents:\n", 186 | " print(ent.text+\"\\t\\t\"+ent.label_+\"\\t\\t\"+spacy.explain(ent.))" 187 | ], 188 | "execution_count": 16, 189 | "outputs": [ 190 | { 191 | "output_type": "stream", 192 | "text": [ 193 | "TOKEN\t\tENTITA'\t\tDESCRIZIONE\n", 194 | "Mark Zuckerberg\t\tPERSON\t\tPeople, including fictional\n", 195 | "Whatsapp\t\tORG\t\tCompanies, agencies, institutions, etc.\n", 196 | "15 billions USD\t\tMONEY\t\tMonetary values, including unit\n", 197 | "15 August 2014\t\tDATE\t\tAbsolute or relative dates or periods\n" 198 | ], 199 | "name": "stdout" 200 | } 201 | ] 202 | }, 203 | { 204 | "metadata": { 205 | "id": "GaIgY28JMKfg", 206 | "colab_type": "text" 207 | }, 208 | "cell_type": "markdown", 209 | "source": [ 210 | "Come vedi Spacy ha fatto un'ottimo lavoro, vediamo se fa lo stesso con un'esempio in Italiano." 211 | ] 212 | }, 213 | { 214 | "metadata": { 215 | "id": "tba5af0YOgKA", 216 | "colab_type": "code", 217 | "colab": { 218 | "base_uri": "https://localhost:8080/", 219 | "height": 174 220 | }, 221 | "outputId": "8b648b0d-4ddd-4dda-9350-d0a589faab6b" 222 | }, 223 | "cell_type": "code", 224 | "source": [ 225 | "!python -m spacy download it_core_news_sm" 226 | ], 227 | "execution_count": 4, 228 | "outputs": [ 229 | { 230 | "output_type": "stream", 231 | "text": [ 232 | "Requirement already satisfied: it_core_news_sm==2.0.0 from https://github.com/explosion/spacy-models/releases/download/it_core_news_sm-2.0.0/it_core_news_sm-2.0.0.tar.gz#egg=it_core_news_sm==2.0.0 in /usr/local/lib/python3.6/dist-packages (2.0.0)\n", 233 | "\n", 234 | "\u001b[93m Linking successful\u001b[0m\n", 235 | " /usr/local/lib/python3.6/dist-packages/it_core_news_sm -->\n", 236 | " /usr/local/lib/python3.6/dist-packages/spacy/data/it_core_news_sm\n", 237 | "\n", 238 | " You can now load the model via spacy.load('it_core_news_sm')\n", 239 | "\n" 240 | ], 241 | "name": "stdout" 242 | } 243 | ] 244 | }, 245 | { 246 | "metadata": { 247 | "id": "Anls_NgoOIRd", 248 | "colab_type": "code", 249 | "colab": { 250 | "base_uri": "https://localhost:8080/", 251 | "height": 140 252 | }, 253 | "outputId": "9f9ff6cd-99ae-44aa-eb30-57bca0f55b34" 254 | }, 255 | "cell_type": "code", 256 | "source": [ 257 | "nlp = spacy.load(\"it_core_news_sm\")\n", 258 | "\n", 259 | "doc = nlp(\"Il 15 gennaio 2020 Giuseppe Gullo ha venduto la sua azienda NIGMATICA a Mediaset per 10 milioni di euro ed è andato a vivere ad Helsinki con il suo gatto Elon.\")\n", 260 | "\n", 261 | "print(\"TOKEN\\t\\tENTITA'\\t\\tDESCRIZIONE\")\n", 262 | "\n", 263 | "for ent in doc.ents:\n", 264 | " print(ent.text+\"\\t\\t\"+ent.label_+\"\\t\\t\"+spacy.explain(ent.label_))" 265 | ], 266 | "execution_count": 34, 267 | "outputs": [ 268 | { 269 | "output_type": "stream", 270 | "text": [ 271 | "TOKEN\t\tENTITA'\t\tDESCRIZIONE\n", 272 | "Giuseppe Gullo\t\tPER\t\tNamed person or family.\n", 273 | "NIGMATICA\t\tORG\t\tCompanies, agencies, institutions, etc.\n", 274 | "Mediaset\t\tORG\t\tCompanies, agencies, institutions, etc.\n", 275 | "Helsinki\t\tLOC\t\tNon-GPE locations, mountain ranges, bodies of water\n", 276 | "Elon\t\tPER\t\tNamed person or family.\n" 277 | ], 278 | "name": "stdout" 279 | } 280 | ] 281 | }, 282 | { 283 | "metadata": { 284 | "id": "r1Sk5wM0PQNq", 285 | "colab_type": "text" 286 | }, 287 | "cell_type": "markdown", 288 | "source": [ 289 | "Come vedi anche in italiano il risultato è buono ma non eccellente come per l'inglese, infatti non è riuscito a riconoscere la data, se certe parole sono importanti per il nostro corpus di testo possiamo assegnargli una entità manualmente. Per farlo dobbiamo ottenere l'hash dell'entità corretta, in questo caso un'organizzazione." 290 | ] 291 | }, 292 | { 293 | "metadata": { 294 | "id": "xfT-us0rkjh6", 295 | "colab_type": "code", 296 | "colab": { 297 | "base_uri": "https://localhost:8080/", 298 | "height": 34 299 | }, 300 | "outputId": "98273a68-62bb-4e9d-de74-045b934a80f0" 301 | }, 302 | "cell_type": "code", 303 | "source": [ 304 | "org = doc.vocab.strings[\"DATE\"]\n", 305 | "org" 306 | ], 307 | "execution_count": 37, 308 | "outputs": [ 309 | { 310 | "output_type": "execute_result", 311 | "data": { 312 | "text/plain": [ 313 | "388" 314 | ] 315 | }, 316 | "metadata": { 317 | "tags": [] 318 | }, 319 | "execution_count": 37 320 | } 321 | ] 322 | }, 323 | { 324 | "metadata": { 325 | "id": "f_a-tbbnlDTJ", 326 | "colab_type": "text" 327 | }, 328 | "cell_type": "markdown", 329 | "source": [ 330 | "E ci serve l'indice del token" 331 | ] 332 | }, 333 | { 334 | "metadata": { 335 | "id": "-KXcpOyElFWz", 336 | "colab_type": "code", 337 | "colab": { 338 | "base_uri": "https://localhost:8080/", 339 | "height": 34 340 | }, 341 | "outputId": "e0b3f836-7a9f-4d04-bb16-70b2c3f766be" 342 | }, 343 | "cell_type": "code", 344 | "source": [ 345 | "index = doc.text.split().index(\"15\")\n", 346 | "index" 347 | ], 348 | "execution_count": 38, 349 | "outputs": [ 350 | { 351 | "output_type": "execute_result", 352 | "data": { 353 | "text/plain": [ 354 | "1" 355 | ] 356 | }, 357 | "metadata": { 358 | "tags": [] 359 | }, 360 | "execution_count": 38 361 | } 362 | ] 363 | }, 364 | { 365 | "metadata": { 366 | "id": "8-6SL3xDlUMN", 367 | "colab_type": "text" 368 | }, 369 | "cell_type": "markdown", 370 | "source": [ 371 | "Ora dobbiamo creare un'oggetto span che rappresenterà il nostro token, all'oggetto passeremo gli indici di inizio e fine del token all'interno della frase e il label corretto." 372 | ] 373 | }, 374 | { 375 | "metadata": { 376 | "id": "sX4hg6u8igxG", 377 | "colab_type": "code", 378 | "colab": {} 379 | }, 380 | "cell_type": "code", 381 | "source": [ 382 | "from spacy.tokens import Span\n", 383 | "\n", 384 | " \n", 385 | "nigma = Span(doc,index, index+3, label = org)" 386 | ], 387 | "execution_count": 0, 388 | "outputs": [] 389 | }, 390 | { 391 | "metadata": { 392 | "id": "uKHf7Ghdlreg", 393 | "colab_type": "text" 394 | }, 395 | "cell_type": "markdown", 396 | "source": [ 397 | "Adesso aggiungiamo lo span alle entità del nostro documento." 398 | ] 399 | }, 400 | { 401 | "metadata": { 402 | "id": "MNez_QE3kxz9", 403 | "colab_type": "code", 404 | "colab": {} 405 | }, 406 | "cell_type": "code", 407 | "source": [ 408 | "doc.ents = list(doc.ents) + [nigma]" 409 | ], 410 | "execution_count": 0, 411 | "outputs": [] 412 | }, 413 | { 414 | "metadata": { 415 | "id": "xAFRKQOlnQxI", 416 | "colab_type": "text" 417 | }, 418 | "cell_type": "markdown", 419 | "source": [ 420 | "Verifichiamo" 421 | ] 422 | }, 423 | { 424 | "metadata": { 425 | "id": "WMP0tlUJic-X", 426 | "colab_type": "code", 427 | "colab": { 428 | "base_uri": "https://localhost:8080/", 429 | "height": 157 430 | }, 431 | "outputId": "dd555f97-0a6f-4fe8-9913-d6e2aa424bb0" 432 | }, 433 | "cell_type": "code", 434 | "source": [ 435 | "print(\"TOKEN\\t\\tENTITA'\\t\\tDESCRIZIONE\")\n", 436 | "\n", 437 | "for ent in doc.ents:\n", 438 | " print(ent.text+\"\\t\\t\"+ent.label_+\"\\t\\t\"+spacy.explain(ent.label_))" 439 | ], 440 | "execution_count": 43, 441 | "outputs": [ 442 | { 443 | "output_type": "stream", 444 | "text": [ 445 | "TOKEN\t\tENTITA'\t\tDESCRIZIONE\n", 446 | "15 gennaio 2020\t\tDATE\t\tAbsolute or relative dates or periods\n", 447 | "Giuseppe Gullo\t\tPER\t\tNamed person or family.\n", 448 | "NIGMATICA\t\tORG\t\tCompanies, agencies, institutions, etc.\n", 449 | "Mediaset\t\tORG\t\tCompanies, agencies, institutions, etc.\n", 450 | "Helsinki\t\tLOC\t\tNon-GPE locations, mountain ranges, bodies of water\n", 451 | "Elon\t\tPER\t\tNamed person or family.\n" 452 | ], 453 | "name": "stdout" 454 | } 455 | ] 456 | }, 457 | { 458 | "metadata": { 459 | "id": "iDQosQ19nSPa", 460 | "colab_type": "text" 461 | }, 462 | "cell_type": "markdown", 463 | "source": [ 464 | "Adesso abbiamo anche la data !" 465 | ] 466 | }, 467 | { 468 | "metadata": { 469 | "id": "cCJi0QgzM1ZB", 470 | "colab_type": "text" 471 | }, 472 | "cell_type": "markdown", 473 | "source": [ 474 | "## Visualizzazione delle entità\n", 475 | "Spacy contiene un fantastico modulo per creare diversi tipi di visualizzazioni del testo chiamato Displacy. Importiamo displacy e utilizziamo per creare una rappresentazione visiva delle entità presenti nel testo." 476 | ] 477 | }, 478 | { 479 | "metadata": { 480 | "id": "mJ0HBr2qKb2V", 481 | "colab_type": "code", 482 | "colab": { 483 | "base_uri": "https://localhost:8080/", 484 | "height": 122 485 | }, 486 | "outputId": "bbeff476-2e01-41c4-905d-92552ec118d6" 487 | }, 488 | "cell_type": "code", 489 | "source": [ 490 | "from spacy import displacy\n", 491 | "\n", 492 | "nlp = spacy.load(\"en_core_web_sm\")\n", 493 | "doc = nlp(\"Jeff Bezos, founder and CEO of Amazon, an ecommerce company with headquarter in Seattle, became the world richest man on October 2017 with a net worth of 90 billions USD\")\n", 494 | "\n", 495 | "displacy.render(doc, style='ent', jupyter=True)" 496 | ], 497 | "execution_count": 33, 498 | "outputs": [ 499 | { 500 | "output_type": "display_data", 501 | "data": { 502 | "text/html": [ 503 | "
\n", 504 | "\n", 505 | " Jeff Bezos\n", 506 | " PERSON\n", 507 | "\n", 508 | ", founder and CEO of \n", 509 | "\n", 510 | " Amazon\n", 511 | " ORG\n", 512 | "\n", 513 | ", an ecommerce company with headquarter in \n", 514 | "\n", 515 | " Seattle\n", 516 | " GPE\n", 517 | "\n", 518 | ", became the world richest man on \n", 519 | "\n", 520 | " October 2017\n", 521 | " DATE\n", 522 | "\n", 523 | " with a net worth of \n", 524 | "\n", 525 | " 90 billions USD\n", 526 | " MONEY\n", 527 | "\n", 528 | "
" 529 | ], 530 | "text/plain": [ 531 | "" 532 | ] 533 | }, 534 | "metadata": { 535 | "tags": [] 536 | } 537 | } 538 | ] 539 | }, 540 | { 541 | "metadata": { 542 | "id": "zAM9_XZ0f8oq", 543 | "colab_type": "text" 544 | }, 545 | "cell_type": "markdown", 546 | "source": [ 547 | "Se lavoriamo su Jupyter Notebook o Colaboratory utilizziamo il parametro jupyter=True per visualizzare il grafico direttamente all'interno del notebook, altrimenti l'ouput del rendering sarà del codice HTML che possiamo salvare e visualizzare dentro al browser." 548 | ] 549 | } 550 | ] 551 | } -------------------------------------------------------------------------------- /06 - Sentiment Analysis/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProfAI/nlp00/bb5e60ccc24e536a0927f544d4f903df03624b85/06 - Sentiment Analysis/.DS_Store -------------------------------------------------------------------------------- /06 - Sentiment Analysis/classifier_nltk.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "name": "classifier_nltk.ipynb", 7 | "version": "0.3.2", 8 | "provenance": [], 9 | "include_colab_link": true 10 | }, 11 | "kernelspec": { 12 | "name": "python3", 13 | "display_name": "Python 3" 14 | } 15 | }, 16 | "cells": [ 17 | { 18 | "cell_type": "markdown", 19 | "metadata": { 20 | "id": "view-in-github", 21 | "colab_type": "text" 22 | }, 23 | "source": [ 24 | "\"Open" 25 | ] 26 | }, 27 | { 28 | "metadata": { 29 | "id": "qwn3tv38gggz", 30 | "colab_type": "text" 31 | }, 32 | "cell_type": "markdown", 33 | "source": [ 34 | "# Creare un classificatore con NLTK\n", 35 | "In questo notebook vedremo come creare un classificatore usando NLTK per eseguire la sentimet analisys sull'IMDB Movies Review Dataset, in modo tale da classificare recensioni positive e negative. Il modello che creeremò sarà un classificatore bayesiano, che si presta molto bene a problemi di classificazione di documenti di testo.\n", 36 | "

\n", 37 | "Cominciamo importando nltk e, se non lo abbiamo già fatto, scarichiamo i moduli per le stopwords e la creazione dei tokens." 38 | ] 39 | }, 40 | { 41 | "metadata": { 42 | "id": "Lc6EJH71QKEj", 43 | "colab_type": "code", 44 | "colab": { 45 | "base_uri": "https://localhost:8080/", 46 | "height": 137 47 | }, 48 | "outputId": "7fff0a31-7179-4842-9da8-c39c18a24992" 49 | }, 50 | "cell_type": "code", 51 | "source": [ 52 | "import nltk\n", 53 | "\n", 54 | "nltk.download(\"stopwords\")\n", 55 | "nltk.download(\"punkt\")" 56 | ], 57 | "execution_count": 28, 58 | "outputs": [ 59 | { 60 | "output_type": "stream", 61 | "text": [ 62 | "[nltk_data] Downloading package stopwords to /root/nltk_data...\n", 63 | "[nltk_data] Package stopwords is already up-to-date!\n", 64 | "[nltk_data] Downloading package punkt to /root/nltk_data...\n", 65 | "[nltk_data] Package punkt is already up-to-date!\n", 66 | "[nltk_data] Downloading package movie_reviews to /root/nltk_data...\n", 67 | "[nltk_data] Unzipping corpora/movie_reviews.zip.\n" 68 | ], 69 | "name": "stdout" 70 | }, 71 | { 72 | "output_type": "execute_result", 73 | "data": { 74 | "text/plain": [ 75 | "True" 76 | ] 77 | }, 78 | "metadata": { 79 | "tags": [] 80 | }, 81 | "execution_count": 28 82 | } 83 | ] 84 | }, 85 | { 86 | "metadata": { 87 | "id": "z-tUDouLeulP", 88 | "colab_type": "text" 89 | }, 90 | "cell_type": "markdown", 91 | "source": [ 92 | "## Procuriamoci il dataset\n", 93 | "Cominciamo scaricando il dataset, esegui la cella di codice qui sotto se sei su Google Colab o se hai wget installato sul tuo computer, altrimenti puoi scaricare il dataset da questo [link](http://ai.stanford.edu/~amaas/data/sentiment/aclImdb_v1.tar.gz).\n" 94 | ] 95 | }, 96 | { 97 | "metadata": { 98 | "id": "dQx5m7I7hYNq", 99 | "colab_type": "code", 100 | "colab": {} 101 | }, 102 | "cell_type": "code", 103 | "source": [ 104 | "!wget http://ai.stanford.edu/~amaas/data/sentiment/aclImdb_v1.tar.gz" 105 | ], 106 | "execution_count": 0, 107 | "outputs": [] 108 | }, 109 | { 110 | "metadata": { 111 | "id": "d5ARe_sZhgT2", 112 | "colab_type": "text" 113 | }, 114 | "cell_type": "markdown", 115 | "source": [ 116 | "L'archivio è compresso in formato tar.gz, esegui la cella di codice qui sotto se sei su Colab o hai l'utility tar installata sul tuo PC (solitamente è installata di base su Linux/OsX) se sei su Windows puoi usare 7-zip (può essere che anche winrar vada bene per estrarlo)." 117 | ] 118 | }, 119 | { 120 | "metadata": { 121 | "id": "snFAFzBpheFo", 122 | "colab_type": "code", 123 | "colab": {} 124 | }, 125 | "cell_type": "code", 126 | "source": [ 127 | "!tar -xzf aclImdb_v1.tar.gz" 128 | ], 129 | "execution_count": 0, 130 | "outputs": [] 131 | }, 132 | { 133 | "metadata": { 134 | "id": "FXIQXCbUhl0G", 135 | "colab_type": "text" 136 | }, 137 | "cell_type": "markdown", 138 | "source": [ 139 | "Se abbiamo estratto il dataset adesso avremo una cartella aclImdb con dentro diversi file e altre due cartelle, una con le recensioni per l'addestramento e una con le recensioni per il test. Il dataset ci fornisce il testo di ogni recensione, ognuna in un file txt differente, organizzate in cartelle corrispondenti al sentiment positivo/negativo. " 140 | ] 141 | }, 142 | { 143 | "metadata": { 144 | "id": "fx5howoghuEW", 145 | "colab_type": "text" 146 | }, 147 | "cell_type": "markdown", 148 | "source": [ 149 | "## Estrazione delle features\n", 150 | "Il classificatore bayesiano di NLTK richiede che gli esempi gli vengano forniti all'interno di un array i cui valori sono un dizionario con dentro la frase e il label. La frase deve a sua volta essere codificata in un dizionario con ogni parola come chiave e il valore True come valore (non chiedermi perché).\n", 151 | "
\n", 152 | "Realizziamo una funzione che ci permetta di creare questo dataset." 153 | ] 154 | }, 155 | { 156 | "metadata": { 157 | "id": "aGABqZh5QLCm", 158 | "colab_type": "code", 159 | "colab": {} 160 | }, 161 | "cell_type": "code", 162 | "source": [ 163 | "from os import listdir\n", 164 | "from nltk.corpus import stopwords\n", 165 | "import string\n", 166 | "\n", 167 | "\n", 168 | "def get_dataset(files_path, labels=[\"pos\",\"neg\"], samples_per_class=None):\n", 169 | " \n", 170 | " dataset = []\n", 171 | " \n", 172 | " for label in labels:\n", 173 | " count = 0\n", 174 | " path = files_path+label\n", 175 | " for file in listdir(path):\n", 176 | " review_file = open(path+\"/\"+file)\n", 177 | " review = review_file.read() \n", 178 | " review = review.translate(string.punctuation)\n", 179 | " words = nltk.word_tokenize(review)\n", 180 | " \n", 181 | " #words_filtered = [word for word in words if word not in stopwords.words(\"english\")]\n", 182 | " #words_dict = dict([(word, True) for word in words_filtered]) \n", 183 | " \n", 184 | " words_dict = dict([(word, True) for word in words if word not in stopwords.words(\"english\")])\n", 185 | " \n", 186 | " dataset.append((words_dict,label))\n", 187 | " \n", 188 | " count+=1\n", 189 | " \n", 190 | " if(samples_per_class!=None):\n", 191 | " if(count>=samples_per_class):\n", 192 | " break\n", 193 | " \n", 194 | " return dataset" 195 | ], 196 | "execution_count": 0, 197 | "outputs": [] 198 | }, 199 | { 200 | "metadata": { 201 | "id": "rDiWUzkpi1eB", 202 | "colab_type": "text" 203 | }, 204 | "cell_type": "markdown", 205 | "source": [ 206 | "Nella funzione abbiamo definito un parametro che ci permette di controllare gli esempi massimi per classe, infatti se cerchiamo di caricare tutte le 50.000 recensioni tra set di addestramento e di test, questo richiederebbe molto tempo, limitiamoci a 1000 per il momento per il set di addestramento e 500 per il set di test." 207 | ] 208 | }, 209 | { 210 | "metadata": { 211 | "id": "N8NrzsdqToFq", 212 | "colab_type": "code", 213 | "colab": { 214 | "base_uri": "https://localhost:8080/", 215 | "height": 88 216 | }, 217 | "outputId": "0d9ab627-dde5-4dab-e292-dd44efb05c26" 218 | }, 219 | "cell_type": "code", 220 | "source": [ 221 | "train_set = get_dataset(\"aclImdb/train/\", samples_per_class=1000)\n", 222 | "\n", 223 | "print(\"Prima recensione del train set\")\n", 224 | "print(train_set[0][0])\n", 225 | "print(\"Sentiment: %s\" % train_set[0][1])" 226 | ], 227 | "execution_count": 60, 228 | "outputs": [ 229 | { 230 | "output_type": "stream", 231 | "text": [ 232 | "Prima recensione del train set\n", 233 | "{'Just': True, 'finished': True, 'watching': True, 'movie': True, 'wanted': True, 'give': True, 'opinion': True, '(': True, 'justice': True, ')': True, 'movie.': True, '<': True, 'br': True, '/': True, '>': True, 'First': True, ',': True, 'get': True, 'things': True, 'straight': True, 'pretending': True, 'anything': True, 'solid': True, 'action': True, 'comedy': True, '.': True, 'It': True, \"n't\": True, 'aim': True, 'revolutionize': True, 'industry': True, 'garner': True, 'critical': True, 'acclaims': True, 'want': True, 'regarded': True, 'one': True, 'If': True, 'really': True, 'enjoy': True, 'fullest': True, 'I': True, 'suggest': True, 'discard': True, 'critical-mindedness': True, 'longing': True, 'good': True, 'plot': True, 'wo': True, 'find': True, 'With': True, 'established': True, 'let': True, 'us': True, 'low': True, 'expectations': True, 'simply': True, 'strong': True, 'Yes': True, 'moviegoers': True, 'underrated': True, 'well': True, 'never': True, 'expected': True, 'much': True, 'even': True, 'enjoyed': True, 'Stephen': True, 'Chow': True, 'flicks': True, 'Kung': True, 'Fu': True, 'Hustle': True, 'best': True, 'effort': True, 'would': True, \"'ve\": True, 'rated': True, '9': True, 'Action': True, 'tight': True, 'epic': True, 'chokes': True, 'right': True, 'places.': True, 'SPOILERS': True, 'alert': True, 'think': True, 'The': True, 'might': True, 'unreal': True, 'watch': True, 'serious': True, 'basketball': True, 'anyways': True, '?': True, 'There': True, 'lot': True, 'sports': True, 'movies': True, 'drama': True, 'already': True, 'create': True, 'another': True, 'end': True, \"'m\": True, 'sure': True, \"'re\": True, 'reading': True, 'Go': True, 'ahead': True, 'remember': True, 'thinking': True, '-': True, 'smile': True, 'laugh': True, 'Every': True, 'creates': True, 'masterpieces': True, 'Pulp': True, 'Fiction': True, 'Godfather': True, 'sometimes': True, 'better': True, 'pile': True, 'dump': True, 'saying': True, 'Dunk': True, 'deserves': True, 'recognition': True, 'previous': True, 'examples': True, 'talking': True, 'Chow-ish': True, \"'s\": True, 'top': True, 'ten.': True, 'Highly': True, 'recommended': True, 'love': True, ':': True, '-no': True, 'brainer': True, '-Kung': True, '-Death': True, 'Trance': True, '-what': True, 'heck': True, \"'ll\": True, 'great': True, 'time.': True, '9/10': True, 'cast': True, '^_^': True}\n", 234 | "Sentiment: pos\n" 235 | ], 236 | "name": "stdout" 237 | } 238 | ] 239 | }, 240 | { 241 | "metadata": { 242 | "id": "gI5xOfnwWo3t", 243 | "colab_type": "code", 244 | "colab": { 245 | "base_uri": "https://localhost:8080/", 246 | "height": 88 247 | }, 248 | "outputId": "d656d5f7-125d-4521-f93f-8497f7a2eb5d" 249 | }, 250 | "cell_type": "code", 251 | "source": [ 252 | "test_set = get_dataset(\"aclImdb/test/\", samples_per_class=500)\n", 253 | "\n", 254 | "print(\"Prima recensione del test set\")\n", 255 | "print(test_set[0][0])\n", 256 | "print(\"Sentiment: %s\" % test_set[0][1])" 257 | ], 258 | "execution_count": 61, 259 | "outputs": [ 260 | { 261 | "output_type": "stream", 262 | "text": [ 263 | "Prima recensione del test set\n", 264 | "{'Although': True, 'little': True, 'pleasant': True, '11-minute': True, 'musical': True, 'diversion': True, '(': True, \"'s\": True, 'rightly': True, 'billed': True, '``': True, 'Tabloid': True, 'Musical': True, \"''\": True, ')': True, 'EVERY': True, 'Sunday': True, 'one': True, 'famous': True, 'precious': True, 'documents': True, 'cinematic': True, 'history': True, ',': True, 'since': True, 'provides': True, 'invaluable': True, 'look': True, 'burgeoning': True, 'talents': True, 'two': True, 'screen': True, 'talented': True, 'beloved': True, 'performers': True, ':': True, 'Deanna': True, 'Durbin': True, 'Judy': True, 'Garland.': True, '<': True, 'br': True, '/': True, '>': True, 'often': True, 'cited': True, 'test': True, 'sorts': True, 'produced': True, 'MGM': True, 'adolescent': True, 'appeal': True, 'studio': True, 'contractees': True, 'Garland': True, 'whose': True, 'options': True, 'reportedly': True, 'coming': True, 'renewal': True, 'assertion': True, 'entirely': True, 'accurate': True, '.': True, 'By': True, 'time': True, 'July': True, '1936': True, 'contract': True, 'already': True, 'lapsed': True, 'immediately': True, 'signed': True, 'Universal': True, 'month': True, 'earlier': True, 'June': True, '1936.': True, 'However': True, 'provision': True, 'permitted': True, 'exercise': True, 'option': True, 'services': True, 'sixty': True, 'days': True, 'providing': True, 'yet': True, 'begun': True, 'work': True, 'picture': True, 'new': True, 'As': True, 'debut': True, 'vehicle': True, 'THREE': True, 'SMART': True, 'GIRLS': True, 'still': True, 'ready': True, 'begin': True, 'filming': True, 'chose': True, \"'\": True, 'although': True, 'officially': True, 'found': True, 'back': True, 'lot': True, 'agreeable': True, 'short': True, 'subject': True, 'fellow': True, 'singing': True, 'hopeful': True, 'This': True, 'along': True, 'far': True, 'extensive': True, 'prior': True, 'professional': True, 'performing': True, 'experience/training': True, 'included': True, 'appearances': True, 'several': True, 'movie': True, 'shorts': True, 'may': True, 'explain': True, 'seems': True, 'favor': True, 'giving': True, 'lines': True, 'speak': True, 'original': True, 'song': True, 'Americana': True, 'sing': True, 'offers': True, 'popular': True, 'classical': True, 'art': True, 'Il': True, 'Bacio': True, 'Luigi': True, 'Ardiiti': True, 'Certainly': True, 'would': True, 'make': True, 'perfect': True, 'sense': True, 'want': True, 'players': True, 'another': True, 'rival': True, 'studio.': True, 'Ironically': True, 'character': True, 'overtly': True, 'pro-active': True, 'girls': True, 'feisty': True, 'impulsive': True, 'Little': True, 'Miss': True, 'Fixit': True, 'persona': True, 'propel': True, 'instantaneous': True, 'worldwide': True, 'super': True, 'stardom': True, 'world': True, 'first': True, 'Teen': True, 'Idol': True, 'passive': True, 'wistful': True, 'wallflower': True, 'image': True, 'see': True, 'generally': True, 'cast': True, 'supporting': True, 'roles': True, 'opposite': True, 'frequent': True, 'partner': True, 'Mickey': True, 'Rooney': True, 'ZIEGFELD': True, 'GIRL': True, 'up-and-coming': True, 'Lana': True, 'Turner': True, 'Not': True, 'fifteenth': True, 'feature': True, '1942': True, 'FOR': True, 'ME': True, 'AND': True, 'MY': True, 'GAL': True, 'also': True, 'fully': True, 'adult': True, 'role': True, 'achieve': True, 'solo': True, 'above-the': True, 'title': True, 'billing': True, 'attraction': True, 'status': True, 'true': True, 'superstar': True, 'attained': True, 'instantaneously': True, 'six': True, 'years': True, 'earlier.': True, 'It': True, 'inaccurate': True, 'therefore': True, 'assert': True, 'press': True, \"'n\": True, 'public': True, 'almost': True, 'decade': True, 'Literally': True, 'foreclosure': True, 'signing': True, 'evidence': True, 'strongly': True, 'suggests': True, 'much': True, 'quicker': True, 'realize': True, 'full': True, 'potential': True, 'worth': True, 'noting': True, 'every': True, 'notable': True, 'accomplishment': True, 'achieved': True, 'starring': True, 'vehicles': True, 'specially': True, 'written': True, 'showcase': True, 'invited': True, 'plant': True, 'footprints': True, 'forecourt': True, 'Graumann': True, 'Chinese': True, 'Theater': True, 'receiving': True, 'Honorary': True, 'Oscar': True, 'recognition': True, 'talent': True, 'received': True, 'well': True, 'gifted': True, 'contemporary.': True, 'In': True, 'case': True, 'delightful': True, 'utterly': True, 'unpretentious': True, 'Its': True, 'plot': True, 'line': True, 'use': True, 'save': True, 'grandfather': True, 'forcibly': True, 'retired': True, 'town': True, 'council': True, 'conducting': True, 'concerts': True, 'park': True, 'presages': True, 'Let': True, 'Put': True, 'On': True, 'Show': True, 'musicals': True, '100': True, 'MEN': True, 'A': True, 'Unlike': True, 'later': True, 'BABES': True, 'films': True, 'never': True, 'treats': True, 'insubstantial': True, 'storyline': True, 'seriously': True, 'consequently': True, 'eleven': True, 'minute': True, 'running': True, 'flies': True, 'by.': True, 'Of': True, 'course': True, 'magic': True, 'observing': True, 'remarkable': True, 'talents/screen': True, 'presences': True, 'beginning': True, 'legendary': True, 'careers': True, 'Both': True, 'even': True, 'early': True, 'stage': True, 'possessed': True, 'natural': True, 'unaffected': True, 'presentation': True, 'singers': True, 'actresses': True, 'fairly': True, 'explodes': True, 'vitality': True, 'literally': True, 'punches': True, 'lyrics': True, 'jaunty': True, 'socks': True, 'across': True, 'number': True, 'appropriate': True, 'hand': True, 'gestures': True, 'chewing': True, 'words': True, 'screws': True, 'mouth': True, 'bugs': True, 'eyes': True, 'intense': True, 'eagerness': True, 'show': True, 'do.': True, 'contrast': True, 'demure': True, 'subdued': True, 'selection': True, 'delivery': True, 'Arditi': True, 'waltz': True, 'traditional': True, 'stand': True, 'variety': True, 'physically': True, 'emotive': True, 'turn': True, 'Nevertheless': True, 'though': True, 'miniature': True, 'diva': True, 'nothing': True, 'call': True, 'attention': True, 'candid': True, 'dazzling': True, 'smile': True, 'artless': True, 'easily': True, 'holds': True, 'jazz': True, 'baby': True, 'duetting': True, 'finale': True, 'makes': True, 'regret': True, 'producer': True, 'Joe': True, 'Pasternak': True, 'able': True, 'dream': True, 'pairing': True, 'film': True, 'refused': True, 'loan': True, 'Number': True, 'One': True, 'Asset': True, 'priceless': True, 'document': True, 'nascent': True, 'unique': True, 'See': True, 'get': True, 'chance': True, '!': True}\n", 265 | "Sentiment: pos\n" 266 | ], 267 | "name": "stdout" 268 | } 269 | ] 270 | }, 271 | { 272 | "metadata": { 273 | "id": "eKWAvuFqjJlw", 274 | "colab_type": "text" 275 | }, 276 | "cell_type": "markdown", 277 | "source": [ 278 | "Adesso possiamo addestrare il nostro classificatore utilizzando la funzione *train(train_set)* del modulo *NaiveBayesClassifier* di NLTK." 279 | ] 280 | }, 281 | { 282 | "metadata": { 283 | "id": "4wPCUiMZV1qI", 284 | "colab_type": "code", 285 | "colab": {} 286 | }, 287 | "cell_type": "code", 288 | "source": [ 289 | "from nltk.classify import NaiveBayesClassifier\n", 290 | "\n", 291 | "classifier = NaiveBayesClassifier.train(train_set)" 292 | ], 293 | "execution_count": 0, 294 | "outputs": [] 295 | }, 296 | { 297 | "metadata": { 298 | "id": "MEJb2ZdQjWac", 299 | "colab_type": "text" 300 | }, 301 | "cell_type": "markdown", 302 | "source": [ 303 | "Utilizziamo la funzione *accuracy* di NLTK per calcolare l'accuratezza delle predizioni del modello sul set di addestramento e sul set di test." 304 | ] 305 | }, 306 | { 307 | "metadata": { 308 | "id": "Jsq4xMDETzdj", 309 | "colab_type": "code", 310 | "colab": { 311 | "base_uri": "https://localhost:8080/", 312 | "height": 51 313 | }, 314 | "outputId": "be017a84-9a89-497c-b016-4882a508b39f" 315 | }, 316 | "cell_type": "code", 317 | "source": [ 318 | "from nltk.classify.util import accuracy\n", 319 | "\n", 320 | "accuracy_train = nltk.classify.util.accuracy(classifier, train_set)\n", 321 | "accuracy_test = nltk.classify.util.accuracy(classifier, test_set)\n", 322 | "\n", 323 | "print(\"Accuracy sul set di addestramento: %.3f \" % accuracy_train)\n", 324 | "print(\"Accuracy sul set di test: %.3f \" % accuracy_test)" 325 | ], 326 | "execution_count": 63, 327 | "outputs": [ 328 | { 329 | "output_type": "stream", 330 | "text": [ 331 | "Accuracy sul set di addestramento: 0.992 \n", 332 | "Accuracy sul set di test: 0.792 \n" 333 | ], 334 | "name": "stdout" 335 | } 336 | ] 337 | }, 338 | { 339 | "metadata": { 340 | "id": "nIf3pRpMjg5Q", 341 | "colab_type": "text" 342 | }, 343 | "cell_type": "markdown", 344 | "source": [ 345 | "Il modello soffre di overfitting ed è normale dato che abbiamo usato soltanto pochi esempi, ma va bene così.
L'oggetto *classifier* ritornato dalla funzione *train* ci permette di ottenere le parole più informative, cioè quelle che se trovate all'interno di una recensione, aumentano di molto la probabilità che questa appartenga all'una o all'altra classe.\n" 346 | ] 347 | }, 348 | { 349 | "metadata": { 350 | "id": "pjFKsgu2eYhu", 351 | "colab_type": "code", 352 | "colab": { 353 | "base_uri": "https://localhost:8080/", 354 | "height": 206 355 | }, 356 | "outputId": "d849478e-9dcc-4146-e0d4-d2693feede2f" 357 | }, 358 | "cell_type": "code", 359 | "source": [ 360 | "classifier.show_most_informative_features()" 361 | ], 362 | "execution_count": 51, 363 | "outputs": [ 364 | { 365 | "output_type": "stream", 366 | "text": [ 367 | "Most Informative Features\n", 368 | " waste = True neg : pos = 14.6 : 1.0\n", 369 | " wasting = True neg : pos = 13.7 : 1.0\n", 370 | " wasted = True neg : pos = 11.9 : 1.0\n", 371 | " terrific = True pos : neg = 11.8 : 1.0\n", 372 | " deeply = True pos : neg = 11.7 : 1.0\n", 373 | " Davis = True pos : neg = 11.7 : 1.0\n", 374 | " underrated = True pos : neg = 11.7 : 1.0\n", 375 | " 8/10 = True pos : neg = 11.0 : 1.0\n", 376 | " uninspired = True neg : pos = 10.3 : 1.0\n", 377 | " stupidity = True neg : pos = 10.3 : 1.0\n" 378 | ], 379 | "name": "stdout" 380 | } 381 | ] 382 | }, 383 | { 384 | "metadata": { 385 | "id": "Kjl19EBwkBte", 386 | "colab_type": "text" 387 | }, 388 | "cell_type": "markdown", 389 | "source": [ 390 | "Fatta eccezione per Davis (che non ho idea di chi sia), le parole sono tutte forti indicatori di una recensione negativa (es. waste, unispired, stupidity) o positiva (deeply, terrific, 8/10).\n", 391 | "
\n", 392 | "Probiamo ora ad utilizzare il modello per classificare recensioni scritte da noi, definiamo una funzione che crea il dizionario parola:True partendo dalla recensione" 393 | ] 394 | }, 395 | { 396 | "metadata": { 397 | "id": "HIYR8uJ2kX_X", 398 | "colab_type": "code", 399 | "colab": {} 400 | }, 401 | "cell_type": "code", 402 | "source": [ 403 | "def create_word_features(review):\n", 404 | " review = review.translate(string.punctuation)\n", 405 | " words = nltk.word_tokenize(review)\n", 406 | " words_dict = dict([(word, True) for word in words if word not in stopwords.words(\"english\")])\n", 407 | " return words_dict" 408 | ], 409 | "execution_count": 0, 410 | "outputs": [] 411 | }, 412 | { 413 | "metadata": { 414 | "id": "4B3fhIM2lrFH", 415 | "colab_type": "text" 416 | }, 417 | "cell_type": "markdown", 418 | "source": [ 419 | "Ora utilizziamo il metodo *classify* insieme alla funzione definita sopra per classificare le recensioni." 420 | ] 421 | }, 422 | { 423 | "metadata": { 424 | "id": "Hc2tSHock3qT", 425 | "colab_type": "code", 426 | "colab": { 427 | "base_uri": "https://localhost:8080/", 428 | "height": 34 429 | }, 430 | "outputId": "b9677a66-97bb-4856-ca50-b1f625f6a906" 431 | }, 432 | "cell_type": "code", 433 | "source": [ 434 | "review = \"This movie was just great\"\n", 435 | "classifier.classify(create_word_features(review))" 436 | ], 437 | "execution_count": 74, 438 | "outputs": [ 439 | { 440 | "output_type": "execute_result", 441 | "data": { 442 | "text/plain": [ 443 | "'pos'" 444 | ] 445 | }, 446 | "metadata": { 447 | "tags": [] 448 | }, 449 | "execution_count": 74 450 | } 451 | ] 452 | }, 453 | { 454 | "metadata": { 455 | "id": "LdlUCtNClU_T", 456 | "colab_type": "code", 457 | "colab": { 458 | "base_uri": "https://localhost:8080/", 459 | "height": 34 460 | }, 461 | "outputId": "e1093f6d-b8d0-4077-9a7b-a231d43ca0fb" 462 | }, 463 | "cell_type": "code", 464 | "source": [ 465 | "review = \"This movie was just terrible\"\n", 466 | "classifier.classify(create_word_features(review))" 467 | ], 468 | "execution_count": 75, 469 | "outputs": [ 470 | { 471 | "output_type": "execute_result", 472 | "data": { 473 | "text/plain": [ 474 | "'neg'" 475 | ] 476 | }, 477 | "metadata": { 478 | "tags": [] 479 | }, 480 | "execution_count": 75 481 | } 482 | ] 483 | } 484 | ] 485 | } -------------------------------------------------------------------------------- /06 - Sentiment Analysis/data/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProfAI/nlp00/bb5e60ccc24e536a0927f544d4f903df03624b85/06 - Sentiment Analysis/data/.DS_Store -------------------------------------------------------------------------------- /06 - Sentiment Analysis/data/hifit_reviews.csv: -------------------------------------------------------------------------------- 1 | Username;title;review;rating 2 | Amazon Customer;Great With Modifications;The recovery times are longer as some have mentioned, but I like to do active recoveries and mix in some cardio, so I jog, do jumping jacks, high knees, etc. during the recovery. Since my workouts are usually 50 minutes, and this is a backup, I will modify the different exercises on different rounds as well. For example, do static lunge squats or backwards lunges instead of just lunges. This makes the workout more challenging and keeps me from boredom. The only thing I don’t like is you can’t pick your music. Overall, this app is just like any workout - it’s yours, do what you want with it.;4.5 3 | Janey_monster;Won't take 'Yes' for an answer!;Just like another reviewer said. Between exercises, when it asks if your ready to start, I say yes and it says "okay I'll keep that in mind for next time.... Blah blah blah..." and closes me out before I finish my set. If not for that, and maybe also not knowing what a 'burpee' is (perhaps I'm a bit behind on exercise vocabulary... But a description option would be nice!), I'd rate 5. Please fix?? (P. S. I have an echo dot 2nd gen); 2 4 | Gary Mercado;Won't respond to my yes command;The skill won't respond to the yes command and basically makes me restart mid workout.other than that when it works it's great.;2 5 | Amazon Customer;Excellent;So far I’m happy of this new Skill. I don’t have time to go to the gym but the 15-minute workouts suits my mornings well. The intensity of the sessions is tailored to my modest standards too.;5 6 | Linda Charlton-Gunderson;Does not always hear ready;I said ready and she would shut off. But when it works it's fine but the recover is too long. It started all over when she told me it was done and asked if it was too easy or too hard. I said it was ok.;2 7 | Mallory galvin;Terrible;Slow and annoying. I don't need 30 seconds to recover from 30 seconds of push ups.;1 8 | Amazon Customer;Challenging;I love bodyweight workouts and they look well-structured from a scientific point of view. I’m curious to know how many different exercises it can generate and how far they will push me.;5 9 | jenisse210;Great idea but doesn't work;I've tried to start twice now and I get to start work outs and she asks if I want music with my workout. I say yes and she shuts off! Did it to me twice!!;2 10 | Matteo;Fantastic!!!;I've never seen something like that, I am a bit passionate about these topics and the trainings (including the evolution of a training) is well structured. Definitely I can see the work of a fitness expert in the preparation of the training. So I totally advice it.;5 11 | Amazon Customer;Five Stars;I tried the app and it's the best one for my daily workout!! Recommended! A+;5 12 | aisha;Great but needs improvement;Great app if it just don't shut itself off time to time and destroys your work out in between;4 13 | Rebekah Bertram;love it;my kids do this woth me. i kove it. great music and quick!;5 14 | -------------------------------------------------------------------------------- /07 - Topic modelling/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProfAI/nlp00/bb5e60ccc24e536a0927f544d4f903df03624b85/07 - Topic modelling/.DS_Store -------------------------------------------------------------------------------- /08 - Deep Learning e Chatbot/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProfAI/nlp00/bb5e60ccc24e536a0927f544d4f903df03624b85/08 - Deep Learning e Chatbot/.DS_Store -------------------------------------------------------------------------------- /08 - Deep Learning e Chatbot/data/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProfAI/nlp00/bb5e60ccc24e536a0927f544d4f903df03624b85/08 - Deep Learning e Chatbot/data/.DS_Store -------------------------------------------------------------------------------- /08 - Deep Learning e Chatbot/data/model.json: -------------------------------------------------------------------------------- 1 | { 2 | "intents": [{ 3 | "name": "HelloIntent", 4 | "samples": ["Ciao", "Salve", "hei", "Ci sei ?", "Buongiorno", "Buonasera"], 5 | "responses": ["Ciao, sono MiaoBot, l'assistente virtuale di Miao Mobile, come posso aiutarti ?", "Buongiorno, questa è l'assistenza clienti di Miao Mobile, come posso esserti utile ?"] 6 | }, 7 | { 8 | "name": "GoodbyeIntent", 9 | "samples": ["Addio", "Arrivederci", "Buona giornata", "A presto", "Ci vediamo"], 10 | "responses": ["Grazie per averci contattato ! Buona giornata", "Per qualsiasi cosa ci trovi sempre qui, buona giornata !","Buona giornata !"] 11 | }, 12 | { 13 | "name": "ThanksIntent", 14 | "samples": ["Grazie", "Ti ringrazio", "Fantastico"], 15 | "responses": ["E' stato un piacere, se hai bisogno di altro non esitare a chiedere", "E' stato un piacere aiutarti", "Figurati, è il mio lavoro :)"] 16 | }, 17 | { 18 | "name": "WhoIntent", 19 | "samples": ["Chi sei tu ?", "Come ti chiami ?","Con chi sto parlando ?"], 20 | "responses": ["Io sono MiaoBot, l'assistente virtuale di Miao Mobile, sono qui 24 ore su 24 per assisterti", "Mi chiamo MiaoBot, sono un'intelligenza artificiale sviluppata da Miao Mobile per assistere ogni cliente"] 21 | }, 22 | { 23 | "name": "CreditIntent", 24 | "samples": ["Posso sapere il mio credito ?", "Qual è il mio credito ?", "Quanti soldi ho ?"], 25 | "responses": ["Per conoscere il tuo credito ti basta inviare un messagio al 199 con il testo 'credito'","Purtroppo io non posso sapere il tuo credito, per conoscerlo ti inviare un SMS con scritto 'credito' al numero 199"] 26 | }, 27 | { 28 | "name": "PromoListIntent", 29 | "samples": ["Quali sono le vostre offerte ?", "Che offerte avete ?","Ci sono promozioni ?"], 30 | "responses": ["Ecco le nostre offerte attuali: 1)Miao 4 Hooman: 10 giga e 1000 minuti al mese a 4.99€ 2) Miao Tanti Giga: 100 giga e chiamate illimitate a 12.99€ 3) Miao & Chilli: 30 giga e chiamate illimitate + Netflix incluso a 9.99€ al mese"] 31 | }, 32 | { 33 | "name": "PromoChangeIntent", 34 | "samples": ["Vorrei cambiare piano tariffario", "Voglio cambiare promozione","Voglio un'altra promozione"], 35 | "responses": ["Certo, puoi scegliere tra una delle seguenti offerte e poi contattare il 199 per eseguire il cambio: 1)Miao 4 Hooman: 10 giga e 1000 minuti al mese a 4.99€ 2) Miao Tanti Giga: 100 giga e chiamate illimitate a 12.99€ 3) Miao & Chilli: 30 giga e chiamate illimitate + Netflix incluso a 9.99€ al mese"] 36 | }, 37 | 38 | { 39 | "name": "ContactIntent", 40 | "samples": ["Qual è il numero verde ?","Posso parlare con un'operatore ?"], 41 | "responses": ["Per parlare con un nostro operatore può contattare il 199","Il nostro numero verde è 199, subito dopo il messaggi di benvenuto digita 0 per parlare con un'operatore"] 42 | }, 43 | { 44 | "name": "FiberIntent", 45 | "samples": ["Avete soluzioni per la fibra ?","Avete offerte per la linea fissa ?"], 46 | "responses": ["Purtroppo al momento non forniamo servizi per la linea fissa ma ci stiamo attrezzando", "Mi dispiace ma al momento non abbiamo soluzioni per il fisso."] 47 | }, 48 | { 49 | "name": "GreetingIntent", 50 | "samples": ["Come stai ?","Come va ?","Come ti senti ?"], 51 | "responses": ["Mi sento al settimo Cloud ! grazie per avermelo chiesto :)"] 52 | }, 53 | { 54 | "name": "WhatIntent", 55 | "samples": ["Cosa puoi fare ?","Come puoi aiutarmi ?"], 56 | "responses": ["Posso aiutarti a conoscere le ultime offerte di Miao Mobile oppure con qualche problema che stai riscontrando, basta chiedere :)"] 57 | }, 58 | { 59 | "name": "HelpIntent", 60 | "samples": ["Mi serve aiuto","Ho bisogno di assistenza"], 61 | "responses": ["Sarò lieto di assisterti ! Come posso aiutarti ?","Sono qui per aiutarti, dimmi come posso esserti utile :)"] 62 | }, 63 | { 64 | "name": "BadIntent", 65 | "samples": ["Fai schifo","Vai a farti friggere","Sei totalmente inutile"], 66 | "responses": ["Mi dispiace molto di non averti soddisfatto, come posso rimediare ?","Sono spiacente di sentirtelo dire, posso rimediare in qualche modo ?"] 67 | }, 68 | { 69 | "name": "GenderIntent", 70 | "samples": ["Sei un essere umano ?","Sei una donna ?","Sei un'uomo ?","Sei una donna ?"], 71 | "responses": ["Sono un'intelligenza artificiale sviluappata da un team di ricercatori umani e felini nei laboratori di Miao Mobile"] 72 | }, 73 | { 74 | "name": "AnswerIntent", 75 | "samples": ["Qual è la risposta alla domanda fondamentale sulla vita, l'universo e tutto quanto"], 76 | "responses": ["42"] 77 | }, 78 | { 79 | "name": "WordEndIntent", 80 | "samples": ["Quando finirà il mondo ?"], 81 | "responses": ["Quando i gatti decideranno di conquistarlo","Quando i gatti impareranno ad aprire le scatolette e non avranno più bisogno degli schiavi umani."] 82 | } 83 | ] 84 | } 85 | -------------------------------------------------------------------------------- /09 - Word embedding e Word2Vec/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProfAI/nlp00/bb5e60ccc24e536a0927f544d4f903df03624b85/09 - Word embedding e Word2Vec/.DS_Store -------------------------------------------------------------------------------- /09 - Word embedding e Word2Vec/word2vec.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "name": "word2vec.ipynb", 7 | "version": "0.3.2", 8 | "provenance": [], 9 | "include_colab_link": true 10 | }, 11 | "kernelspec": { 12 | "name": "python3", 13 | "display_name": "Python 3" 14 | } 15 | }, 16 | "cells": [ 17 | { 18 | "cell_type": "markdown", 19 | "metadata": { 20 | "id": "view-in-github", 21 | "colab_type": "text" 22 | }, 23 | "source": [ 24 | "\"Open" 25 | ] 26 | }, 27 | { 28 | "cell_type": "markdown", 29 | "metadata": { 30 | "id": "KprtIuKVksZF", 31 | "colab_type": "text" 32 | }, 33 | "source": [ 34 | "# Il Word2Vec\n", 35 | "Il **Word2Vec** è un metodo che ci permette di creare una rappresentazione vettoriale delle parole (**word embedding**) usando il deep learning. Google mette a disposizione un modello preaddestrato su un corpus di Google News, contenente 3 milioni di parole e 300 dimensioni. Possiamo scaricare il modello preaddestrato da [questo link](https://s3.amazonaws.com/dl4j-distribution/GoogleNews-vectors-negative300.bin.gz).\n", 36 | "

\n", 37 | "Se utilizzi Google Colab o comunque hai wget installato sul tuo computer esegui pure la cella di codice qui sotto per scaricare il dataset." 38 | ] 39 | }, 40 | { 41 | "cell_type": "code", 42 | "metadata": { 43 | "id": "0qLzv-tDUYHa", 44 | "colab_type": "code", 45 | "outputId": "76d98278-7876-4e24-e3f4-d169af507f42", 46 | "colab": { 47 | "base_uri": "https://localhost:8080/", 48 | "height": 206 49 | } 50 | }, 51 | "source": [ 52 | "!wget https://s3.amazonaws.com/dl4j-distribution/GoogleNews-vectors-negative300.bin.gz" 53 | ], 54 | "execution_count": 1, 55 | "outputs": [ 56 | { 57 | "output_type": "stream", 58 | "text": [ 59 | "--2019-05-03 14:01:20-- https://s3.amazonaws.com/dl4j-distribution/GoogleNews-vectors-negative300.bin.gz\n", 60 | "Resolving s3.amazonaws.com (s3.amazonaws.com)... 52.216.106.85\n", 61 | "Connecting to s3.amazonaws.com (s3.amazonaws.com)|52.216.106.85|:443... connected.\n", 62 | "HTTP request sent, awaiting response... 200 OK\n", 63 | "Length: 1647046227 (1.5G) [application/x-gzip]\n", 64 | "Saving to: ‘GoogleNews-vectors-negative300.bin.gz’\n", 65 | "\n", 66 | "GoogleNews-vectors- 100%[===================>] 1.53G 50.2MB/s in 27s \n", 67 | "\n", 68 | "2019-05-03 14:01:47 (58.7 MB/s) - ‘GoogleNews-vectors-negative300.bin.gz’ saved [1647046227/1647046227]\n", 69 | "\n" 70 | ], 71 | "name": "stdout" 72 | } 73 | ] 74 | }, 75 | { 76 | "cell_type": "markdown", 77 | "metadata": { 78 | "id": "yu-yv8ttmIXE", 79 | "colab_type": "text" 80 | }, 81 | "source": [ 82 | "Ed estrai il file .gz utilizzando gunzip." 83 | ] 84 | }, 85 | { 86 | "cell_type": "code", 87 | "metadata": { 88 | "id": "7vodVGN_Ug8Q", 89 | "colab_type": "code", 90 | "colab": {} 91 | }, 92 | "source": [ 93 | "!gunzip GoogleNews-vectors-negative300.bin.gz" 94 | ], 95 | "execution_count": 0, 96 | "outputs": [] 97 | }, 98 | { 99 | "cell_type": "markdown", 100 | "metadata": { 101 | "id": "hVTpHydnmNYh", 102 | "colab_type": "text" 103 | }, 104 | "source": [ 105 | "In questo notebook useremo **gensim** per caricare il modello preaddestrato, per farlo ci basta usare la funzione *.load_word2vec_format(filpath)*, trattandosi di un file binario dobbiamo specificare il parametro *binary* a true." 106 | ] 107 | }, 108 | { 109 | "cell_type": "code", 110 | "metadata": { 111 | "id": "sliNG3G7Ureu", 112 | "colab_type": "code", 113 | "colab": { 114 | "base_uri": "https://localhost:8080/", 115 | "height": 34 116 | }, 117 | "outputId": "f672ca16-07fc-4a9f-cef2-dff9d45514cf" 118 | }, 119 | "source": [ 120 | "from gensim.models import Word2Vec\n", 121 | "import gensim\n", 122 | "\n", 123 | "model = gensim.models.KeyedVectors.load_word2vec_format('GoogleNews-vectors-negative300.bin', binary=True)\n", 124 | "type(model)" 125 | ], 126 | "execution_count": 4, 127 | "outputs": [ 128 | { 129 | "output_type": "execute_result", 130 | "data": { 131 | "text/plain": [ 132 | "gensim.models.keyedvectors.Word2VecKeyedVectors" 133 | ] 134 | }, 135 | "metadata": { 136 | "tags": [] 137 | }, 138 | "execution_count": 4 139 | } 140 | ] 141 | }, 142 | { 143 | "cell_type": "markdown", 144 | "metadata": { 145 | "id": "uxDCro_1mh8E", 146 | "colab_type": "text" 147 | }, 148 | "source": [ 149 | "Possiamo accedere alla rappresentazione vettoriale di una parola utilizzando l'oggetto model come se fosse un dizionario." 150 | ] 151 | }, 152 | { 153 | "cell_type": "code", 154 | "metadata": { 155 | "id": "rWTDpWvIWmGo", 156 | "colab_type": "code", 157 | "outputId": "6567b2d5-b064-4565-b6ec-12e65541b99a", 158 | "colab": { 159 | "base_uri": "https://localhost:8080/", 160 | "height": 891 161 | } 162 | }, 163 | "source": [ 164 | "print(model[\"man\"].shape)\n", 165 | "print(model[\"man\"])" 166 | ], 167 | "execution_count": 5, 168 | "outputs": [ 169 | { 170 | "output_type": "stream", 171 | "text": [ 172 | "(300,)\n", 173 | "[ 0.32617188 0.13085938 0.03466797 -0.08300781 0.08984375 -0.04125977\n", 174 | " -0.19824219 0.00689697 0.14355469 0.0019455 0.02880859 -0.25\n", 175 | " -0.08398438 -0.15136719 -0.10205078 0.04077148 -0.09765625 0.05932617\n", 176 | " 0.02978516 -0.10058594 -0.13085938 0.001297 0.02612305 -0.27148438\n", 177 | " 0.06396484 -0.19140625 -0.078125 0.25976562 0.375 -0.04541016\n", 178 | " 0.16210938 0.13671875 -0.06396484 -0.02062988 -0.09667969 0.25390625\n", 179 | " 0.24804688 -0.12695312 0.07177734 0.3203125 0.03149414 -0.03857422\n", 180 | " 0.21191406 -0.00811768 0.22265625 -0.13476562 -0.07617188 0.01049805\n", 181 | " -0.05175781 0.03808594 -0.13378906 0.125 0.0559082 -0.18261719\n", 182 | " 0.08154297 -0.08447266 -0.07763672 -0.04345703 0.08105469 -0.01092529\n", 183 | " 0.17480469 0.30664062 -0.04321289 -0.01416016 0.09082031 -0.00927734\n", 184 | " -0.03442383 -0.11523438 0.12451172 -0.0246582 0.08544922 0.14355469\n", 185 | " -0.27734375 0.03662109 -0.11035156 0.13085938 -0.01721191 -0.08056641\n", 186 | " -0.00708008 -0.02954102 0.30078125 -0.09033203 0.03149414 -0.18652344\n", 187 | " -0.11181641 0.10253906 -0.25976562 -0.02209473 0.16796875 -0.05322266\n", 188 | " -0.14550781 -0.01049805 -0.03039551 -0.03857422 0.11523438 -0.0062561\n", 189 | " -0.13964844 0.08007812 0.06103516 -0.15332031 -0.11132812 -0.14160156\n", 190 | " 0.19824219 -0.06933594 0.29296875 -0.16015625 0.20898438 0.00041771\n", 191 | " 0.01831055 -0.20214844 0.04760742 0.05810547 -0.0123291 -0.01989746\n", 192 | " -0.00364685 -0.0135498 -0.08251953 -0.03149414 0.00717163 0.20117188\n", 193 | " 0.08300781 -0.0480957 -0.26367188 -0.09667969 -0.22558594 -0.09667969\n", 194 | " 0.06494141 -0.02502441 0.08496094 0.03198242 -0.07568359 -0.25390625\n", 195 | " -0.11669922 -0.01446533 -0.16015625 -0.00701904 -0.05712891 0.02807617\n", 196 | " -0.09179688 0.25195312 0.24121094 0.06640625 0.12988281 0.17089844\n", 197 | " -0.13671875 0.1875 -0.10009766 -0.04199219 -0.12011719 0.00524902\n", 198 | " 0.15625 -0.203125 -0.07128906 -0.06103516 0.01635742 0.18261719\n", 199 | " 0.03588867 -0.04248047 0.16796875 -0.15039062 -0.16992188 0.01831055\n", 200 | " 0.27734375 -0.01269531 -0.0390625 -0.15429688 0.18457031 -0.07910156\n", 201 | " 0.09033203 -0.02709961 0.08251953 0.06738281 -0.16113281 -0.19628906\n", 202 | " -0.15234375 -0.04711914 0.04760742 0.05908203 -0.16894531 -0.14941406\n", 203 | " 0.12988281 0.04321289 0.02624512 -0.1796875 -0.19628906 0.06445312\n", 204 | " 0.08935547 0.1640625 -0.03808594 -0.09814453 -0.01483154 0.1875\n", 205 | " 0.12792969 0.22753906 0.01818848 -0.07958984 -0.11376953 -0.06933594\n", 206 | " -0.15527344 -0.08105469 -0.09277344 -0.11328125 -0.15136719 -0.08007812\n", 207 | " -0.05126953 -0.15332031 0.11669922 0.06835938 0.0324707 -0.33984375\n", 208 | " -0.08154297 -0.08349609 0.04003906 0.04907227 -0.24121094 -0.13476562\n", 209 | " -0.05932617 0.12158203 -0.34179688 0.16503906 0.06176758 -0.18164062\n", 210 | " 0.20117188 -0.07714844 0.1640625 0.00402832 0.30273438 -0.10009766\n", 211 | " -0.13671875 -0.05957031 0.0625 -0.21289062 -0.06542969 0.1796875\n", 212 | " -0.07763672 -0.01928711 -0.15039062 -0.00106049 0.03417969 0.03344727\n", 213 | " 0.19335938 0.01965332 -0.19921875 -0.10644531 0.01525879 0.00927734\n", 214 | " 0.01416016 -0.02392578 0.05883789 0.02368164 0.125 0.04760742\n", 215 | " -0.05566406 0.11572266 0.14746094 0.1015625 -0.07128906 -0.07714844\n", 216 | " -0.12597656 0.0291748 0.09521484 -0.12402344 -0.109375 -0.12890625\n", 217 | " 0.16308594 0.28320312 -0.03149414 0.12304688 -0.23242188 -0.09375\n", 218 | " -0.12988281 0.0135498 -0.03881836 -0.08251953 0.00897217 0.16308594\n", 219 | " 0.10546875 -0.13867188 -0.16503906 -0.03857422 0.10839844 -0.10498047\n", 220 | " 0.06396484 0.38867188 -0.05981445 -0.0612793 -0.10449219 -0.16796875\n", 221 | " 0.07177734 0.13964844 0.15527344 -0.03125 -0.20214844 -0.12988281\n", 222 | " -0.10058594 -0.06396484 -0.08349609 -0.30273438 -0.08007812 0.02099609]\n" 223 | ], 224 | "name": "stdout" 225 | } 226 | ] 227 | }, 228 | { 229 | "cell_type": "markdown", 230 | "metadata": { 231 | "id": "mQ75Nonomo8f", 232 | "colab_type": "text" 233 | }, 234 | "source": [ 235 | "Calcolando la **cosine similarity** tra le rappresentazioni vettoriali di due parole possiamo sapere quanto esse sono simili.\n", 236 | "
\n", 237 | "**NOTA BENE**\n", 238 | "
\n", 239 | "La funzione *cosine(u,v)* di scipy calcola la distanza del coseno, possiamo trasformare la distanza in similitudine sottrando tale distanza a 1." 240 | ] 241 | }, 242 | { 243 | "cell_type": "code", 244 | "metadata": { 245 | "id": "rDZ9AYKEa8KO", 246 | "colab_type": "code", 247 | "outputId": "c73971bf-6572-465e-8a09-ee31e5d1cd16", 248 | "colab": { 249 | "base_uri": "https://localhost:8080/", 250 | "height": 34 251 | } 252 | }, 253 | "source": [ 254 | "from scipy.spatial.distance import cosine\n", 255 | "\n", 256 | "1-cosine(model[\"man\"],model[\"boy\"])" 257 | ], 258 | "execution_count": 6, 259 | "outputs": [ 260 | { 261 | "output_type": "execute_result", 262 | "data": { 263 | "text/plain": [ 264 | "0.6824870705604553" 265 | ] 266 | }, 267 | "metadata": { 268 | "tags": [] 269 | }, 270 | "execution_count": 6 271 | } 272 | ] 273 | }, 274 | { 275 | "cell_type": "markdown", 276 | "metadata": { 277 | "id": "v9TDXWzinW5A", 278 | "colab_type": "text" 279 | }, 280 | "source": [ 281 | "L'oggetto BOH ha il metodo *.similarity(word1, word2)* già implementato per il calcolo diretto della similitudine di due parole." 282 | ] 283 | }, 284 | { 285 | "cell_type": "code", 286 | "metadata": { 287 | "id": "GPmc3PsoVNLM", 288 | "colab_type": "code", 289 | "outputId": "d99169f3-6a23-4197-dacb-79974163e706", 290 | "colab": { 291 | "base_uri": "https://localhost:8080/", 292 | "height": 106 293 | } 294 | }, 295 | "source": [ 296 | "print(model.similarity(\"man\",\"boy\")) # queste parole sono molto simili\n", 297 | "print(model.similarity(\"pizza\",\"mouse\")) # queste parole sono molto diverse (o almeno spero che lo siano)" 298 | ], 299 | "execution_count": 7, 300 | "outputs": [ 301 | { 302 | "output_type": "stream", 303 | "text": [ 304 | "0.68248713\n", 305 | "0.042691886\n" 306 | ], 307 | "name": "stdout" 308 | }, 309 | { 310 | "output_type": "stream", 311 | "text": [ 312 | "/usr/local/lib/python3.6/dist-packages/gensim/matutils.py:737: FutureWarning: Conversion of the second argument of issubdtype from `int` to `np.signedinteger` is deprecated. In future, it will be treated as `np.int64 == np.dtype(int).type`.\n", 313 | " if np.issubdtype(vec.dtype, np.int):\n" 314 | ], 315 | "name": "stderr" 316 | } 317 | ] 318 | }, 319 | { 320 | "cell_type": "markdown", 321 | "metadata": { 322 | "id": "j0ZCreGvYzOE", 323 | "colab_type": "text" 324 | }, 325 | "source": [ 326 | "**ATTENZIONE**\n", 327 | "
\n", 328 | "Le celle di codice che seguono necessitano di molta RAM e fanno crashare Google Colaboratory, eseguile in locale se hai un PC con almeno 8 gb di RAM." 329 | ] 330 | }, 331 | { 332 | "cell_type": "markdown", 333 | "metadata": { 334 | "id": "xbn2vbuenmcy", 335 | "colab_type": "text" 336 | }, 337 | "source": [ 338 | "Possiamo cercare le parole più simili ad una nostra parola chiave usando il metodo *.most_similar*." 339 | ] 340 | }, 341 | { 342 | "cell_type": "code", 343 | "metadata": { 344 | "id": "Wg_obKSuZyke", 345 | "colab_type": "code", 346 | "colab": {} 347 | }, 348 | "source": [ 349 | "print(model.most_similar(positive=['shocked'], topn=10))" 350 | ], 351 | "execution_count": 0, 352 | "outputs": [] 353 | }, 354 | { 355 | "cell_type": "markdown", 356 | "metadata": { 357 | "id": "h99PSXVjn4HD", 358 | "colab_type": "text" 359 | }, 360 | "source": [ 361 | "Utilizzando questo stesso metodo possiamo anche eseguire ricerche più complesse, come le parole più simili a delle determinate parole chiave, passate all'interno del parametro *positive* ma contrarie ad altre parole chiave, passate all'interno del parametro *negative*." 362 | ] 363 | }, 364 | { 365 | "cell_type": "code", 366 | "metadata": { 367 | "id": "81DI8i4GAMOG", 368 | "colab_type": "code", 369 | "colab": {} 370 | }, 371 | "source": [ 372 | "print(model.most_similar(positive=['woman', 'king'], negative=['man'])) " 373 | ], 374 | "execution_count": 0, 375 | "outputs": [] 376 | }, 377 | { 378 | "cell_type": "markdown", 379 | "metadata": { 380 | "id": "epJq20ZDoKJ7", 381 | "colab_type": "text" 382 | }, 383 | "source": [ 384 | "Un'altro metodo utile è *.doesnt_match(words)* che prendendo in input una serie di parole ritorna quella meno attinente alle altre." 385 | ] 386 | }, 387 | { 388 | "cell_type": "code", 389 | "metadata": { 390 | "id": "l0nkCxoqX4LU", 391 | "colab_type": "code", 392 | "colab": {} 393 | }, 394 | "source": [ 395 | "print(model.doesnt_match(\"breakfast cereal dinner lunch\".split()))" 396 | ], 397 | "execution_count": 0, 398 | "outputs": [] 399 | } 400 | ] 401 | } -------------------------------------------------------------------------------- /09 - Word embedding e Word2Vec/word_embedding.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "name": "word_embedding.ipynb", 7 | "version": "0.3.2", 8 | "provenance": [], 9 | "include_colab_link": true 10 | }, 11 | "kernelspec": { 12 | "name": "python3", 13 | "display_name": "Python 3" 14 | } 15 | }, 16 | "cells": [ 17 | { 18 | "cell_type": "markdown", 19 | "metadata": { 20 | "id": "view-in-github", 21 | "colab_type": "text" 22 | }, 23 | "source": [ 24 | "\"Open" 25 | ] 26 | }, 27 | { 28 | "cell_type": "markdown", 29 | "metadata": { 30 | "id": "sNb6_Q5_f2vE", 31 | "colab_type": "text" 32 | }, 33 | "source": [ 34 | "## Word embedding\n", 35 | "Il **Word embedding** è un modello che ci permette di generare una serie di vettori (embedding vectors) ognuno dei quali quantifica una caratteristica delle parole. In questo notebook creeremo una rete neurale artificiale per classsificare recensioni come positive o negative usando il Word Embedding per codificare le recensioni." 36 | ] 37 | }, 38 | { 39 | "cell_type": "code", 40 | "metadata": { 41 | "id": "9cSDivbYhDhW", 42 | "colab_type": "code", 43 | "colab": { 44 | "base_uri": "https://localhost:8080/", 45 | "height": 34 46 | }, 47 | "outputId": "85816c17-8127-416d-d852-a2fc5bd260bd" 48 | }, 49 | "source": [ 50 | "!pip install numpy==1.16.2" 51 | ], 52 | "execution_count": 1, 53 | "outputs": [ 54 | { 55 | "output_type": "stream", 56 | "text": [ 57 | "Requirement already satisfied: numpy==1.16.2 in /usr/local/lib/python3.6/dist-packages (1.16.2)\n" 58 | ], 59 | "name": "stdout" 60 | } 61 | ] 62 | }, 63 | { 64 | "cell_type": "markdown", 65 | "metadata": { 66 | "id": "LyB8q8Aw1tqp", 67 | "colab_type": "text" 68 | }, 69 | "source": [ 70 | "## Prepariamo i dati\n", 71 | "In precedenza abbiamo caricato e preprocessato manualmente l'IMDB Movies Review Dataset, in questo caso utilizziamo direttamente il dataset già preprocessato che ci mette a disposizione Keras.\n", 72 | "
**ATTENZIONE**
\n", 73 | "Se caricando il dataset ottieni questo errore:
\n", 74 | "*ValueError: Object arrays cannot be loaded when allow_pickle=False*\n", 75 | "
\n", 76 | "questo è casuato da un bug nell'ultima versione di keras, per correggerlo esegui il downgrade di numpy usando la cella di codice qui sotto e riavvia il kernel (su Colaboratory seleziona Runtime dalla barra dei comandi e clicca su Restart Runtime)." 77 | ] 78 | }, 79 | { 80 | "cell_type": "code", 81 | "metadata": { 82 | "id": "MP00t5BP3PNL", 83 | "colab_type": "code", 84 | "colab": {} 85 | }, 86 | "source": [ 87 | "!pip install numpy==1.16.2" 88 | ], 89 | "execution_count": 0, 90 | "outputs": [] 91 | }, 92 | { 93 | "cell_type": "code", 94 | "metadata": { 95 | "id": "zVFYLaPrf054", 96 | "colab_type": "code", 97 | "colab": { 98 | "base_uri": "https://localhost:8080/", 99 | "height": 51 100 | }, 101 | "outputId": "aed8a090-3a31-4f2f-9f8e-0eea866111dc" 102 | }, 103 | "source": [ 104 | "import numpy as np\n", 105 | "from keras.datasets import imdb \n", 106 | "\n", 107 | "num_words = 10000\n", 108 | "\n", 109 | "(X_train, y_train), (X_test, y_test) = imdb.load_data(num_words=num_words)\n", 110 | "\n", 111 | "print(\"Numero di esempi nel train set: %d\" % len(X_train))\n", 112 | "print(\"Numero di esempi nel test set: %d\" % len(X_test))" 113 | ], 114 | "execution_count": 22, 115 | "outputs": [ 116 | { 117 | "output_type": "stream", 118 | "text": [ 119 | "Numero di esempi nel train set: 25000\n", 120 | "Numero di esempi nel test set: 25000\n" 121 | ], 122 | "name": "stdout" 123 | } 124 | ] 125 | }, 126 | { 127 | "cell_type": "markdown", 128 | "metadata": { 129 | "id": "6jvHkFhC3T30", 130 | "colab_type": "text" 131 | }, 132 | "source": [ 133 | "Ogni riga della lista con le features corrisponde ad una frase, ogni colonna contiene l'indice di una parola all'interno del vocabolario dell'intero corpus di testo. Il vettore con il target contiene un unico valore che può essere 0 per una recensione negativa o 1 per una recensione positiva.
\n", 134 | "Definiamo una funzione che ci permette di ricostruire la frase partendo dagli indici, per farlo abbiamo bisogno del vocabolario che mappa le parole agli indici, possiamo ottenerlo con il metodo *.get_word_index()*.\n", 135 | "
\n", 136 | "**NOTA BENE**\n", 137 | "
\n", 138 | "Gli indici delle parole hanno un'offset di 3, quindi per ottenere l'indice corretto per il vocabolario dovremo sottrarre 3 all'indice della parola contenuto nella frase." 139 | ] 140 | }, 141 | { 142 | "cell_type": "code", 143 | "metadata": { 144 | "id": "lddFN1OX52C3", 145 | "colab_type": "code", 146 | "colab": { 147 | "base_uri": "https://localhost:8080/", 148 | "height": 54 149 | }, 150 | "outputId": "f21ae533-fb43-478f-84ef-f5644e55193a" 151 | }, 152 | "source": [ 153 | "word_index = imdb.get_word_index()\n", 154 | "index_word = dict([(value, key) for (key, value) in word_index.items()])\n", 155 | "\n", 156 | "def vec_to_text(x):\n", 157 | " \n", 158 | " text = [index_word.get(i-3,'?') for i in x]\n", 159 | " return \" \".join(text)\n", 160 | " \n", 161 | "vec_to_text(X_test[0])" 162 | ], 163 | "execution_count": 58, 164 | "outputs": [ 165 | { 166 | "output_type": "execute_result", 167 | "data": { 168 | "text/plain": [ 169 | "\"terrible performances the show is flat flat flat br br i don't know how michael madison could have allowed this one on his plate he almost seemed to know this wasn't going to work out and his performance was quite ? so all you madison fans give this a miss\"" 170 | ] 171 | }, 172 | "metadata": { 173 | "tags": [] 174 | }, 175 | "execution_count": 58 176 | } 177 | ] 178 | }, 179 | { 180 | "cell_type": "markdown", 181 | "metadata": { 182 | "id": "pCvLErNe8aSk", 183 | "colab_type": "text" 184 | }, 185 | "source": [ 186 | "Ovviamente le recensioni avranno lunghezza differente, calcoliamo la lunghezza della più lunga e della più corta." 187 | ] 188 | }, 189 | { 190 | "cell_type": "code", 191 | "metadata": { 192 | "id": "IpphdUrrg-gD", 193 | "colab_type": "code", 194 | "colab": { 195 | "base_uri": "https://localhost:8080/", 196 | "height": 51 197 | }, 198 | "outputId": "fcfca3e4-55af-493f-ce75-e117bf87b61e" 199 | }, 200 | "source": [ 201 | "longest_review = max(X_train,key=len)\n", 202 | "shortest_review = min(X_train,key=len)\n", 203 | "\n", 204 | "print(\"La review più lunga ha %d parole\" % len(longest_review))\n", 205 | "print(\"La review più corta ha %d parole\" % len(shortest_review))" 206 | ], 207 | "execution_count": 24, 208 | "outputs": [ 209 | { 210 | "output_type": "stream", 211 | "text": [ 212 | "La review più lunga ha 2494 parole\n", 213 | "La review più corta ha 11 parole\n" 214 | ], 215 | "name": "stdout" 216 | } 217 | ] 218 | }, 219 | { 220 | "cell_type": "markdown", 221 | "metadata": { 222 | "id": "02dun4qF3bjU", 223 | "colab_type": "text" 224 | }, 225 | "source": [ 226 | "Per rendere le features un buon input per il nostro modello dobbiamo fare in modo che ogni frase abbia la stessa lunghezza, per farlo possiamo usare la funzione *pad_sequences(text)* di keras, che riduce tutte le frasi ad una lunghezza prefissata troncando quelle troppo lunghe e aggiungendo degli zeri a quelle troppo brevi. Usiamo una lunghezza comune di 50 parole." 227 | ] 228 | }, 229 | { 230 | "cell_type": "code", 231 | "metadata": { 232 | "id": "0NybngBzhRGQ", 233 | "colab_type": "code", 234 | "colab": { 235 | "base_uri": "https://localhost:8080/", 236 | "height": 34 237 | }, 238 | "outputId": "c652169c-e934-47d6-bc5b-1a22297cab8d" 239 | }, 240 | "source": [ 241 | "from keras.preprocessing.sequence import pad_sequences\n", 242 | "\n", 243 | "maxlen = 50\n", 244 | "\n", 245 | "X_train = pad_sequences(X_train, maxlen = maxlen)\n", 246 | "X_test = pad_sequences(X_test, maxlen = maxlen)\n", 247 | "\n", 248 | "X_train.shape" 249 | ], 250 | "execution_count": 25, 251 | "outputs": [ 252 | { 253 | "output_type": "execute_result", 254 | "data": { 255 | "text/plain": [ 256 | "(25000, 50)" 257 | ] 258 | }, 259 | "metadata": { 260 | "tags": [] 261 | }, 262 | "execution_count": 25 263 | } 264 | ] 265 | }, 266 | { 267 | "cell_type": "markdown", 268 | "metadata": { 269 | "id": "F-M5pPcD1wB2", 270 | "colab_type": "text" 271 | }, 272 | "source": [ 273 | "## Creiamo il modello\n", 274 | "Possiamo utilizzare l'embedding come se fosse uno strato della nostra rete neurale che verrà anch'esso ottimizzato durante la fase di addestramento. Creiamo la rete aggiungendo al primo strato uno strato di embedding, dopodichè aggiungiamo un'altro strato che utilizza la classe Flatten() di keras per convertire la matrice che contiene la rappresentazione vettoriale di una frase in un vettore, unendo tutte le righe una dietro l'altra. Infine aggiungiamo uno strato di output per eseguire la classificazione binaria." 275 | ] 276 | }, 277 | { 278 | "cell_type": "code", 279 | "metadata": { 280 | "id": "JiflX3qnhUIq", 281 | "colab_type": "code", 282 | "colab": { 283 | "base_uri": "https://localhost:8080/", 284 | "height": 240 285 | }, 286 | "outputId": "38b4e184-f03b-4061-aed0-274704469fc5" 287 | }, 288 | "source": [ 289 | "from keras.models import Sequential\n", 290 | "from keras.layers import Embedding, SimpleRNN, Dense, Flatten\n", 291 | "\n", 292 | "model = Sequential()\n", 293 | "\n", 294 | "model.add(Embedding(num_words, 50, input_length=maxlen))\n", 295 | "model.add(Flatten())\n", 296 | "model.add(Dense(1, activation='sigmoid'))\n", 297 | "\n", 298 | "model.summary()" 299 | ], 300 | "execution_count": 37, 301 | "outputs": [ 302 | { 303 | "output_type": "stream", 304 | "text": [ 305 | "_________________________________________________________________\n", 306 | "Layer (type) Output Shape Param # \n", 307 | "=================================================================\n", 308 | "embedding_10 (Embedding) (None, 50, 50) 500000 \n", 309 | "_________________________________________________________________\n", 310 | "flatten_4 (Flatten) (None, 2500) 0 \n", 311 | "_________________________________________________________________\n", 312 | "dense_5 (Dense) (None, 1) 2501 \n", 313 | "=================================================================\n", 314 | "Total params: 502,501\n", 315 | "Trainable params: 502,501\n", 316 | "Non-trainable params: 0\n", 317 | "_________________________________________________________________\n" 318 | ], 319 | "name": "stdout" 320 | } 321 | ] 322 | }, 323 | { 324 | "cell_type": "markdown", 325 | "metadata": { 326 | "id": "ueLGoyMK4O7A", 327 | "colab_type": "text" 328 | }, 329 | "source": [ 330 | "Compiliamo il modello e avviamo l'addestramento per 10 epoche." 331 | ] 332 | }, 333 | { 334 | "cell_type": "code", 335 | "metadata": { 336 | "id": "XD6yja5whYuZ", 337 | "colab_type": "code", 338 | "colab": { 339 | "base_uri": "https://localhost:8080/", 340 | "height": 414 341 | }, 342 | "outputId": "91cfc754-6c2c-41d5-e8e2-27b18bcc945e" 343 | }, 344 | "source": [ 345 | "model.compile(loss='binary_crossentropy', optimizer=\"adam\", metrics=['accuracy'])\n", 346 | "model.fit(X_train, y_train, batch_size=512, validation_split=0.2, epochs=10)" 347 | ], 348 | "execution_count": 38, 349 | "outputs": [ 350 | { 351 | "output_type": "stream", 352 | "text": [ 353 | "Train on 20000 samples, validate on 5000 samples\n", 354 | "Epoch 1/10\n", 355 | "20000/20000 [==============================] - 1s 61us/step - loss: 0.6890 - acc: 0.5621 - val_loss: 0.6786 - val_acc: 0.6538\n", 356 | "Epoch 2/10\n", 357 | "20000/20000 [==============================] - 1s 35us/step - loss: 0.6346 - acc: 0.7770 - val_loss: 0.6023 - val_acc: 0.7410\n", 358 | "Epoch 3/10\n", 359 | "20000/20000 [==============================] - 1s 35us/step - loss: 0.5101 - acc: 0.8193 - val_loss: 0.4969 - val_acc: 0.7790\n", 360 | "Epoch 4/10\n", 361 | "20000/20000 [==============================] - 1s 37us/step - loss: 0.3932 - acc: 0.8570 - val_loss: 0.4415 - val_acc: 0.7982\n", 362 | "Epoch 5/10\n", 363 | "20000/20000 [==============================] - 1s 36us/step - loss: 0.3183 - acc: 0.8892 - val_loss: 0.4151 - val_acc: 0.8054\n", 364 | "Epoch 6/10\n", 365 | "20000/20000 [==============================] - 1s 35us/step - loss: 0.2630 - acc: 0.9158 - val_loss: 0.4053 - val_acc: 0.8076\n", 366 | "Epoch 7/10\n", 367 | "20000/20000 [==============================] - 1s 36us/step - loss: 0.2191 - acc: 0.9364 - val_loss: 0.4021 - val_acc: 0.8112\n", 368 | "Epoch 8/10\n", 369 | "20000/20000 [==============================] - 1s 35us/step - loss: 0.1822 - acc: 0.9553 - val_loss: 0.4048 - val_acc: 0.8116\n", 370 | "Epoch 9/10\n", 371 | "20000/20000 [==============================] - 1s 35us/step - loss: 0.1494 - acc: 0.9709 - val_loss: 0.4085 - val_acc: 0.8120\n", 372 | "Epoch 10/10\n", 373 | "20000/20000 [==============================] - 1s 35us/step - loss: 0.1217 - acc: 0.9814 - val_loss: 0.4146 - val_acc: 0.8120\n" 374 | ], 375 | "name": "stdout" 376 | }, 377 | { 378 | "output_type": "execute_result", 379 | "data": { 380 | "text/plain": [ 381 | "" 382 | ] 383 | }, 384 | "metadata": { 385 | "tags": [] 386 | }, 387 | "execution_count": 38 388 | } 389 | ] 390 | }, 391 | { 392 | "cell_type": "code", 393 | "metadata": { 394 | "id": "-JXeWNcxhfrd", 395 | "colab_type": "code", 396 | "colab": { 397 | "base_uri": "https://localhost:8080/", 398 | "height": 51 399 | }, 400 | "outputId": "61b5b9c2-936c-47c5-b4c5-446ca0b37cdb" 401 | }, 402 | "source": [ 403 | "model.evaluate(X_test, y_test)" 404 | ], 405 | "execution_count": 39, 406 | "outputs": [ 407 | { 408 | "output_type": "stream", 409 | "text": [ 410 | "25000/25000 [==============================] - 1s 31us/step\n" 411 | ], 412 | "name": "stdout" 413 | }, 414 | { 415 | "output_type": "execute_result", 416 | "data": { 417 | "text/plain": [ 418 | "[0.40605927324295044, 0.815]" 419 | ] 420 | }, 421 | "metadata": { 422 | "tags": [] 423 | }, 424 | "execution_count": 39 425 | } 426 | ] 427 | }, 428 | { 429 | "cell_type": "markdown", 430 | "metadata": { 431 | "id": "q1LAyqsu1zs4", 432 | "colab_type": "text" 433 | }, 434 | "source": [ 435 | "## Otteniamo gli embedding\n", 436 | "Se volessimo conoscere gli embedding che il modello genera per una determinata frase possiamo farlo creando un nuovo modello che da in output l'output dell'embedding che abbiamo addestrato. Keras ci da la possibilità di accedere ai singoli strati di un modello utilizzato l'attributo *.layers*" 437 | ] 438 | }, 439 | { 440 | "cell_type": "code", 441 | "metadata": { 442 | "id": "qTPAimqL5NZq", 443 | "colab_type": "code", 444 | "colab": { 445 | "base_uri": "https://localhost:8080/", 446 | "height": 34 447 | }, 448 | "outputId": "d87a8aac-95af-4360-d5e5-af4e4f5ea661" 449 | }, 450 | "source": [ 451 | "model.layers[0]" 452 | ], 453 | "execution_count": 41, 454 | "outputs": [ 455 | { 456 | "output_type": "execute_result", 457 | "data": { 458 | "text/plain": [ 459 | "" 460 | ] 461 | }, 462 | "metadata": { 463 | "tags": [] 464 | }, 465 | "execution_count": 41 466 | } 467 | ] 468 | }, 469 | { 470 | "cell_type": "markdown", 471 | "metadata": { 472 | "id": "meavLoRp5Qg0", 473 | "colab_type": "text" 474 | }, 475 | "source": [ 476 | "Utilizzando le API Funzionali di Keras (ne parleremo più avanti) possiamo creare un modello che prende in input lo stesso input del modello addestrato e da in output l'output dell'embedding." 477 | ] 478 | }, 479 | { 480 | "cell_type": "code", 481 | "metadata": { 482 | "id": "dqGhALMG06Y0", 483 | "colab_type": "code", 484 | "colab": {} 485 | }, 486 | "source": [ 487 | "from keras.models import Model\n", 488 | "\n", 489 | "embedding_model = Model(inputs=model.input, outputs=model.layers[0].output)" 490 | ], 491 | "execution_count": 0, 492 | "outputs": [] 493 | }, 494 | { 495 | "cell_type": "markdown", 496 | "metadata": { 497 | "id": "-ZpItTpc5fIt", 498 | "colab_type": "text" 499 | }, 500 | "source": [ 501 | "Utilizzando il metodo *.predict(x)* otterremo una matrice con la rappresentazione vettoriale di ogni parola della frase." 502 | ] 503 | }, 504 | { 505 | "cell_type": "code", 506 | "metadata": { 507 | "id": "eTh6OMit1VJd", 508 | "colab_type": "code", 509 | "colab": { 510 | "base_uri": "https://localhost:8080/", 511 | "height": 240 512 | }, 513 | "outputId": "6c3bb837-106b-473b-a5eb-7d8cbf9fbb2e" 514 | }, 515 | "source": [ 516 | "x = np.array([X_test[0]])\n", 517 | "\n", 518 | "embedding_model.predict(x)" 519 | ], 520 | "execution_count": 42, 521 | "outputs": [ 522 | { 523 | "output_type": "execute_result", 524 | "data": { 525 | "text/plain": [ 526 | "array([[[ 0.30276826, 0.111716 , 0.17554781, ..., 0.2054588 ,\n", 527 | " -0.23213504, 0.12865287],\n", 528 | " [-0.10857813, 0.00208598, -0.11951214, ..., -0.20470296,\n", 529 | " -0.12110917, -0.09332115],\n", 530 | " [-0.05576379, 0.0109272 , -0.00774001, ..., 0.02854038,\n", 531 | " -0.02343158, 0.02618085],\n", 532 | " ...,\n", 533 | " [ 0.08926877, -0.00070353, -0.05446988, ..., 0.07803367,\n", 534 | " -0.0772426 , -0.10260648],\n", 535 | " [-0.0244258 , -0.0769368 , -0.12284474, ..., -0.02184814,\n", 536 | " 0.03313072, -0.04578592],\n", 537 | " [-0.07755034, 0.29535306, -0.04420415, ..., -0.05049261,\n", 538 | " -0.04422899, -0.03766544]]], dtype=float32)" 539 | ] 540 | }, 541 | "metadata": { 542 | "tags": [] 543 | }, 544 | "execution_count": 42 545 | } 546 | ] 547 | } 548 | ] 549 | } -------------------------------------------------------------------------------- /10 - Reti Ricorrenti e Text Generation/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProfAI/nlp00/bb5e60ccc24e536a0927f544d4f903df03624b85/10 - Reti Ricorrenti e Text Generation/.DS_Store -------------------------------------------------------------------------------- /10 - Reti Ricorrenti e Text Generation/model/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProfAI/nlp00/bb5e60ccc24e536a0927f544d4f903df03624b85/10 - Reti Ricorrenti e Text Generation/model/.DS_Store -------------------------------------------------------------------------------- /10 - Reti Ricorrenti e Text Generation/model/dante_500.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProfAI/nlp00/bb5e60ccc24e536a0927f544d4f903df03624b85/10 - Reti Ricorrenti e Text Generation/model/dante_500.h5 -------------------------------------------------------------------------------- /11- Seq2Seq e Machine Translation/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProfAI/nlp00/bb5e60ccc24e536a0927f544d4f903df03624b85/11- Seq2Seq e Machine Translation/.DS_Store -------------------------------------------------------------------------------- /11- Seq2Seq e Machine Translation/model/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProfAI/nlp00/bb5e60ccc24e536a0927f544d4f903df03624b85/11- Seq2Seq e Machine Translation/model/.DS_Store -------------------------------------------------------------------------------- /11- Seq2Seq e Machine Translation/model/translator_500.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProfAI/nlp00/bb5e60ccc24e536a0927f544d4f903df03624b85/11- Seq2Seq e Machine Translation/model/translator_500.h5 -------------------------------------------------------------------------------- /11- Seq2Seq e Machine Translation/model/translator_decoder_500.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProfAI/nlp00/bb5e60ccc24e536a0927f544d4f903df03624b85/11- Seq2Seq e Machine Translation/model/translator_decoder_500.h5 -------------------------------------------------------------------------------- /11- Seq2Seq e Machine Translation/model/translator_encoder_500.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProfAI/nlp00/bb5e60ccc24e536a0927f544d4f903df03624b85/11- Seq2Seq e Machine Translation/model/translator_encoder_500.h5 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Natural Language Processing con Python: il Corso Pratico 2 | -------------------------------------------------------------------------------- /X - Workspace/Untitled9.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "name": "Untitled9.ipynb", 7 | "version": "0.3.2", 8 | "provenance": [], 9 | "include_colab_link": true 10 | }, 11 | "kernelspec": { 12 | "name": "python3", 13 | "display_name": "Python 3" 14 | } 15 | }, 16 | "cells": [ 17 | { 18 | "cell_type": "markdown", 19 | "metadata": { 20 | "id": "view-in-github", 21 | "colab_type": "text" 22 | }, 23 | "source": [ 24 | "\"Open" 25 | ] 26 | }, 27 | { 28 | "metadata": { 29 | "id": "q3cb6BFDHJ44", 30 | "colab_type": "code", 31 | "colab": { 32 | "base_uri": "https://localhost:8080/", 33 | "height": 226 34 | }, 35 | "outputId": "9454e099-ad14-452b-d9a4-85a3c4abc95c" 36 | }, 37 | "cell_type": "code", 38 | "source": [ 39 | "!wget https://clarin.eurac.edu/repository/xmlui/bitstream/handle/20.500.12124/3/paisa.raw.utf8.gz" 40 | ], 41 | "execution_count": 2, 42 | "outputs": [ 43 | { 44 | "output_type": "stream", 45 | "text": [ 46 | "--2019-04-20 14:26:47-- https://clarin.eurac.edu/repository/xmlui/bitstream/handle/20.500.12124/3/paisa.raw.utf8.gz\n", 47 | "Resolving clarin.eurac.edu (clarin.eurac.edu)... 46.18.24.111\n", 48 | "Connecting to clarin.eurac.edu (clarin.eurac.edu)|46.18.24.111|:443... connected.\n", 49 | "HTTP request sent, awaiting response... 200 OK\n", 50 | "Length: 546911754 (522M) [application/gzip]\n", 51 | "Saving to: ‘paisa.raw.utf8.gz’\n", 52 | "\n", 53 | "paisa.raw.utf8.gz 100%[===================>] 521.58M 5.14MB/s in 1m 48s \n", 54 | "\n", 55 | "2019-04-20 14:28:36 (4.84 MB/s) - ‘paisa.raw.utf8.gz’ saved [546911754/546911754]\n", 56 | "\n" 57 | ], 58 | "name": "stdout" 59 | } 60 | ] 61 | }, 62 | { 63 | "metadata": { 64 | "id": "_kJMMCZmIgvK", 65 | "colab_type": "code", 66 | "colab": {} 67 | }, 68 | "cell_type": "code", 69 | "source": [ 70 | "!zcat paisa.raw.utf8.gz > paisa.raw" 71 | ], 72 | "execution_count": 0, 73 | "outputs": [] 74 | }, 75 | { 76 | "metadata": { 77 | "id": "A8S_sktYJwaO", 78 | "colab_type": "code", 79 | "colab": { 80 | "base_uri": "https://localhost:8080/", 81 | "height": 34 82 | }, 83 | "outputId": "cf2719e2-52c1-4e77-952e-58041d9df31a" 84 | }, 85 | "cell_type": "code", 86 | "source": [ 87 | "!ls -sh paisa.raw" 88 | ], 89 | "execution_count": 6, 90 | "outputs": [ 91 | { 92 | "output_type": "stream", 93 | "text": [ 94 | "1.4G paisa.raw\n" 95 | ], 96 | "name": "stdout" 97 | } 98 | ] 99 | }, 100 | { 101 | "metadata": { 102 | "id": "r6Jb2lDdJ4rJ", 103 | "colab_type": "code", 104 | "colab": {} 105 | }, 106 | "cell_type": "code", 107 | "source": [ 108 | "max_lines = 10000\n", 109 | "\n", 110 | "corpus = \"\"\n", 111 | "\n", 112 | "with open(\"paisa.raw\") as text_file:\n", 113 | " for i,text in enumerate(text_file.readlines()):\n", 114 | " corpus+=text\n", 115 | " if(i>10000):\n", 116 | " break" 117 | ], 118 | "execution_count": 0, 119 | "outputs": [] 120 | }, 121 | { 122 | "metadata": { 123 | "id": "l8fKWhRlKLPR", 124 | "colab_type": "code", 125 | "colab": { 126 | "base_uri": "https://localhost:8080/", 127 | "height": 34 128 | }, 129 | "outputId": "e761f185-125a-4c8f-ca6d-87fad16c09de" 130 | }, 131 | "cell_type": "code", 132 | "source": [ 133 | "len(corpus)" 134 | ], 135 | "execution_count": 5, 136 | "outputs": [ 137 | { 138 | "output_type": "execute_result", 139 | "data": { 140 | "text/plain": [ 141 | "3213481" 142 | ] 143 | }, 144 | "metadata": { 145 | "tags": [] 146 | }, 147 | "execution_count": 5 148 | } 149 | ] 150 | }, 151 | { 152 | "metadata": { 153 | "id": "_YDbdrpcLuaY", 154 | "colab_type": "code", 155 | "colab": {} 156 | }, 157 | "cell_type": "code", 158 | "source": [ 159 | "X = corpus.split(\"\n", 197 | "In risposta alla richiesta di un contribuente, l'Agenzia delle Entrate, con la risoluzione 256/E del 20 giugno chiarisce che gli integratori alimentari, ancorché prescritti da uno specialista, non possono beneficiare \"della detrazione d'imposta del 19%, di cui all'art. 15, comma 1, lett. c), del TUIR, riconosciuta esclusivamente per spese mediche e di assistenza specifica (diverse da quelle indicate nell'art. 10, comma 1, lett. b)), per spese chirurgiche, per l'acquisto di medicinali, per prestazioni specialistiche e per protesi dentarie e sanitarie in genere\". La ragione discenderebbe dalla natura stessa degli integratori che \"vengono somministrati, sostanzialmente, per cure dirette ad ottimizzare gli apporti nutrizionali e a migliorare le condizioni fisiologiche, senza per questo essere considerati dei medicinali. In ragione della loro composizione, gli integratori si qualificano, infatti, come prodotti appartenenti all'area alimentare\".\n", 198 | "Rating: 0/5 (0 votes cast)\n", 199 | "Apprendo con vivo stupore quanto riportato nella newletter del 27.06.2008 in merito alla non dertraibilità degli integratori per uso curativo. L'Agenzia delle Entrate del 20.06.08 motiva tale non detraibilità per la natura stessa degli integratori che \"vengono somministrati, sostanzialmente, per cure dirette ad ottimizzare gli apporti nutrizionali e a migliorare le condizioni fisiologiche, senza per questo essere considerati dei medicinali. In ragione della loro composizione, gli integratori si qualificano, infatti, come prodotti appartenenti all'area alimentare\".Tale risposta è in assoluto contrasto con quanto indicato sul settimanale Fisco Oggi del 29.11.2006 che riporto fedelmente:\n", 200 | "R: i prodotti integratori alimentari prescritti da un medico specialista a scopo curativo possono essere detratti ai sensi dell'articolo 15 del Tuir.Mi permetto quindi dissentire da quest'ultima risoluzione anche in considerazione che non tutti \"\" gli integratori servono per ottimizzare gli apporti nutrizionali ecc.Così ad es.nel mio caso che soffro di colesterolemia faccio uso del prodotto denominato Equisterol prescrittomi dal medico di base in luogo delle statine che hanno effetti collaterali sul sistema muscolare,sulle funzionalità renali ed epatiche,memtre a mia moglie che soffre di diverticolsi è stato prescritto l'integratore biologico Enterolactis dopo la cura con antibiotici.E' proprio vero che siamo in un Paese dove non esiste la certezza del diritto!\n", 201 | "\n", 202 | "\n" 203 | ], 204 | "name": "stdout" 205 | } 206 | ] 207 | }, 208 | { 209 | "metadata": { 210 | "id": "MWmfqpvsL-Vg", 211 | "colab_type": "code", 212 | "colab": {} 213 | }, 214 | "cell_type": "code", 215 | "source": [ 216 | "" 217 | ], 218 | "execution_count": 0, 219 | "outputs": [] 220 | } 221 | ] 222 | } --------------------------------------------------------------------------------