From cc33a3e0c26e1962c5fab8ce4684d7f6fb31dadc Mon Sep 17 00:00:00 2001 From: Thais Date: Fri, 12 Jul 2019 16:18:32 -0300 Subject: [PATCH] Adding notebooks with solutions/answers --- 26-nlp/Desafio-gabarito.ipynb | 283 +++ 26-nlp/nlp-gabarito.ipynb | 4517 +++++++++++++++++++++++++++++++++ 2 files changed, 4800 insertions(+) create mode 100644 26-nlp/Desafio-gabarito.ipynb create mode 100644 26-nlp/nlp-gabarito.ipynb diff --git a/26-nlp/Desafio-gabarito.ipynb b/26-nlp/Desafio-gabarito.ipynb new file mode 100644 index 0000000..6619c30 --- /dev/null +++ b/26-nlp/Desafio-gabarito.ipynb @@ -0,0 +1,283 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Aula 26 - NLP\n", + "### Desafio - Possibilidades de melhorar o modelo" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "from sklearn.feature_extraction.text import CountVectorizer\n", + "from sklearn.feature_extraction.text import TfidfVectorizer\n", + "from sklearn.linear_model import LogisticRegression\n", + "from sklearn.naive_bayes import MultinomialNB\n", + "from sklearn.ensemble import GradientBoostingClassifier\n", + "from sklearn.pipeline import Pipeline\n", + "from sklearn.metrics import classification_report\n", + "from utils.confusion_matrix import plot_confusion_matrix\n", + "from utils.to_dense import DenseTransformer\n", + "\n", + "pd.options.display.max_columns = 999\n", + "pd.options.display.max_colwidth = 999" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "train_df = pd.read_pickle('data/processed/train_preprocessed.pickle')\n", + "test_df = pd.read_pickle('data/processed/test_preprocessed.pickle')\n", + "#train_df" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "train_df['y'] = (train_df['polarity'] == 'positive').astype(int)\n", + "test_df['y'] = (test_df['polarity'] == 'positive').astype(int)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "X_train = train_df['norm_text'].values\n", + "y_train = train_df['y'].values\n", + "X_test = test_df['norm_text'].values\n", + "y_test = test_df['y'].values" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "steps = [\n", + " ('vect', CountVectorizer(binary=True)),\n", + "# ('dens', DenseTransformer()),\n", + " ('clf', LogisticRegression())\n", + "]\n", + "\n", + "pipeline = Pipeline(steps)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Confusion matrix, without normalization\n", + "[[16 7]\n", + " [ 0 59]]\n", + "Normalized confusion matrix\n", + "[[ 0.69565217 0.30434783]\n", + " [ 0. 1. ]]\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "sentiment_analyzer = pipeline.fit(X_train, y_train)\n", + "y_pred = sentiment_analyzer.predict(X_test)\n", + "plot_confusion_matrix(y_test, y_pred);\n", + "plot_confusion_matrix(y_test, y_pred, normalize=True);" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "##### Naive Bayes: \n", + "- [Esse post](https://towardsdatascience.com/algorithms-for-text-classification-part-1-naive-bayes-3ff1d116fdd8) explica um pouco da ideia do algoritmo e fala sobre como ele e regressão logística são \"os básicos\" em NLP;\n", + "\n", + "- No Scikit Learn, temos [vários modelos NaiveBayes](https://scikit-learn.org/stable/modules/classes.html#module-sklearn.naive_bayes). " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- De uma olhada no [MultinomialNB](https://scikit-learn.org/0.19/modules/generated/sklearn.naive_bayes.MultinomialNB.html#sklearn.naive_bayes.MultinomialNB), refaça o treinamento usando ele como classificador e compare os resultados.\n", + "\n", + "Dicas: \n", + "1. Você precisará incluir no seu pipeline a classe *DenseTransformer* (do `to_dense.py` do diretório `utils`)\n", + "\n", + "2. Experimente valores diferentes para os parâmetros, especialmente o \"alpha\", que na verdade é o *Laplace Smoothing* explicado [nesse vídeo](https://www.youtube.com/watch?v=gCI-ZC7irbY&t=84s)." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "steps = [\n", + " ('vect', CountVectorizer(binary=True)),\n", + " ('dens', DenseTransformer()),\n", + " ('clf', MultinomialNB(alpha=0,fit_prior=False))\n", + "]\n", + "\n", + "pipeline = Pipeline(steps)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/macbook/anaconda3/envs/tera-env/lib/python3.6/site-packages/sklearn/naive_bayes.py:472: UserWarning: alpha too small will result in numeric errors, setting alpha = 1.0e-10\n", + " 'setting alpha = %.1e' % _ALPHA_MIN)\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Confusion matrix, without normalization\n", + "[[22 1]\n", + " [ 3 56]]\n", + "Normalized confusion matrix\n", + "[[ 0.95652174 0.04347826]\n", + " [ 0.05084746 0.94915254]]\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "sentiment_analyzer = pipeline.fit(X_train, y_train)\n", + "y_pred = sentiment_analyzer.predict(X_test)\n", + "plot_confusion_matrix(y_test, y_pred);\n", + "plot_confusion_matrix(y_test, y_pred, normalize=True);" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Word2Vec" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "[Vídeo introdutório](https://www.youtube.com/watch?v=5PL0TmQhItY)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Veja o [Word2Vec do Gensim](https://radimrehurek.com/gensim/models/word2vec.html#gensim.models.word2vec.Word2Vec) e [esse tutorial](https://www.kaggle.com/pierremegret/gensim-word2vec-tutorial) para utilizá-lo." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "[Aula de NLP da Cinthia](https://github.com/somostera/tera-datascience-out2018/tree/master/26-nlp) de uma turma de Data Science do ano passado: \n", + "- links bastante interessantes no `ReadME`, como o [desse vídeo](https://www.youtube.com/watch?v=ERibwqs9p38) que é uma aula de Word2Vec da Stanford.\n", + "- No [notebook parte 2](https://github.com/somostera/tera-datascience-out2018/blob/master/26-nlp/nlp_parte_2.ipynb) tem Word2Vec;\n", + "- E no [na parte 3](https://github.com/somostera/tera-datascience-out2018/blob/master/26-nlp/nlp_parte_extra.ipynb) tem visualizações." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.5" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/26-nlp/nlp-gabarito.ipynb b/26-nlp/nlp-gabarito.ipynb new file mode 100644 index 0000000..a1bede2 --- /dev/null +++ b/26-nlp/nlp-gabarito.ipynb @@ -0,0 +1,4517 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Aula 26 - NLP" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Warm up" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![](https://media1.tenor.com/images/2c5e2003710c3f8e3d39ebb424b80f0c/tenor.gif?itemid=6169062)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Expectativas" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![](https://everythingbutthebooks.files.wordpress.com/2014/06/gif-rapunzel.gif)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### O que é NLP?" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- Campo relativamente novo da computação que combina ML e linguística.\n", + "- Principal foco: fazer as máquinas entendam (e até se comuniquem) em linguagem humana. \n", + "- Área de pesquisa/atuação extremamente ampla.\n", + "- Biggest consequence: lowering (or complete removal) of the barrier to entry for BI and big data in general: \n", + "\n", + "> \"Google might tell you today what the weather will be tomorrow. But soon enough, you’ll be able to ask your personal data chatbot about customer sentiment today, and how they’ll feel about your brand next week; all while walking down the street.\"\n", + "> https://www.sisense.com/blog/heres-natural-language-processing-future-bi/" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "##### Exemplos?" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + ".\n", + "\n", + ".\n", + "\n", + ".\n", + "\n", + ".\n", + "\n", + ".\n", + "\n", + ".\n", + "\n", + ".\n", + "\n", + ".\n", + "\n", + ".\n", + "\n", + ".\n", + "\n", + ".\n", + "\n", + ".\n", + "\n", + ".\n", + "\n", + ".\n", + "\n", + ".\n", + "\n", + ".\n", + "\n", + ".\n", + "\n", + ".\n", + "\n", + ".\n", + "\n", + ".\n", + "\n", + ".\n", + "\n", + ".\n", + "\n", + ".\n", + "\n", + ".\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![](images/nlp-fields.png)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " - Autocomplete: celular, e-mail, pesquisa Google.\n", + " - Spell checker\n", + " - Spam detection\n", + " - Information Retrieval: query do usuário -> produto/documento (Google)\n", + " - Chatbot\n", + " - Q&A: pergunta -> resposta (Watson/Jeopardy)\n", + " - Speech recognition\n", + " - Machine Translation (Google Translate)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Os dados: \n", + "Suponha que você é um Cientista de Dados, trabalha em um app de um restaurante e tem reviews de alguns clientes.\n", + "\n", + "*PS: Esse conjunto de dados é composto de reviews de restaurantes e foi modificado a partir do dataset usado no workshop SemEval (International Workshop on Semantic Evaluation) na [edição de 2016](http://alt.qcri.org/semeval2016/task5/).*" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "import re\n", + "import pickle\n", + "import pandas as pd\n", + "import en_core_web_sm\n", + "import spacy\n", + "from spacy.lang.en import English\n", + "from collections import Counter\n", + "from pycontractions import Contractions\n", + "from sklearn.feature_extraction.text import CountVectorizer\n", + "from sklearn.feature_extraction.text import TfidfVectorizer\n", + "from sklearn.linear_model import LogisticRegression\n", + "from sklearn.naive_bayes import MultinomialNB\n", + "from sklearn.ensemble import GradientBoostingClassifier\n", + "from sklearn.pipeline import Pipeline\n", + "from sklearn.metrics import classification_report\n", + "from utils.confusion_matrix import plot_confusion_matrix\n", + "from utils.to_dense import DenseTransformer\n", + "\n", + "pd.options.display.max_columns = 999\n", + "pd.options.display.max_colwidth = 999" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#!python -m spacy download en_core_web_sm\n", + "#!pip install pycontractions" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "pd.read_csv('data/raw/raw_reviews.csv').sample(5)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Qual a tarefa??\n", + "\n", + "Como agregar valor ao negócio a partir desses dados?" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + ".\n", + "\n", + ".\n", + "\n", + ".\n", + "\n", + ".\n", + "\n", + ".\n", + "\n", + ".\n", + "\n", + ".\n", + "\n", + ".\n", + "\n", + ".\n", + "\n", + ".\n", + "\n", + ".\n", + "\n", + ".\n", + "\n", + ".\n", + "\n", + ".\n", + "\n", + ".\n", + "\n", + ".\n", + "\n", + ".\n", + "\n", + ".\n", + "\n", + ".\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Tarefa: *Sentiment analysis*\n", + "Classificar review em positiva ou negativa." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
textpolarity
0It is nearly impossible to get a table, so if you ever have the chance to go here for dinner, DO NOT pass it up.positive
1I won't go back unless someone else is footing the bill.negative
2There are so many better places to visit!negative
3This place is a must visit!positive
4but the service was a bit slow.positive
\n", + "
" + ], + "text/plain": [ + " text \\\n", + "0 It is nearly impossible to get a table, so if you ever have the chance to go here for dinner, DO NOT pass it up. \n", + "1 I won't go back unless someone else is footing the bill. \n", + "2 There are so many better places to visit! \n", + "3 This place is a must visit! \n", + "4 but the service was a bit slow. \n", + "\n", + " polarity \n", + "0 positive \n", + "1 negative \n", + "2 negative \n", + "3 positive \n", + "4 positive " + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "train_df = pd.read_csv('data/processed/train.csv')\n", + "test_df = pd.read_csv('data/processed/test.csv')\n", + "\n", + "train_df.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### As ferramentas\n", + "- Principal biblioteca atualmente para trabalhar com NLP: *Spacy*. \n", + "\n", + "* O datacamp lançou recentemente um [curso](https://campus.datacamp.com/courses/advanced-nlp-with-spacy) bem legal sobre ele que vale a pena dar uma conferida já que hoje, focaremos no \"básico\".\n", + "\n", + "- Outra lib bastante usada (principal biblioteca até alguns meses atrás): [NLTK](https://www.nltk.org/), .\n", + "\n", + "- Outras iniciativas famosas com deep learning: [AllenNLP](https://allennlp.org/) e o [StanfordNLP](https://stanfordnlp.github.io/stanfordnlp/), que são capazes de atingir o estado da arte de muitas aplicações.\n", + "\n", + "\n", + "#### Spacy: \n", + "- Conceito de objeto (comumente chamada de 'nlp') que contém todo o pipeline de processamento, além de outras regras específicas de uma certa língua." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "#from spacy.lang.en import English\n", + "nlp = English()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Como a máquina vai \"entender\" os textos?" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "[![](http://img.youtube.com/vi/d4gGtcobq8M/0.jpg)](http://www.youtube.com/watch?v=d4gGtcobq8M \"\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " **Patterns, Disambiguation (context), Stopwords, Tokens, Bag-of-words, TF, TF-IDF**" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Pipeline NLP**\n", + "" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Patterns\n", + "Em alguns casos, pode ser interessante substituir certas partes em textos fixos, como horários, quantidades, emails.\n", + "\n", + "Exemplo:" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'hi there EMAIL_ADDR!'" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "re.sub(u'[a-z0-9\\_\\.\\-]*@[a-z0-9\\_\\.\\-]*', 'EMAIL_ADDR', u'hi there thais.neubauer@gmail.com!',flags=re.UNICODE)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Tokenization\n", + "- Segmentação de sentenças em \"palavras\".\n", + "- Análise léxica: eliminação de caracteres de pontuação e outros caracteres \"especiais\" - não alfa-numéricos (em alguns casos, excluindo até mesmo os numéricos e acentuação).\n", + "\n", + "Exemplos de potenciais problemas:\n", + "\n", + "" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['We', 'went', 'around', '9:30', 'on', 'a', 'Friday', '...']" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "doc = nlp(\"We went around 9:30 on a Friday...\")\n", + "tokens = [token.text for token in doc]\n", + "tokens" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['It',\n", + " \"'s\",\n", + " 'also',\n", + " 'attached',\n", + " 'to',\n", + " 'Angel',\n", + " \"'s\",\n", + " 'Share',\n", + " ',',\n", + " 'which',\n", + " 'is',\n", + " 'a',\n", + " 'cool',\n", + " ',',\n", + " 'more',\n", + " 'romantic',\n", + " 'bar',\n", + " '...']" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "doc = nlp(\"It's also attached to Angel's Share, which is a cool, more romantic bar...\")\n", + "tokens = [token.text for token in doc]\n", + "tokens" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "* Exercício: Crie o objeto nlp para português e imprima o texto do primeiro token" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Isso\n" + ] + } + ], + "source": [ + "# Import the Portuguese language class\n", + "from spacy.lang.pt import Portuguese\n", + "\n", + "# Create the nlp object\n", + "nlp_pt = Portuguese()\n", + "\n", + "# Process a text\n", + "doc = nlp_pt(\"Isso é uma sentença\")\n", + "\n", + "# Select the first token\n", + "first_token = doc[0]\n", + "\n", + "# Print the first token's text\n", + "print(first_token.text)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Pré-processamento" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Removing stopwords (and maybe other tokens)\n", + "- Para muitas tarefas de NLP, é bom prestar atenção nas chamadas *stopwords*, que são as palavras muito comuns que aparecem no texto e que, por isso, não tem potencial para contribuir para a caracterização do conteúdo presente no texto. \n", + "\n", + "- Nessa lista geramente estão: artigos definidos e indefinidos, preposições, pronomes, numerais, conjunções e advérbios. \n", + "\n", + "-> IMPORTANTE: Além das palavras pertencentes a essas classes gramaticais, podem entrar na lista as palavras muito comuns dentro do contexto referente aos documentos do corpus." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Lei de Zipf e proposta de cortes de Luhn:\n", + "\n", + "" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[('', 309),\n", + " ('the', 177),\n", + " ('a', 103),\n", + " ('to', 97),\n", + " ('and', 92),\n", + " ('i', 90),\n", + " ('is', 79),\n", + " ('it', 75),\n", + " ('for', 56),\n", + " ('you', 55)]" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from collections import Counter\n", + "#splita as frases por palavras (espaco incluido) e soma elas\n", + "Counter(sum(train_df['text'].str.lower().str.split(r'[\\W\\s]+').tolist(), [])).most_common(10)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "countings = dict(Counter(sum(train_df['text'].str.lower().str.split(r'[\\W\\s]+').tolist(), [])).items())" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'it': 75,\n", + " 'is': 79,\n", + " 'nearly': 2,\n", + " 'impossible': 1,\n", + " 'to': 97,\n", + " 'get': 9,\n", + " 'a': 103,\n", + " 'table': 4,\n", + " 'so': 18,\n", + " 'if': 19,\n", + " 'you': 55,\n", + " 'ever': 2,\n", + " 'have': 19,\n", + " 'the': 177,\n", + " 'chance': 1,\n", + " 'go': 32,\n", + " 'here': 9,\n", + " 'for': 56,\n", + " 'dinner': 5,\n", + " 'do': 4,\n", + " 'not': 26,\n", + " 'pass': 1,\n", + " 'up': 7,\n", + " '': 309,\n", + " 'i': 90,\n", + " 'won': 3,\n", + " 't': 35,\n", + " 'back': 36,\n", + " 'unless': 2,\n", + " 'someone': 2,\n", + " 'else': 3,\n", + " 'footing': 1,\n", + " 'bill': 2,\n", + " 'there': 21,\n", + " 'are': 24,\n", + " 'many': 8,\n", + " 'better': 6,\n", + " 'places': 10,\n", + " 'visit': 9,\n", + " 'this': 44,\n", + " 'place': 43,\n", + " 'must': 3,\n", + " 'but': 28,\n", + " 'service': 24,\n", + " 'was': 39,\n", + " 'bit': 6,\n", + " 'slow': 1,\n", + " 'amazing': 5,\n", + " 'fun': 3,\n", + " 'hot': 2,\n", + " 'dog': 2,\n", + " 'lovers': 2,\n", + " 'of': 37,\n", + " 'all': 20,\n", + " 'ages': 1,\n", + " 'please': 3,\n", + " 'yourself': 3,\n", + " 'favor': 1,\n", + " 'and': 92,\n", + " 'check': 5,\n", + " 'out': 12,\n", + " 'leave': 2,\n", + " 'room': 2,\n", + " 'dessert': 5,\n", + " 've': 3,\n", + " 'been': 8,\n", + " 'time': 12,\n", + " 'never': 10,\n", + " 'disappointed': 5,\n", + " 'personally': 1,\n", + " 'like': 12,\n", + " 'margherita': 1,\n", + " 'pizza': 5,\n", + " 'they': 14,\n", + " 'good': 27,\n", + " 'm': 6,\n", + " 'astonished': 1,\n", + " 'that': 29,\n", + " 'restaurant': 18,\n", + " 'categorized': 1,\n", + " 'as': 7,\n", + " 'rather': 3,\n", + " 'than': 7,\n", + " 'has': 5,\n", + " 'correct': 1,\n", + " 'ambience': 5,\n", + " 'an': 5,\n", + " 'excellent': 5,\n", + " 'staff': 10,\n", + " 'make': 4,\n", + " 'feel': 5,\n", + " 'guest': 1,\n", + " 'friend': 2,\n", + " 'at': 17,\n", + " 'same': 2,\n", + " 'decor': 3,\n", + " 'needs': 3,\n", + " 'be': 28,\n", + " 'upgraded': 1,\n", + " 'food': 28,\n", + " 'no': 9,\n", + " 'excuse': 1,\n", + " 'such': 4,\n", + " 'lousy': 1,\n", + " 'sunday': 2,\n", + " 'afternoons': 1,\n", + " 'band': 1,\n", + " 'playing': 1,\n", + " 'lots': 1,\n", + " 'case': 1,\n", + " 'gem': 3,\n", + " 'saving': 1,\n", + " 'my': 14,\n", + " 'next': 3,\n", + " 'can': 18,\n", + " 'wait': 11,\n", + " 'we': 20,\n", + " 'agreed': 1,\n", + " 'mare': 1,\n", + " 'one': 15,\n", + " 'best': 7,\n", + " 'seafood': 1,\n", + " 'restaurants': 4,\n", + " 'in': 53,\n", + " 'new': 3,\n", + " 'york': 3,\n", + " 'highly': 11,\n", + " 'recommend': 12,\n", + " 'caviar': 2,\n", + " 'russe': 1,\n", + " 'anyone': 2,\n", + " 'who': 7,\n", + " 'wants': 1,\n", + " 'delicious': 4,\n", + " 'top': 3,\n", + " 'grade': 1,\n", + " 'fantastic': 4,\n", + " 'sure': 5,\n", + " 'would': 15,\n", + " 'd': 6,\n", + " 'heartbeat': 1,\n", + " 'price': 6,\n", + " 'high': 1,\n", + " 'come': 5,\n", + " 'again': 12,\n", + " 'on': 22,\n", + " 'scale': 1,\n", + " 's': 31,\n", + " 'world': 3,\n", + " 'beater': 1,\n", + " 'thanked': 1,\n", + " 'recommended': 7,\n", + " 'me': 5,\n", + " 'will': 19,\n", + " 'certainly': 2,\n", + " 'others': 1,\n", + " 'keep': 4,\n", + " 'work': 2,\n", + " 'guys': 1,\n", + " 'loved': 2,\n", + " 'huge': 1,\n", + " 'crust': 1,\n", + " 'thin': 1,\n", + " 'mind': 1,\n", + " 'when': 6,\n", + " 're': 13,\n", + " 'ordering': 1,\n", + " 'however': 2,\n", + " 'stop': 2,\n", + " 'going': 12,\n", + " 'priced': 2,\n", + " 'upper': 2,\n", + " 'intermediate': 1,\n", + " 'range': 1,\n", + " 'though': 2,\n", + " 'expensive': 5,\n", + " 'prefer': 1,\n", + " 'bella': 2,\n", + " 'via': 1,\n", + " 'just': 15,\n", + " 'blocks': 1,\n", + " 'away': 4,\n", + " 'by': 6,\n", + " 'far': 4,\n", + " 'very': 16,\n", + " 'what': 7,\n", + " 'more': 18,\n", + " 'could': 3,\n", + " 'want': 5,\n", + " 'always': 6,\n", + " 'crowded': 1,\n", + " 'popular': 2,\n", + " 'overall': 2,\n", + " 'decent': 2,\n", + " 'with': 16,\n", + " 'friendly': 4,\n", + " 'people': 5,\n", + " 'am': 5,\n", + " 'coming': 6,\n", + " 'much': 3,\n", + " 'several': 1,\n", + " 'times': 4,\n", + " 'dissapoints': 1,\n", + " 'relax': 1,\n", + " 'your': 19,\n", + " 'somewhere': 2,\n", + " 'jersey': 1,\n", + " 'deli': 1,\n", + " 'way': 4,\n", + " 'im': 1,\n", + " 'honest': 1,\n", + " 'mistake': 1,\n", + " 'skip': 2,\n", + " 'big': 4,\n", + " 'disappointment': 2,\n", + " 'll': 4,\n", + " 'ther': 1,\n", + " 'every': 3,\n", + " 'anniversary': 1,\n", + " 'birthday': 2,\n", + " 'valentines': 1,\n", + " 'day': 2,\n", + " 'wont': 1,\n", + " 'over': 2,\n", + " 'dozen': 1,\n", + " 'complaints': 1,\n", + " 'date': 3,\n", + " 'uws': 1,\n", + " 'don': 13,\n", + " 'need': 4,\n", + " 'overpriced': 2,\n", + " 'absurdly': 1,\n", + " 'arrogant': 1,\n", + " 'recognize': 1,\n", + " 'glorified': 1,\n", + " 'diner': 1,\n", + " 'clumsy': 1,\n", + " 'management': 3,\n", + " 'doesn': 2,\n", + " 'care': 1,\n", + " 'also': 7,\n", + " 'little': 7,\n", + " 'average': 2,\n", + " 'bagel': 1,\n", + " 'oh': 4,\n", + " 'hookah': 1,\n", + " 'taiwanese': 1,\n", + " 'ny': 3,\n", + " 'love': 4,\n", + " 'yuka': 2,\n", + " 'save': 1,\n", + " 'trouble': 2,\n", + " 'night': 4,\n", + " 'splurge': 1,\n", + " 'think': 4,\n", + " 'manhattan': 8,\n", + " 'should': 5,\n", + " 'cost': 2,\n", + " '400': 1,\n", + " '00': 2,\n", + " 'where': 2,\n", + " 'swept': 1,\n", + " 'off': 4,\n", + " 'feet': 1,\n", + " 'meat': 1,\n", + " 'fresh': 2,\n", + " 'sauces': 1,\n", + " 'great': 25,\n", + " 'kimchi': 1,\n", + " 'salad': 1,\n", + " 'free': 1,\n", + " 'meal': 3,\n", + " 'too': 10,\n", + " 'definetly': 1,\n", + " 'say': 4,\n", + " 'stay': 2,\n", + " 'pleased': 1,\n", + " 'found': 1,\n", + " 'nights': 2,\n", + " 'weekends': 1,\n", + " 'private': 1,\n", + " 'party': 1,\n", + " 'celebrate': 1,\n", + " 'try': 10,\n", + " 'pad': 1,\n", + " 'thai': 3,\n", + " 'or': 14,\n", + " 'sample': 1,\n", + " 'anything': 1,\n", + " 'appetizer': 2,\n", + " 'menu': 4,\n", + " 'untill': 1,\n", + " 'happens': 1,\n", + " 'advice': 1,\n", + " 'believe': 2,\n", + " 'baby': 1,\n", + " 'worth': 10,\n", + " 'trip': 5,\n", + " 'from': 6,\n", + " 'pasta': 2,\n", + " 'penne': 2,\n", + " 'pretty': 4,\n", + " 'extra': 2,\n", + " 'buttery': 1,\n", + " 'creamy': 1,\n", + " 'which': 6,\n", + " 'means': 1,\n", + " 'task': 1,\n", + " 'diggest': 1,\n", + " 'tasty': 2,\n", + " 'first': 1,\n", + " 'full': 2,\n", + " 'slice': 1,\n", + " '7': 1,\n", + " 'count': 1,\n", + " 'got': 5,\n", + " 'moody': 1,\n", + " 'afterwards': 1,\n", + " 'cause': 1,\n", + " 'stuffed': 1,\n", + " 'lol': 2,\n", + " 'spectacular': 1,\n", + " 'location': 4,\n", + " 'us': 3,\n", + " 'year': 2,\n", + " 'after': 3,\n", + " 'awesome': 2,\n", + " 'sally': 1,\n", + " 'even': 2,\n", + " 'bother': 2,\n", + " 'describe': 1,\n", + " 'speaks': 1,\n", + " 'itself': 2,\n", + " 'had': 8,\n", + " 'their': 4,\n", + " 'eggs': 1,\n", + " 'benedict': 1,\n", + " 'brunch': 1,\n", + " 'were': 6,\n", + " 'worst': 2,\n", + " 'entire': 1,\n", + " 'life': 1,\n", + " 'tried': 1,\n", + " 'removing': 1,\n", + " 'hollondaise': 1,\n", + " 'sauce': 1,\n", + " 'completely': 2,\n", + " 'how': 4,\n", + " 'failed': 1,\n", + " 'various': 1,\n", + " 'greek': 1,\n", + " 'cypriot': 1,\n", + " 'dishes': 3,\n", + " 'gyro': 1,\n", + " 'reason': 2,\n", + " 'eat': 9,\n", + " 'wasted': 1,\n", + " 'wine': 3,\n", + " 'choices': 1,\n", + " 'pastas': 1,\n", + " 'incredible': 3,\n", + " 'risottos': 1,\n", + " 'particularly': 1,\n", + " 'sepia': 1,\n", + " 'braised': 1,\n", + " 'rabbit': 1,\n", + " 'definitely': 9,\n", + " 'spot': 2,\n", + " 'nice': 7,\n", + " 'occasion': 2,\n", + " 'packaged': 1,\n", + " 'everything': 1,\n", + " 'nicely': 1,\n", + " 'didn': 2,\n", + " 'spill': 1,\n", + " 'give': 2,\n", + " 'enjoy': 5,\n", + " 'cheese': 1,\n", + " 'fries': 1,\n", + " 'sushimi': 1,\n", + " 'cucumber': 1,\n", + " 'roll': 3,\n", + " 'seemed': 1,\n", + " 'really': 6,\n", + " 'stressed': 1,\n", + " 'unisex': 1,\n", + " 'bathroom': 1,\n", + " 'cleaned': 1,\n", + " 'often': 1,\n", + " 'shame': 1,\n", + " 'horrible': 1,\n", + " 'rude': 1,\n", + " 'non': 1,\n", + " 'existent': 1,\n", + " 'customer': 2,\n", + " 'another': 2,\n", + " 'ruth': 1,\n", + " 'mother': 2,\n", + " 'bride': 1,\n", + " 'fired': 1,\n", + " 'our': 3,\n", + " 'favorite': 4,\n", + " 'beautiful': 4,\n", + " 'joke': 1,\n", + " 'dont': 2,\n", + " 'area': 2,\n", + " 'sadly': 1,\n", + " 'lacking': 1,\n", + " 'spots': 1,\n", + " 'whole': 1,\n", + " 'set': 2,\n", + " 'truly': 1,\n", + " 'unprofessional': 1,\n", + " 'wish': 5,\n", + " 'cafe': 2,\n", + " 'noir': 1,\n", + " 'some': 4,\n", + " 'because': 2,\n", + " 'despite': 1,\n", + " 'current': 1,\n", + " 'return': 4,\n", + " 'oasis': 1,\n", + " 'mid': 2,\n", + " 'town': 1,\n", + " 'remember': 4,\n", + " 'dress': 1,\n", + " 'urban': 1,\n", + " 'chic': 1,\n", + " 'look': 3,\n", + " 'lobster': 1,\n", + " 'sandwich': 1,\n", + " '24': 1,\n", + " 'although': 3,\n", + " 'enough': 3,\n", + " 'warrant': 1,\n", + " 'indian': 3,\n", + " 'chinese': 2,\n", + " 'city': 3,\n", + " 'owners': 1,\n", + " 'open': 3,\n", + " 'sesame': 2,\n", + " 'bravo': 1,\n", + " 'dine': 2,\n", + " 'plus': 1,\n", + " 'roxy': 1,\n", + " 'avoid': 2,\n", + " 'casa': 1,\n", + " 'la': 1,\n", + " 'femme': 1,\n", + " 'any': 7,\n", + " 'special': 2,\n", + " 'impress': 1,\n", + " 'cannot': 5,\n", + " 'imagine': 1,\n", + " 'rushing': 1,\n", + " 'cold': 3,\n", + " 'taste': 4,\n", + " 'them': 2,\n", + " 'growing': 1,\n", + " 'taiwan': 1,\n", + " 'turkey': 1,\n", + " 'burgers': 1,\n", + " 'scary': 1,\n", + " 'authentic': 2,\n", + " 'shanghai': 2,\n", + " 'style': 2,\n", + " 'zero': 1,\n", + " 'ambiance': 1,\n", + " 'boot': 1,\n", + " 'tipsy': 1,\n", + " 'sake': 2,\n", + " 'isn': 2,\n", + " 'saturday': 1,\n", + " 'girlfriends': 1,\n", + " 'about': 6,\n", + " 'friends': 4,\n", + " 'thank': 2,\n", + " 'introducing': 1,\n", + " 'hang': 1,\n", + " 'rest': 1,\n", + " 'hipsters': 1,\n", + " 'apparently': 1,\n", + " 'sense': 1,\n", + " 'drinks': 1,\n", + " 'suberb': 1,\n", + " 'third': 1,\n", + " 'country': 1,\n", + " 'walk': 4,\n", + " 'door': 1,\n", + " 'die': 1,\n", + " 'appetizers': 1,\n", + " 'owner': 1,\n", + " 'belligerent': 1,\n", + " 'guests': 1,\n", + " 'complaint': 1,\n", + " 'gets': 1,\n", + " 'response': 1,\n", + " 'simply': 2,\n", + " 'spendid': 1,\n", + " 'quite': 2,\n", + " 'delight': 2,\n", + " 'east': 2,\n", + " 'elevated': 1,\n", + " 'level': 1,\n", + " 'real': 2,\n", + " 'entree': 1,\n", + " 'numerous': 1,\n", + " 'variations': 1,\n", + " 'available': 1,\n", + " 'its': 2,\n", + " 'live': 2,\n", + " 'neighborhood': 5,\n", + " 'wherever': 1,\n", + " 'well': 3,\n", + " 'guess': 1,\n", + " 'maybe': 2,\n", + " 'might': 1,\n", + " 'beneficial': 1,\n", + " 'pay': 1,\n", + " 'tutta': 1,\n", + " 'columbia': 1,\n", + " 'tips': 1,\n", + " 'these': 3,\n", + " 'kind': 1,\n", + " 'intimate': 1,\n", + " 'superb': 1,\n", + " 'homey': 1,\n", + " 'notch': 1,\n", + " 'around': 5,\n", + " 'oyster': 1,\n", + " 'hats': 1,\n", + " 'chef': 2,\n", + " 'delightful': 1,\n", + " 'impeccable': 1,\n", + " 'thanks': 1,\n", + " 'dates': 1,\n", + " 'wow': 1,\n", + " 'partial': 1,\n", + " 'gnocchi': 1,\n", + " 'usually': 2,\n", + " 'establishment': 1,\n", + " 'once': 4,\n", + " 'twice': 1,\n", + " 'zenkichi': 1,\n", + " 'anytime': 2,\n", + " 'quiet': 2,\n", + " 'unhurried': 1,\n", + " 'memorable': 1,\n", + " 'right': 1,\n", + " 'size': 1,\n", + " '20': 3,\n", + " 'sushi': 5,\n", + " 'beaten': 1,\n", + " 'looking': 2,\n", + " 'quality': 2,\n", + " 'bs': 1,\n", + " 'seen': 2,\n", + " 'yelp': 1,\n", + " 'ratings': 2,\n", + " 'allegedly': 1,\n", + " 'recently': 1,\n", + " 'adjusting': 1,\n", + " 'prices': 2,\n", + " 'reasonable': 2,\n", + " 'downstairs': 1,\n", + " 'lounge': 1,\n", + " 'attraction': 1,\n", + " 'busy': 2,\n", + " 'fridays': 1,\n", + " 'seated': 1,\n", + " 'efficient': 1,\n", + " 'quickly': 1,\n", + " 'rao': 1,\n", + " 'nothing': 2,\n", + " 'venture': 1,\n", + " 'island': 1,\n", + " 'seem': 1,\n", + " 'find': 2,\n", + " 'italian': 1,\n", + " 'drive': 1,\n", + " 'corona': 1,\n", + " 'interested': 1,\n", + " 'tasting': 1,\n", + " 'without': 2,\n", + " 'fish': 1,\n", + " 'smell': 1,\n", + " 'large': 2,\n", + " 'portions': 1,\n", + " 'creative': 2,\n", + " 'scallion': 1,\n", + " 'pancakes': 1,\n", + " 'fried': 1,\n", + " 'dumplings': 1,\n", + " 'ordinary': 1,\n", + " 'guaranteeed': 1,\n", + " '10': 1,\n", + " 'bound': 1,\n", + " 'charming': 2,\n", + " 'reputation': 1,\n", + " 'packed': 1,\n", + " 'lack': 1,\n", + " 'intelligent': 1,\n", + " 'eats': 2,\n", + " 'anybody': 1,\n", + " 'casual': 2,\n", + " 'romantic': 2,\n", + " 'confortable': 1,\n", + " 'perfect': 2,\n", + " 'frendly': 1,\n", + " 'daring': 1,\n", + " 'balsamic': 1,\n", + " 'vinegar': 1,\n", + " 'icecream': 1,\n", + " 'wonderful': 6,\n", + " 'expected': 1,\n", + " 'bar': 2,\n", + " 'scene': 1,\n", + " 'seems': 1,\n", + " 'happening': 1,\n", + " 'take': 3,\n", + " 'towners': 1,\n", + " 'watching': 1,\n", + " 'sunset': 1,\n", + " 'holiday': 1,\n", + " 'wrong': 2,\n", + " 'wong': 1,\n", + " 'fill': 1,\n", + " 'stomach': 1,\n", + " 'definately': 1,\n", + " 'ok': 2,\n", + " 'expect': 1,\n", + " '500': 1,\n", + " 'conversation': 2,\n", + " 'lunch': 2,\n", + " 'probably': 3,\n", + " 'eating': 3,\n", + " 'atmosphere': 2,\n", + " 'saves': 1,\n", + " 'desk': 1,\n", + " 'disappointing': 1,\n", + " 'experience': 3,\n", + " 'lava': 1,\n", + " 'cake': 1,\n", + " 'pleasantly': 1,\n", + " 'suprised': 1,\n", + " 'most': 2,\n", + " 'likely': 2,\n", + " 'prepared': 1,\n", + " 'spend': 3,\n", + " 'ask': 1,\n", + " 'something': 2,\n", + " 'offer': 2,\n", + " 'complimentary': 1,\n", + " 'then': 4,\n", + " 'poor': 1,\n", + " 'ahhh': 1,\n", + " 'especially': 1,\n", + " 'since': 2,\n", + " 'call': 1,\n", + " 'ready': 1,\n", + " 'japanese': 2,\n", + " 'spanish': 1,\n", + " 'tapas': 1,\n", + " 'creation': 1,\n", + " 'williamsburg': 1,\n", + " 'misstake': 1,\n", + " 'finally': 1,\n", + " 'reliable': 1,\n", + " 'depends': 1,\n", + " 'luck': 2,\n", + " 'absolutely': 1,\n", + " 'fabulous': 2,\n", + " 'cheapest': 1,\n", + " 'last': 1,\n", + " 'walked': 1,\n", + " 'looked': 1,\n", + " 'empty': 1,\n", + " 'hmmm': 1,\n", + " 'cool': 2,\n", + " 'fire': 1,\n", + " 'ads': 1,\n", + " 'heat': 1,\n", + " 'throughout': 1,\n", + " 'judge': 1,\n", + " 'prima': 1,\n", + " 'facie': 1,\n", + " 'home': 3,\n", + " 'literate': 1,\n", + " 'heart': 1,\n", + " 'dancing': 1,\n", + " 'white': 1,\n", + " 'river': 2,\n", + " 'millenium': 1,\n", + " 'rolls': 2,\n", + " 'musts': 1,\n", + " 'winner': 1,\n", + " 'arrived': 1,\n", + " 'minutes': 1,\n", + " 'called': 1,\n", + " 'soggy': 1,\n", + " 'now': 1,\n", + " 'inconsistent': 1,\n", + " 'money': 1,\n", + " 'slightly': 1,\n", + " 'pricey': 2,\n", + " 'side': 5,\n", + " 'fav': 1,\n", + " 'sassy': 1,\n", + " 'lassi': 1,\n", + " 'noisy': 2,\n", + " 'overlooked': 1,\n", + " 'sit': 1,\n", + " 'down': 4,\n", + " 'forgivable': 1,\n", + " 'asked': 1,\n", + " 'still': 2,\n", + " 'quibbles': 1,\n", + " 'pour': 1,\n", + " 'own': 2,\n", + " 'measures': 1,\n", + " 'liquers': 1,\n", + " 'courtesey': 1,\n", + " 'house': 1,\n", + " 'calling': 1,\n", + " 'hampton': 1,\n", + " 'chutney': 1,\n", + " 'co': 1,\n", + " 'does': 1,\n", + " 'warn': 1,\n", + " 'folks': 1,\n", + " 'substance': 1,\n", + " 'unattractive': 1,\n", + " 'unhelpful': 1,\n", + " 'clerks': 1,\n", + " 'dearth': 1,\n", + " 'former': 1,\n", + " 'father': 1,\n", + " 'flank': 1,\n", + " 'steak': 1,\n", + " 'swordfish': 1,\n", + " 'ignore': 1,\n", + " 'trendy': 2,\n", + " 'wannabes': 1,\n", + " 'few': 2,\n", + " 'socal': 1,\n", + " 'actually': 2,\n", + " 'car': 1,\n", + " 'korean': 1,\n", + " '32nd': 1,\n", + " 'street': 2,\n", + " 'course': 1,\n", + " 'guarantee': 1,\n", + " 'valet': 1,\n", + " 'parking': 1,\n", + " 'west': 5,\n", + " 'village': 3,\n", + " 'only': 5,\n", + " 'thing': 2,\n", + " 'strikes': 1,\n", + " 'pleasant': 2,\n", + " 'located': 1,\n", + " 'strip': 1,\n", + " 'mall': 1,\n", + " 'near': 1,\n", + " 'beverly': 1,\n", + " 'center': 1,\n", + " 'greatest': 1,\n", + " 'keeps': 1,\n", + " 'liked': 1,\n", + " 'point': 1,\n", + " 'snacks': 1,\n", + " 'chat': 1,\n", + " 'appreciate': 1,\n", + " 'delivery': 1,\n", + " 'wasn': 1,\n", + " 'hey': 1,\n", + " '2': 3,\n", + " '5': 2,\n", + " 'block': 1,\n", + " 'ain': 1,\n", + " 'bad': 2,\n", + " 'delivered': 1,\n", + " 'mint': 1,\n", + " 'retrain': 1,\n", + " 'went': 1,\n", + " '9': 1,\n", + " '30': 1,\n", + " 'friday': 1,\n", + " 'died': 1,\n", + " 'leisure': 1,\n", + " 'breakfast': 2,\n", + " 'amidst': 1,\n", + " 'yachts': 1,\n", + " 'stroll': 1,\n", + " 'through': 1,\n", + " 'nearby': 1,\n", + " 'farmer': 1,\n", + " 'market': 2,\n", + " 'son': 1,\n", + " 'cubano': 1,\n", + " 'edgewater': 1,\n", + " 'nj': 1,\n", + " 'instead': 1,\n", + " 'egg': 1,\n", + " 'custards': 1,\n", + " 'pork': 1,\n", + " 'buns': 1,\n", + " 'either': 1,\n", + " 'bakery': 1,\n", + " 'mott': 1,\n", + " 'south': 1,\n", + " 'canal': 1,\n", + " 'meet': 1,\n", + " 'hope': 1,\n", + " 'pays': 1,\n", + " 'attention': 1,\n", + " 'details': 1,\n", + " 'future': 1,\n", + " 'traditional': 1,\n", + " 'french': 1,\n", + " 'decour': 1,\n", + " 'hall': 1,\n", + " 'raise': 1,\n", + " 'voices': 1,\n", + " 'able': 1,\n", + " 'maintain': 1,\n", + " 'negatives': 1,\n", + " 'speak': 1,\n", + " 'inexpensive': 1,\n", + " 'frequently': 1,\n", + " 'small': 2,\n", + " '6': 1,\n", + " 'perfection': 1,\n", + " 'tiny': 1,\n", + " '8': 1,\n", + " 'plain': 1,\n", + " 'cramped': 1,\n", + " 'closes': 1,\n", + " 'early': 1,\n", + " 'plan': 1,\n", + " 'asking': 1,\n", + " 'hair': 1,\n", + " 'other': 2,\n", + " 'settle': 1,\n", + " 'getting': 1,\n", + " 'obvious': 1,\n", + " 'idea': 1,\n", + " 'cuisine': 1,\n", + " 'teenage': 1,\n", + " 'kids': 1,\n", + " 'yes': 1,\n", + " 'summer': 1,\n", + " 'outside': 1,\n", + " 'terrace': 1,\n", + " 'feature': 1,\n", + " 'suan': 1,\n", + " 'eaten': 1,\n", + " 'nyc': 3,\n", + " 'hands': 1,\n", + " 'happy': 1,\n", + " 'choice': 2,\n", + " 'deal': 1,\n", + " 'hate': 1,\n", + " 'tourists': 1,\n", + " 'park': 1,\n", + " 'chalet': 1,\n", + " 'san': 2,\n", + " 'francisco': 1,\n", + " 'joint': 2,\n", + " 'lets': 1,\n", + " 'company': 1,\n", + " 'family': 1,\n", + " 'general': 1,\n", + " 'dining': 1,\n", + " 'already': 1,\n", + " 'excuses': 1,\n", + " 'ahead': 1,\n", + " 'soon': 3,\n", + " 'wks': 1,\n", + " 'jukebox': 1,\n", + " 'long': 2,\n", + " 'risk': 1,\n", + " 'bukhara': 1,\n", + " 'weekend': 1,\n", + " 'southglenn': 1,\n", + " 'largest': 1,\n", + " 'tomorrow': 1,\n", + " 'view': 1,\n", + " 'attached': 1,\n", + " 'angel': 1,\n", + " 'share': 1,\n", + " 'smoked': 1,\n", + " 'yellowtail': 1,\n", + " 'cheap': 1,\n", + " 'chicken': 1,\n", + " 'cant': 1,\n", + " 'name': 1,\n", + " 'sooo': 1,\n", + " 'model': 1,\n", + " 'w': 1,\n", + " 'late': 4,\n", + " 'crowd': 1,\n", + " 'understand': 1,\n", + " 'hype': 1,\n", + " 'single': 1,\n", + " 'problem': 1,\n", + " 'less': 1,\n", + " 'courteous': 1,\n", + " 'attentive': 2,\n", + " 'st': 1,\n", + " 'bart': 1,\n", + " 'art': 1,\n", + " 'walls': 1,\n", + " 'colorful': 1,\n", + " 'evaluated': 1,\n", + " 'those': 1,\n", + " 'terms': 1,\n", + " 'pastis': 1,\n", + " 'write': 1,\n", + " 'reviews': 1,\n", + " 'moved': 1,\n", + " 'felt': 2,\n", + " 'duty': 1,\n", + " 'spread': 1,\n", + " 'word': 1,\n", + " 'aware': 1,\n", + " 'cash': 1,\n", + " 'amex': 1,\n", + " 'makes': 1,\n", + " 'cheaply': 1,\n", + " 'generally': 1,\n", + " 'manhattanite': 1,\n", + " 'rice': 1,\n", + " 'avenue': 2,\n", + " 'soho': 1,\n", + " 'minus': 1,\n", + " 'pretentious': 1,\n", + " 'clientele': 1,\n", + " 'roosevelt': 1,\n", + " 'plans': 1,\n", + " 'hungry': 1,\n", + " 'run': 1,\n", + " 'list': 2,\n", + " 'sad': 1,\n", + " 'frequent': 1,\n", + " 'hotel': 1,\n", + " 'miss': 1,\n", + " 'esp': 1,\n", + " 'downtown': 1,\n", + " 'jose': 1,\n", + " 'thius': 1,\n", + " 'loves': 1,\n", + " 'shabu': 2,\n", + " 'refunded': 1,\n", + " 'cal': 1,\n", + " 'effort': 1,\n", + " 'person': 1,\n", + " 'terrible': 2,\n", + " 'deserves': 1,\n", + " 'shut': 1,\n", + " 'arigato': 1,\n", + " 'gozimas': 1,\n", + " 'boston': 1,\n", + " 'emma': 1,\n", + " 'kendall': 1,\n", + " 'square': 1,\n", + " 'cambridge': 1,\n", + " 'funky': 1,\n", + " 'toppings': 3,\n", + " 'fool': 1,\n", + " 'heartily': 1,\n", + " 'shouldn': 1,\n", + " 'survives': 1,\n", + " 'competitive': 1,\n", + " 'economy': 1,\n", + " 'matter': 1,\n", + " 'beyond': 1,\n", + " 'tons': 1,\n", + " 'potential': 1,\n", + " 'weren': 1,\n", + " 'impersonal': 1,\n", + " 'corporate': 1,\n", + " 'opened': 1,\n", + " 'reminds': 1,\n", + " 'recent': 1,\n", + " 'italy': 1,\n", + " '3': 1,\n", + " 'each': 1,\n", + " 'forward': 1,\n", + " 'donot': 1,\n", + " 'cute': 1,\n", + " 'positive': 1,\n", + " 'mioposto': 1,\n", + " 'order': 1,\n", + " 'office': 1,\n", + " 'consider': 1,\n", + " 'companion': 1,\n", + " 'across': 1,\n", + " 'munchies': 1,\n", + " 'boost': 1,\n", + " ...}" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "countings" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[('impossible', 1),\n", + " ('chance', 1),\n", + " ('pass', 1),\n", + " ('footing', 1),\n", + " ('slow', 1),\n", + " ('ages', 1),\n", + " ('favor', 1),\n", + " ('personally', 1),\n", + " ('margherita', 1),\n", + " ('astonished', 1),\n", + " ('categorized', 1),\n", + " ('correct', 1),\n", + " ('guest', 1),\n", + " ('upgraded', 1),\n", + " ('excuse', 1),\n", + " ('lousy', 1),\n", + " ('afternoons', 1),\n", + " ('band', 1),\n", + " ('playing', 1),\n", + " ('lots', 1),\n", + " ('case', 1),\n", + " ('saving', 1),\n", + " ('agreed', 1),\n", + " ('mare', 1),\n", + " ('seafood', 1),\n", + " ('russe', 1),\n", + " ('wants', 1),\n", + " ('grade', 1),\n", + " ('heartbeat', 1),\n", + " ('high', 1),\n", + " ('scale', 1),\n", + " ('beater', 1),\n", + " ('thanked', 1),\n", + " ('others', 1),\n", + " ('guys', 1),\n", + " ('huge', 1),\n", + " ('crust', 1),\n", + " ('thin', 1),\n", + " ('mind', 1),\n", + " ('ordering', 1),\n", + " ('intermediate', 1),\n", + " ('range', 1),\n", + " ('prefer', 1),\n", + " ('via', 1),\n", + " ('blocks', 1),\n", + " ('crowded', 1),\n", + " ('several', 1),\n", + " ('dissapoints', 1),\n", + " ('relax', 1),\n", + " ('jersey', 1),\n", + " ('deli', 1),\n", + " ('im', 1),\n", + " ('honest', 1),\n", + " ('mistake', 1),\n", + " ('ther', 1),\n", + " ('anniversary', 1),\n", + " ('valentines', 1),\n", + " ('wont', 1),\n", + " ('dozen', 1),\n", + " ('complaints', 1),\n", + " ('uws', 1),\n", + " ('absurdly', 1),\n", + " ('arrogant', 1),\n", + " ('recognize', 1),\n", + " ('glorified', 1),\n", + " ('diner', 1),\n", + " ('clumsy', 1),\n", + " ('care', 1),\n", + " ('bagel', 1),\n", + " ('hookah', 1),\n", + " ('taiwanese', 1),\n", + " ('save', 1),\n", + " ('splurge', 1),\n", + " ('400', 1),\n", + " ('swept', 1),\n", + " ('feet', 1),\n", + " ('meat', 1),\n", + " ('sauces', 1),\n", + " ('kimchi', 1),\n", + " ('salad', 1),\n", + " ('free', 1),\n", + " ('definetly', 1),\n", + " ('pleased', 1),\n", + " ('found', 1),\n", + " ('weekends', 1),\n", + " ('private', 1),\n", + " ('party', 1),\n", + " ('celebrate', 1),\n", + " ('pad', 1),\n", + " ('sample', 1),\n", + " ('anything', 1),\n", + " ('untill', 1),\n", + " ('happens', 1),\n", + " ('advice', 1),\n", + " ('baby', 1),\n", + " ('buttery', 1),\n", + " ('creamy', 1),\n", + " ('means', 1),\n", + " ('task', 1),\n", + " ('diggest', 1),\n", + " ('first', 1),\n", + " ('slice', 1),\n", + " ('7', 1),\n", + " ('count', 1),\n", + " ('moody', 1),\n", + " ('afterwards', 1),\n", + " ('cause', 1),\n", + " ('stuffed', 1),\n", + " ('spectacular', 1),\n", + " ('sally', 1),\n", + " ('describe', 1),\n", + " ('speaks', 1),\n", + " ('eggs', 1),\n", + " ('benedict', 1),\n", + " ('brunch', 1),\n", + " ('entire', 1),\n", + " ('life', 1),\n", + " ('tried', 1),\n", + " ('removing', 1),\n", + " ('hollondaise', 1),\n", + " ('sauce', 1),\n", + " ('failed', 1),\n", + " ('various', 1),\n", + " ('greek', 1),\n", + " ('cypriot', 1),\n", + " ('gyro', 1),\n", + " ('wasted', 1),\n", + " ('choices', 1),\n", + " ('pastas', 1),\n", + " ('risottos', 1),\n", + " ('particularly', 1),\n", + " ('sepia', 1),\n", + " ('braised', 1),\n", + " ('rabbit', 1),\n", + " ('packaged', 1),\n", + " ('everything', 1),\n", + " ('nicely', 1),\n", + " ('spill', 1),\n", + " ('cheese', 1),\n", + " ('fries', 1),\n", + " ('sushimi', 1),\n", + " ('cucumber', 1),\n", + " ('seemed', 1),\n", + " ('stressed', 1),\n", + " ('unisex', 1),\n", + " ('bathroom', 1),\n", + " ('cleaned', 1),\n", + " ('often', 1),\n", + " ('shame', 1),\n", + " ('horrible', 1),\n", + " ('rude', 1),\n", + " ('non', 1),\n", + " ('existent', 1),\n", + " ('ruth', 1),\n", + " ('bride', 1),\n", + " ('fired', 1),\n", + " ('joke', 1),\n", + " ('sadly', 1),\n", + " ('lacking', 1),\n", + " ('spots', 1),\n", + " ('whole', 1),\n", + " ('truly', 1),\n", + " ('unprofessional', 1),\n", + " ('noir', 1),\n", + " ('despite', 1),\n", + " ('current', 1),\n", + " ('oasis', 1),\n", + " ('town', 1),\n", + " ('dress', 1),\n", + " ('urban', 1),\n", + " ('chic', 1),\n", + " ('lobster', 1),\n", + " ('sandwich', 1),\n", + " ('24', 1),\n", + " ('warrant', 1),\n", + " ('owners', 1),\n", + " ('bravo', 1),\n", + " ('plus', 1),\n", + " ('roxy', 1),\n", + " ('casa', 1),\n", + " ('la', 1),\n", + " ('femme', 1),\n", + " ('impress', 1),\n", + " ('imagine', 1),\n", + " ('rushing', 1),\n", + " ('growing', 1),\n", + " ('taiwan', 1),\n", + " ('turkey', 1),\n", + " ('burgers', 1),\n", + " ('scary', 1),\n", + " ('zero', 1),\n", + " ('ambiance', 1),\n", + " ('boot', 1),\n", + " ('tipsy', 1),\n", + " ('saturday', 1),\n", + " ('girlfriends', 1),\n", + " ('introducing', 1),\n", + " ('hang', 1),\n", + " ('rest', 1),\n", + " ('hipsters', 1),\n", + " ('apparently', 1),\n", + " ('sense', 1),\n", + " ('drinks', 1),\n", + " ('suberb', 1),\n", + " ('third', 1),\n", + " ('country', 1),\n", + " ('door', 1),\n", + " ('die', 1),\n", + " ('appetizers', 1),\n", + " ('owner', 1),\n", + " ('belligerent', 1),\n", + " ('guests', 1),\n", + " ('complaint', 1),\n", + " ('gets', 1),\n", + " ('response', 1),\n", + " ('spendid', 1),\n", + " ('elevated', 1),\n", + " ('level', 1),\n", + " ('entree', 1),\n", + " ('numerous', 1),\n", + " ('variations', 1),\n", + " ('available', 1),\n", + " ('wherever', 1),\n", + " ('guess', 1),\n", + " ('might', 1),\n", + " ('beneficial', 1),\n", + " ('pay', 1),\n", + " ('tutta', 1),\n", + " ('columbia', 1),\n", + " ('tips', 1),\n", + " ('kind', 1),\n", + " ('intimate', 1),\n", + " ('superb', 1),\n", + " ('homey', 1),\n", + " ('notch', 1),\n", + " ('oyster', 1),\n", + " ('hats', 1),\n", + " ('delightful', 1),\n", + " ('impeccable', 1),\n", + " ('thanks', 1),\n", + " ('dates', 1),\n", + " ('wow', 1),\n", + " ('partial', 1),\n", + " ('gnocchi', 1),\n", + " ('establishment', 1),\n", + " ('twice', 1),\n", + " ('zenkichi', 1),\n", + " ('unhurried', 1),\n", + " ('memorable', 1),\n", + " ('right', 1),\n", + " ('size', 1),\n", + " ('beaten', 1),\n", + " ('bs', 1),\n", + " ('yelp', 1),\n", + " ('allegedly', 1),\n", + " ('recently', 1),\n", + " ('adjusting', 1),\n", + " ('downstairs', 1),\n", + " ('lounge', 1),\n", + " ('attraction', 1),\n", + " ('fridays', 1),\n", + " ('seated', 1),\n", + " ('efficient', 1),\n", + " ('quickly', 1),\n", + " ('rao', 1),\n", + " ('venture', 1),\n", + " ('island', 1),\n", + " ('seem', 1),\n", + " ('italian', 1),\n", + " ('drive', 1),\n", + " ('corona', 1),\n", + " ('interested', 1),\n", + " ('tasting', 1),\n", + " ('fish', 1),\n", + " ('smell', 1),\n", + " ('portions', 1),\n", + " ('scallion', 1),\n", + " ('pancakes', 1),\n", + " ('fried', 1),\n", + " ('dumplings', 1),\n", + " ('ordinary', 1),\n", + " ('guaranteeed', 1),\n", + " ('10', 1),\n", + " ('bound', 1),\n", + " ('reputation', 1),\n", + " ('packed', 1),\n", + " ('lack', 1),\n", + " ('intelligent', 1),\n", + " ('anybody', 1),\n", + " ('confortable', 1),\n", + " ('frendly', 1),\n", + " ('daring', 1),\n", + " ('balsamic', 1),\n", + " ('vinegar', 1),\n", + " ('icecream', 1),\n", + " ('expected', 1),\n", + " ('scene', 1),\n", + " ('seems', 1),\n", + " ('happening', 1),\n", + " ('towners', 1),\n", + " ('watching', 1),\n", + " ('sunset', 1),\n", + " ('holiday', 1),\n", + " ('wong', 1),\n", + " ('fill', 1),\n", + " ('stomach', 1),\n", + " ('definately', 1),\n", + " ('expect', 1),\n", + " ('500', 1),\n", + " ('saves', 1),\n", + " ('desk', 1),\n", + " ('disappointing', 1),\n", + " ('lava', 1),\n", + " ('cake', 1),\n", + " ('pleasantly', 1),\n", + " ('suprised', 1),\n", + " ('prepared', 1),\n", + " ('ask', 1),\n", + " ('complimentary', 1),\n", + " ('poor', 1),\n", + " ('ahhh', 1),\n", + " ('especially', 1),\n", + " ('call', 1),\n", + " ('ready', 1),\n", + " ('spanish', 1),\n", + " ('tapas', 1),\n", + " ('creation', 1),\n", + " ('williamsburg', 1),\n", + " ('misstake', 1),\n", + " ('finally', 1),\n", + " ('reliable', 1),\n", + " ('depends', 1),\n", + " ('absolutely', 1),\n", + " ('cheapest', 1),\n", + " ('last', 1),\n", + " ('walked', 1),\n", + " ('looked', 1),\n", + " ('empty', 1),\n", + " ('hmmm', 1),\n", + " ('fire', 1),\n", + " ('ads', 1),\n", + " ('heat', 1),\n", + " ('throughout', 1),\n", + " ('judge', 1),\n", + " ('prima', 1),\n", + " ('facie', 1),\n", + " ('literate', 1),\n", + " ('heart', 1),\n", + " ('dancing', 1),\n", + " ('white', 1),\n", + " ('millenium', 1),\n", + " ('musts', 1),\n", + " ('winner', 1),\n", + " ('arrived', 1),\n", + " ('minutes', 1),\n", + " ('called', 1),\n", + " ('soggy', 1),\n", + " ('now', 1),\n", + " ('inconsistent', 1),\n", + " ('money', 1),\n", + " ('slightly', 1),\n", + " ('fav', 1),\n", + " ('sassy', 1),\n", + " ('lassi', 1),\n", + " ('overlooked', 1),\n", + " ('sit', 1),\n", + " ('forgivable', 1),\n", + " ('asked', 1),\n", + " ('quibbles', 1),\n", + " ('pour', 1),\n", + " ('measures', 1),\n", + " ('liquers', 1),\n", + " ('courtesey', 1),\n", + " ('house', 1),\n", + " ('calling', 1),\n", + " ('hampton', 1),\n", + " ('chutney', 1),\n", + " ('co', 1),\n", + " ('does', 1),\n", + " ('warn', 1),\n", + " ('folks', 1),\n", + " ('substance', 1),\n", + " ('unattractive', 1),\n", + " ('unhelpful', 1),\n", + " ('clerks', 1),\n", + " ('dearth', 1),\n", + " ('former', 1),\n", + " ('father', 1),\n", + " ('flank', 1),\n", + " ('steak', 1),\n", + " ('swordfish', 1),\n", + " ('ignore', 1),\n", + " ('wannabes', 1),\n", + " ('socal', 1),\n", + " ('car', 1),\n", + " ('korean', 1),\n", + " ('32nd', 1),\n", + " ('course', 1),\n", + " ('guarantee', 1),\n", + " ('valet', 1),\n", + " ('parking', 1),\n", + " ('strikes', 1),\n", + " ('located', 1),\n", + " ('strip', 1),\n", + " ('mall', 1),\n", + " ('near', 1),\n", + " ('beverly', 1),\n", + " ('center', 1),\n", + " ('greatest', 1),\n", + " ('keeps', 1),\n", + " ('liked', 1),\n", + " ('point', 1),\n", + " ('snacks', 1),\n", + " ('chat', 1),\n", + " ('appreciate', 1),\n", + " ('delivery', 1),\n", + " ('wasn', 1),\n", + " ('hey', 1),\n", + " ('block', 1),\n", + " ('ain', 1),\n", + " ('delivered', 1),\n", + " ('mint', 1),\n", + " ('retrain', 1),\n", + " ('went', 1),\n", + " ('9', 1),\n", + " ('30', 1),\n", + " ('friday', 1),\n", + " ('died', 1),\n", + " ('leisure', 1),\n", + " ('amidst', 1),\n", + " ('yachts', 1),\n", + " ('stroll', 1),\n", + " ('through', 1),\n", + " ('nearby', 1),\n", + " ('farmer', 1),\n", + " ('son', 1),\n", + " ('cubano', 1),\n", + " ('edgewater', 1),\n", + " ('nj', 1),\n", + " ('instead', 1),\n", + " ('egg', 1),\n", + " ('custards', 1),\n", + " ('pork', 1),\n", + " ('buns', 1),\n", + " ('either', 1),\n", + " ('bakery', 1),\n", + " ('mott', 1),\n", + " ('south', 1),\n", + " ('canal', 1),\n", + " ('meet', 1),\n", + " ('hope', 1),\n", + " ('pays', 1),\n", + " ('attention', 1),\n", + " ('details', 1),\n", + " ('future', 1),\n", + " ('traditional', 1),\n", + " ('french', 1),\n", + " ('decour', 1),\n", + " ('hall', 1),\n", + " ('raise', 1),\n", + " ('voices', 1),\n", + " ('able', 1),\n", + " ('maintain', 1),\n", + " ('negatives', 1),\n", + " ('speak', 1),\n", + " ('inexpensive', 1),\n", + " ('frequently', 1),\n", + " ('6', 1),\n", + " ('perfection', 1),\n", + " ('tiny', 1),\n", + " ('8', 1),\n", + " ('plain', 1),\n", + " ('cramped', 1),\n", + " ('closes', 1),\n", + " ('early', 1),\n", + " ('plan', 1),\n", + " ('asking', 1),\n", + " ('hair', 1),\n", + " ('settle', 1),\n", + " ('getting', 1),\n", + " ('obvious', 1),\n", + " ('idea', 1),\n", + " ('cuisine', 1),\n", + " ('teenage', 1),\n", + " ('kids', 1),\n", + " ('yes', 1),\n", + " ('summer', 1),\n", + " ('outside', 1),\n", + " ('terrace', 1),\n", + " ('feature', 1),\n", + " ('suan', 1),\n", + " ('eaten', 1),\n", + " ('hands', 1),\n", + " ('happy', 1),\n", + " ('deal', 1),\n", + " ('hate', 1),\n", + " ('tourists', 1),\n", + " ('park', 1),\n", + " ('chalet', 1),\n", + " ('francisco', 1),\n", + " ('lets', 1),\n", + " ('company', 1),\n", + " ('family', 1),\n", + " ('general', 1),\n", + " ('dining', 1),\n", + " ('already', 1),\n", + " ('excuses', 1),\n", + " ('ahead', 1),\n", + " ('wks', 1),\n", + " ('jukebox', 1),\n", + " ('risk', 1),\n", + " ('bukhara', 1),\n", + " ('weekend', 1),\n", + " ('southglenn', 1),\n", + " ('largest', 1),\n", + " ('tomorrow', 1),\n", + " ('view', 1),\n", + " ('attached', 1),\n", + " ('angel', 1),\n", + " ('share', 1),\n", + " ('smoked', 1),\n", + " ('yellowtail', 1),\n", + " ('cheap', 1),\n", + " ('chicken', 1),\n", + " ('cant', 1),\n", + " ('name', 1),\n", + " ('sooo', 1),\n", + " ('model', 1),\n", + " ('w', 1),\n", + " ('crowd', 1),\n", + " ('understand', 1),\n", + " ('hype', 1),\n", + " ('single', 1),\n", + " ('problem', 1),\n", + " ('less', 1),\n", + " ('courteous', 1),\n", + " ('st', 1),\n", + " ('bart', 1),\n", + " ('art', 1),\n", + " ('walls', 1),\n", + " ('colorful', 1),\n", + " ('evaluated', 1),\n", + " ('those', 1),\n", + " ('terms', 1),\n", + " ('pastis', 1),\n", + " ('write', 1),\n", + " ('reviews', 1),\n", + " ('moved', 1),\n", + " ('duty', 1),\n", + " ('spread', 1),\n", + " ('word', 1),\n", + " ('aware', 1),\n", + " ('cash', 1),\n", + " ('amex', 1),\n", + " ('makes', 1),\n", + " ('cheaply', 1),\n", + " ('generally', 1),\n", + " ('manhattanite', 1),\n", + " ('rice', 1),\n", + " ('soho', 1),\n", + " ('minus', 1),\n", + " ('pretentious', 1),\n", + " ('clientele', 1),\n", + " ('roosevelt', 1),\n", + " ('plans', 1),\n", + " ('hungry', 1),\n", + " ('run', 1),\n", + " ('sad', 1),\n", + " ('frequent', 1),\n", + " ('hotel', 1),\n", + " ('miss', 1),\n", + " ('esp', 1),\n", + " ('downtown', 1),\n", + " ('jose', 1),\n", + " ('thius', 1),\n", + " ('loves', 1),\n", + " ('refunded', 1),\n", + " ('cal', 1),\n", + " ('effort', 1),\n", + " ('person', 1),\n", + " ('deserves', 1),\n", + " ('shut', 1),\n", + " ('arigato', 1),\n", + " ('gozimas', 1),\n", + " ('boston', 1),\n", + " ('emma', 1),\n", + " ('kendall', 1),\n", + " ('square', 1),\n", + " ('cambridge', 1),\n", + " ('funky', 1),\n", + " ('fool', 1),\n", + " ('heartily', 1),\n", + " ('shouldn', 1),\n", + " ('survives', 1),\n", + " ('competitive', 1),\n", + " ('economy', 1),\n", + " ('matter', 1),\n", + " ('beyond', 1),\n", + " ('tons', 1),\n", + " ('potential', 1),\n", + " ('weren', 1),\n", + " ('impersonal', 1),\n", + " ('corporate', 1),\n", + " ('opened', 1),\n", + " ('reminds', 1),\n", + " ('recent', 1),\n", + " ('italy', 1),\n", + " ('3', 1),\n", + " ('each', 1),\n", + " ('forward', 1),\n", + " ('donot', 1),\n", + " ('cute', 1),\n", + " ('positive', 1),\n", + " ('mioposto', 1),\n", + " ('order', 1),\n", + " ('office', 1),\n", + " ('consider', 1),\n", + " ('companion', 1),\n", + " ('across', 1),\n", + " ('munchies', 1),\n", + " ('boost', 1),\n", + " ('mussels', 1),\n", + " ('nearly', 2),\n", + " ('ever', 2),\n", + " ('unless', 2),\n", + " ('someone', 2),\n", + " ('bill', 2),\n", + " ('hot', 2),\n", + " ('dog', 2),\n", + " ('lovers', 2),\n", + " ('leave', 2),\n", + " ('room', 2),\n", + " ('friend', 2),\n", + " ('same', 2),\n", + " ('sunday', 2),\n", + " ('caviar', 2),\n", + " ('anyone', 2),\n", + " ('certainly', 2),\n", + " ('work', 2),\n", + " ('loved', 2),\n", + " ('however', 2),\n", + " ('stop', 2),\n", + " ('priced', 2),\n", + " ('upper', 2),\n", + " ('though', 2),\n", + " ('bella', 2),\n", + " ('popular', 2),\n", + " ('overall', 2),\n", + " ('decent', 2),\n", + " ('somewhere', 2),\n", + " ('skip', 2),\n", + " ('disappointment', 2),\n", + " ('birthday', 2),\n", + " ('day', 2),\n", + " ('over', 2),\n", + " ('overpriced', 2),\n", + " ('doesn', 2),\n", + " ('average', 2),\n", + " ('yuka', 2),\n", + " ('trouble', 2),\n", + " ('cost', 2),\n", + " ('00', 2),\n", + " ('where', 2),\n", + " ('fresh', 2),\n", + " ('stay', 2),\n", + " ('nights', 2),\n", + " ('appetizer', 2),\n", + " ('believe', 2),\n", + " ('pasta', 2),\n", + " ('penne', 2),\n", + " ('extra', 2),\n", + " ('tasty', 2),\n", + " ('full', 2),\n", + " ('lol', 2),\n", + " ('year', 2),\n", + " ('awesome', 2),\n", + " ('even', 2),\n", + " ('bother', 2),\n", + " ('itself', 2),\n", + " ('worst', 2),\n", + " ('completely', 2),\n", + " ('reason', 2),\n", + " ('spot', 2),\n", + " ('occasion', 2),\n", + " ('didn', 2),\n", + " ('give', 2),\n", + " ('customer', 2),\n", + " ('another', 2),\n", + " ('mother', 2),\n", + " ('dont', 2),\n", + " ('area', 2),\n", + " ('set', 2),\n", + " ('cafe', 2),\n", + " ('because', 2),\n", + " ('mid', 2),\n", + " ('chinese', 2),\n", + " ('sesame', 2),\n", + " ('dine', 2),\n", + " ('avoid', 2),\n", + " ('special', 2),\n", + " ('them', 2),\n", + " ('authentic', 2),\n", + " ('shanghai', 2),\n", + " ('style', 2),\n", + " ('sake', 2),\n", + " ('isn', 2),\n", + " ('thank', 2),\n", + " ('simply', 2),\n", + " ('quite', 2),\n", + " ('delight', 2),\n", + " ('east', 2),\n", + " ('real', 2),\n", + " ('its', 2),\n", + " ('live', 2),\n", + " ('maybe', 2),\n", + " ('chef', 2),\n", + " ('usually', 2),\n", + " ('anytime', 2),\n", + " ('quiet', 2),\n", + " ('looking', 2),\n", + " ('quality', 2),\n", + " ('seen', 2),\n", + " ('ratings', 2),\n", + " ('prices', 2),\n", + " ('reasonable', 2),\n", + " ('busy', 2),\n", + " ('nothing', 2),\n", + " ('find', 2),\n", + " ('without', 2),\n", + " ('large', 2),\n", + " ('creative', 2),\n", + " ('charming', 2),\n", + " ('eats', 2),\n", + " ('casual', 2),\n", + " ('romantic', 2),\n", + " ('perfect', 2),\n", + " ('bar', 2),\n", + " ('wrong', 2),\n", + " ('ok', 2),\n", + " ('conversation', 2),\n", + " ('lunch', 2),\n", + " ('atmosphere', 2),\n", + " ('most', 2),\n", + " ('likely', 2),\n", + " ('something', 2),\n", + " ('offer', 2),\n", + " ('since', 2),\n", + " ('japanese', 2),\n", + " ('luck', 2),\n", + " ('fabulous', 2),\n", + " ('cool', 2),\n", + " ('river', 2),\n", + " ('rolls', 2),\n", + " ('pricey', 2),\n", + " ('noisy', 2),\n", + " ('still', 2),\n", + " ('own', 2),\n", + " ('trendy', 2),\n", + " ('few', 2),\n", + " ('actually', 2),\n", + " ('street', 2),\n", + " ('thing', 2),\n", + " ('pleasant', 2),\n", + " ('5', 2),\n", + " ('bad', 2),\n", + " ('breakfast', 2),\n", + " ('market', 2),\n", + " ('small', 2),\n", + " ('other', 2),\n", + " ('choice', 2),\n", + " ('san', 2),\n", + " ('joint', 2),\n", + " ('long', 2),\n", + " ('attentive', 2),\n", + " ('felt', 2),\n", + " ('avenue', 2),\n", + " ('list', 2),\n", + " ('shabu', 2),\n", + " ('terrible', 2),\n", + " ('won', 3),\n", + " ('else', 3),\n", + " ('must', 3),\n", + " ('fun', 3),\n", + " ('please', 3),\n", + " ('yourself', 3),\n", + " ('ve', 3),\n", + " ('rather', 3),\n", + " ('decor', 3),\n", + " ('needs', 3),\n", + " ('gem', 3),\n", + " ('next', 3),\n", + " ('new', 3),\n", + " ('york', 3),\n", + " ('top', 3),\n", + " ('world', 3),\n", + " ('could', 3),\n", + " ('much', 3),\n", + " ('every', 3),\n", + " ('date', 3),\n", + " ('management', 3),\n", + " ('ny', 3),\n", + " ('meal', 3),\n", + " ('thai', 3),\n", + " ('us', 3),\n", + " ('after', 3),\n", + " ('dishes', 3),\n", + " ('wine', 3),\n", + " ('incredible', 3),\n", + " ('roll', 3),\n", + " ('our', 3),\n", + " ('look', 3),\n", + " ('although', 3),\n", + " ('enough', 3),\n", + " ('indian', 3),\n", + " ('city', 3),\n", + " ('open', 3),\n", + " ('cold', 3),\n", + " ('well', 3),\n", + " ('these', 3),\n", + " ('20', 3),\n", + " ('take', 3),\n", + " ('probably', 3),\n", + " ('eating', 3),\n", + " ('experience', 3),\n", + " ('spend', 3),\n", + " ('home', 3),\n", + " ('village', 3),\n", + " ('2', 3),\n", + " ('nyc', 3),\n", + " ('soon', 3),\n", + " ('toppings', 3),\n", + " ('table', 4),\n", + " ('do', 4),\n", + " ('make', 4),\n", + " ('such', 4),\n", + " ('restaurants', 4),\n", + " ('delicious', 4),\n", + " ('fantastic', 4),\n", + " ('keep', 4),\n", + " ('away', 4),\n", + " ('far', 4),\n", + " ('friendly', 4),\n", + " ('times', 4),\n", + " ('way', 4),\n", + " ('big', 4),\n", + " ('ll', 4),\n", + " ('need', 4),\n", + " ('oh', 4),\n", + " ('love', 4),\n", + " ('night', 4),\n", + " ('think', 4),\n", + " ('off', 4),\n", + " ('say', 4),\n", + " ('menu', 4),\n", + " ('pretty', 4),\n", + " ('location', 4),\n", + " ('their', 4),\n", + " ('how', 4),\n", + " ('favorite', 4),\n", + " ('beautiful', 4),\n", + " ('some', 4),\n", + " ('return', 4),\n", + " ('remember', 4),\n", + " ('taste', 4),\n", + " ('friends', 4),\n", + " ('walk', 4),\n", + " ('once', 4),\n", + " ('then', 4),\n", + " ('down', 4),\n", + " ('late', 4),\n", + " ('dinner', 5),\n", + " ('amazing', 5),\n", + " ('check', 5),\n", + " ('dessert', 5),\n", + " ('disappointed', 5),\n", + " ('pizza', 5),\n", + " ('has', 5),\n", + " ('ambience', 5),\n", + " ('an', 5),\n", + " ('excellent', 5),\n", + " ('feel', 5),\n", + " ('sure', 5),\n", + " ('come', 5),\n", + " ('me', 5),\n", + " ('expensive', 5),\n", + " ('want', 5),\n", + " ('people', 5),\n", + " ('am', 5),\n", + " ('should', 5),\n", + " ('trip', 5),\n", + " ('got', 5),\n", + " ('enjoy', 5),\n", + " ('wish', 5),\n", + " ('cannot', 5),\n", + " ('neighborhood', 5),\n", + " ('around', 5),\n", + " ('sushi', 5),\n", + " ('side', 5),\n", + " ('west', 5),\n", + " ('only', 5),\n", + " ('better', 6),\n", + " ('bit', 6),\n", + " ('m', 6),\n", + " ('d', 6),\n", + " ('price', 6),\n", + " ('when', 6),\n", + " ('by', 6),\n", + " ('always', 6),\n", + " ('coming', 6),\n", + " ('from', 6),\n", + " ('which', 6),\n", + " ('were', 6),\n", + " ('really', 6),\n", + " ('about', 6),\n", + " ('wonderful', 6),\n", + " ('up', 7),\n", + " ('as', 7),\n", + " ('than', 7),\n", + " ('best', 7),\n", + " ('who', 7),\n", + " ('recommended', 7),\n", + " ('what', 7),\n", + " ('also', 7),\n", + " ('little', 7),\n", + " ('nice', 7),\n", + " ('any', 7),\n", + " ('many', 8),\n", + " ('been', 8),\n", + " ('manhattan', 8),\n", + " ('had', 8),\n", + " ('get', 9),\n", + " ('here', 9),\n", + " ('visit', 9),\n", + " ('no', 9),\n", + " ('eat', 9),\n", + " ('definitely', 9),\n", + " ('places', 10),\n", + " ('never', 10),\n", + " ('staff', 10),\n", + " ('too', 10),\n", + " ('try', 10),\n", + " ('worth', 10),\n", + " ('wait', 11),\n", + " ('highly', 11),\n", + " ('out', 12),\n", + " ('time', 12),\n", + " ('like', 12),\n", + " ('recommend', 12),\n", + " ('again', 12),\n", + " ('going', 12),\n", + " ('re', 13),\n", + " ('don', 13),\n", + " ('they', 14),\n", + " ('my', 14),\n", + " ('or', 14),\n", + " ('one', 15),\n", + " ('would', 15),\n", + " ('just', 15),\n", + " ('very', 16),\n", + " ('with', 16),\n", + " ('at', 17),\n", + " ('so', 18),\n", + " ('restaurant', 18),\n", + " ('can', 18),\n", + " ('more', 18),\n", + " ('if', 19),\n", + " ('have', 19),\n", + " ('will', 19),\n", + " ('your', 19),\n", + " ('all', 20),\n", + " ('we', 20),\n", + " ('there', 21),\n", + " ('on', 22),\n", + " ('are', 24),\n", + " ('service', 24),\n", + " ('great', 25),\n", + " ('not', 26),\n", + " ('good', 27),\n", + " ('but', 28),\n", + " ('be', 28),\n", + " ('food', 28),\n", + " ('that', 29),\n", + " ('s', 31),\n", + " ('go', 32),\n", + " ('t', 35),\n", + " ('back', 36),\n", + " ('of', 37),\n", + " ('was', 39),\n", + " ('place', 43),\n", + " ('this', 44),\n", + " ('in', 53),\n", + " ('you', 55),\n", + " ('for', 56),\n", + " ('it', 75),\n", + " ('is', 79),\n", + " ('i', 90),\n", + " ('and', 92),\n", + " ('to', 97),\n", + " ('a', 103),\n", + " ('the', 177),\n", + " ...]" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import operator \n", + "sorted(countings.items(), key=operator.itemgetter(1))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "***\n", + "\n", + "O que essa regex está fazendo é basicamente convertendo todo o texto para minúsculo e depois 'splitando' em tokens sempre que o texto encontra um caracter em brando (\\s) **ou** sempre que encontra um caracter que **não** é alfanumérico ([^a-zA-Z0-9]), representado pelo \\W\n", + "\n", + "Depois, ela pega as 10 ocorrências mais comumns.\n", + "\n", + "***" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "No spacy já existe uma lista de stopwords comuns, que podemos ver assim:" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['no', 'nobody', 'none', 'noone', 'nor', 'not']" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "nlp = spacy.load('en_core_web_sm')\n", + "\n", + "en_stopwords = sorted([token.text for token in nlp.vocab if token.is_stop])\n", + "en_stopwords[155:161]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "* Exercício:\n", + "Explore um pouco a lista e analise as que você acha que podem ser excluídas." + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [], + "source": [ + "#list_excl = ['cannot', 'go', 'off']\n", + "list_excl = ['cannot', 'go', 'never', 'no', 'nobody', 'none', 'noone', 'nor', 'not', 'nothing', 'nowhere', 'off']\n", + "\n", + "\n", + "for w in list_excl:\n", + " nlp.vocab[w].is_stop = False" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Para verificarmos quais palavras excluímos da lista de stopwords:" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'cannot -- go -- never -- no -- nobody -- none -- noone -- nor -- not -- nothing -- nowhere -- off'" + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "' -- '.join([w for w in en_stopwords if not nlp.vocab[w].is_stop])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- Além de excluir, podemos também incluir, pois, como dito no início da conversa sobre *stopwords*, podem entrar na lista as palavras muito comuns dentro do contexto referente aos documentos do corpus.\n", + "- Outra forma de **definir stopwords** é **verificando a frequência das palavras no corpus**, ou seja, contando a frequência de cada token no *corpus*." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Stemming\n", + "Normalize words into its base or root form, using common prefixes and suffixes.\n", + "\n", + "Exemplo: affectation, affects, affections, affected, affection, affecting -> affect.\n", + "\n", + "Problemas: boiando -> boi, factual -> fact (suffixe \"ual\"), equal -> eq (suffixe \"ual\")." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Lemmatization\n", + "Also maps several similar words into one common root, but groups together different inflected forms of a word to its *lemma* (dictionary needed), which is a proper word. \n", + "\n", + "Exemplo: gone, going, went -> go" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Part-Of-Speech (POS) Tags\n", + "Grammatical type of the word: noun, verb, adjective, adverb, pronoun, preposition, conjunction, determiner, exclamation.\n", + "\n", + "Exemplo: \n", + "\n", + "" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "##### Objeto \"Token\" - Spacy\n", + "\n", + "É possível carregar alguns modelos pré treinados no Spacy para prever atributos linguísticos, como:\n", + "\n", + "- POS tags (classificação gramátical - Apple companhia vs apple fruta)\n", + "- Nomeação de Entidades (Apple companhia, Photograph Nickelback album)\n", + "\n", + "\n", + "Tais modelos estão divididos em pacotes que precisam ser baixados, como o 'en_core_web_sm', pacote com vários modelos treinados em inglês.\n", + "\n", + "\n", + "O objeto Token é um objeto que possui vários atributos, inclusive o \"pos_\" . Outros atributos importantes/legais:\n", + "\n", + "" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "She PRON\n", + "ate VERB\n", + "the DET\n", + "pizza NOUN\n" + ] + } + ], + "source": [ + "nlp = English()\n", + "nlp = spacy.load('en_core_web_sm')\n", + "\n", + "doc = nlp(\"She ate the pizza\")\n", + "for token in doc:\n", + " print(token.text, token.pos_)" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Photograph ORG\n", + "Nicklelback PERSON\n", + "yesterday DATE\n" + ] + } + ], + "source": [ + "doc = nlp(\"I heard Photograph from Nicklelback yesterday !\")\n", + "for ent in doc.ents:\n", + " print(ent.text, ent.label_)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "* Exercício: Se usarmos .lower() no texto abaixo, como ficam as entidades?" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "yesterday DATE\n" + ] + } + ], + "source": [ + "# Process the text in lowercase\n", + "text = \"I heard Photograph from Nicklelback yesterday!\"\n", + "doc = nlp(text.lower())\n", + "\n", + "# Print entities' texts and labels \n", + "for ent in doc.ents:\n", + " print(ent.text, ent.label_)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Normalização:\n", + "\n", + "- Além do que já comentamos até aqui, outras diferentes formas de escrever a mesma coisa podem \"confundir\" os algoritmos. \n", + "\n", + "- Transformar o texto todo em minúsculo e retirar acentos, pro exemplo, são bastante comuns. \n", + "\n", + "CUIDADO pra essas etapas não atrapalharem outras, como identificação de entidades!!!\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "##### Contractions \n", + "Outro exemplo de normalização interessante na língua inglesa é a expansão de contrações: I'm -> I am, We're -> we are etc.\n", + "\n", + "Para expansão de contractions, usaremos o [PyContractions](https://pypi.org/project/pycontractions/) e especificaremos o modelo da api gensim.downloader:" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['we are all so happy!! cannot believe this!']" + ] + }, + "execution_count": 39, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cont = Contractions(api_key=\"glove-twitter-100\")\n", + "list(cont.expand_texts([\"We're all so happy!! Can't believe this!\"]))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Etapas do pré-processamento:\n", + "\n", + "\n", + "1. Remove entidades (remove_ents);\n", + "2. Expande constrações (expand_contractions);\n", + "3. Transforme tudo para minúscula;\n", + "4. Remove stopwords e pontuações (remove_stop_and_punct).\n", + "\n", + "IMPORTANTE: Atenção na ordem!!!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- Exercício: Crie uma função ```preprocess``` que recebe qualquer string como entrada e faz todas as etapas do pré-processamento." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "def remove_ents(text):\n", + " doc = nlp(text)\n", + " for ent in doc.ents:\n", + " text = text.replace(ent.text, '')\n", + " return text\n", + "\n", + "\n", + "def expand_contractions(text):\n", + " return list(cont.expand_texts([text]))[0]\n", + "\n", + " \n", + "def remove_stop_and_punct(text):\n", + " doc = nlp(text.lower())\n", + " tokens = []\n", + " for token in doc:\n", + " if token.is_stop or token.is_punct:\n", + " continue\n", + " tokens.append(token.text)\n", + " return ' '.join(tokens)" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "def preprocess(original_text):\n", + " new_text = remove_ents(original_text)\n", + " new_text = expand_contractions(new_text)\n", + " if len(new_text) == 0:\n", + " return new_text \n", + " return remove_stop_and_punct(new_text)" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [], + "source": [ + "#Ja fizemos isso neste notebook, mas aqui teriamos que carregar esses objetos se já não estivéssemos feito ainda, \n", + "#pois as funções estão usando-os. Porém, atenção: carregamos E alteramos o en_core_web_sm quando exluímos algumas \n", + "#palavras da lista de stopwords, então se carregarmos novamente, temos que excluir as stopwords novamente também\n", + "\n", + "#nlp = English()\n", + "#nlp = spacy.load('en_core_web_sm') " + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [], + "source": [ + "assert(preprocess(\"It's also not attached to Angel's Share, which is a cool, more romantic bar...\") \n", + " == 'not attached cool romantic bar')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- Exercício: Aplique sua função preprocess à coluna text (dos dois dataframes, train_df e test_df), criando uma coluna nova norm_text, que será usada para treinarmos um modelo de análise de sentimento. Dica: Use o apply do pandas!" + ] + }, + { + "cell_type": "code", + "execution_count": 316, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train:\n", + "\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
textnorm_textpolarity
193One of my favorite places in Manhattan.favorite placespositive
240It is obvious that no one in the restaurant has any idea about or experience with Japanese cuisine.obvious no restaurant idea experience cuisinenegative
188My fav was the sassy lassi...fav sassy lassipositive
213An excellent serviceexcellent servicepositive
319DONOT GO!donot gonegative
\n", + "
" + ], + "text/plain": [ + " text \\\n", + "193 One of my favorite places in Manhattan. \n", + "240 It is obvious that no one in the restaurant has any idea about or experience with Japanese cuisine. \n", + "188 My fav was the sassy lassi... \n", + "213 An excellent service \n", + "319 DONOT GO! \n", + "\n", + " norm_text polarity \n", + "193 favorite places positive \n", + "240 obvious no restaurant idea experience cuisine negative \n", + "188 fav sassy lassi positive \n", + "213 excellent service positive \n", + "319 donot go negative " + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "train_df['norm_text'] = train_df['text'].apply(preprocess)\n", + "train_df.to_pickle('data/processed/train_preprocessed.pickle')\n", + "print(\"Train:\\n\")\n", + "display(train_df[['text','norm_text','polarity']].sample(n=5))" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Test:\n", + "\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
textnorm_textpolarity
4Can’t believe how an expensive NYC restaurant can be so disrespectful to its clients.n’t believe expensive restaurant disrespectful clientsnegative
65They are not greasy or anything.not greasynegative
19A perfect place to take out of town guests any time of the year.perfect place town guests timepositive
8The food is great and they make a mean bloody mary.food great mean bloody marypositive
74I noticed alot of indian people eatting there which is a great sign for an indian place!noticed alot indian people eatting great sign indian placepositive
\n", + "
" + ], + "text/plain": [ + " text \\\n", + "4 Can’t believe how an expensive NYC restaurant can be so disrespectful to its clients. \n", + "65 They are not greasy or anything. \n", + "19 A perfect place to take out of town guests any time of the year. \n", + "8 The food is great and they make a mean bloody mary. \n", + "74 I noticed alot of indian people eatting there which is a great sign for an indian place! \n", + "\n", + " norm_text polarity \n", + "4 n’t believe expensive restaurant disrespectful clients negative \n", + "65 not greasy negative \n", + "19 perfect place town guests time positive \n", + "8 food great mean bloody mary positive \n", + "74 noticed alot indian people eatting great sign indian place positive " + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "test_df['norm_text'] = test_df['text'].apply(preprocess)\n", + "test_df.to_pickle('data/processed/train_preprocessed.pickle')\n", + "print(\"Test:\\n\")\n", + "display(test_df[['text','norm_text','polarity']].sample(n=5))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Feature engineering" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Bag of words\n", + "\n", + "" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- Com o Scikit Learn: [CountVectorizer](https://scikit-learn.org/0.19/modules/generated/sklearn.feature_extraction.text.CountVectorizer.html)" + ] + }, + { + "cell_type": "code", + "execution_count": 73, + "metadata": {}, + "outputs": [], + "source": [ + "examples_for_bow = [\n", + " 'camisa preta botao botao botao',\n", + " 'botao feito linha preta',\n", + " 'considera-se caro preco botao camisa botao',\n", + " 'linha costurar botão mesma camisa',\n", + " 'costurar linha camisa mesma botao'\n", + "]" + ] + }, + { + "cell_type": "code", + "execution_count": 122, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
botaocamisacaroconsideracosturarfeitolinhamesmaprecopretase
011000000010
110000110010
211110000101
311001011000
411001011000
\n", + "
" + ], + "text/plain": [ + " botao camisa caro considera costurar feito linha mesma preco \\\n", + "0 1 1 0 0 0 0 0 0 0 \n", + "1 1 0 0 0 0 1 1 0 0 \n", + "2 1 1 1 1 0 0 0 0 1 \n", + "3 1 1 0 0 1 0 1 1 0 \n", + "4 1 1 0 0 1 0 1 1 0 \n", + "\n", + " preta se \n", + "0 1 0 \n", + "1 1 0 \n", + "2 0 1 \n", + "3 0 0 \n", + "4 0 0 " + ] + }, + "execution_count": 122, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cv = CountVectorizer(strip_accents='unicode', binary=True)\n", + "bow_matrix = cv.fit_transform(examples_for_bow)\n", + "columns = [token[0] for token in sorted(cv.vocabulary_.items(), key=lambda item: item[1])]\n", + "pd.DataFrame(bow_matrix.todense(), columns=columns)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- Exercício: Use o parâmetro 'max_features' do CountVectorizer para diminuir a quantidade de dimensões e veja a diferença na matriz resultante:" + ] + }, + { + "cell_type": "code", + "execution_count": 126, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
botaocamisacosturarlinhamesma
011000
110010
211000
311111
411111
\n", + "
" + ], + "text/plain": [ + " botao camisa costurar linha mesma\n", + "0 1 1 0 0 0\n", + "1 1 0 0 1 0\n", + "2 1 1 0 0 0\n", + "3 1 1 1 1 1\n", + "4 1 1 1 1 1" + ] + }, + "execution_count": 126, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cv_5 = CountVectorizer(max_features=5, strip_accents='unicode', binary=True)\n", + "bow_matrix_5 = cv_5.fit_transform(examples_for_bow)\n", + "columns = [token[0] for token in sorted(cv_5.vocabulary_.items(), key=lambda item: item[1])]\n", + "pd.DataFrame(bow_matrix_5.todense(),columns=columns)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### TF: E se usássemos a quantidade de vezes que o token ocorre?\n", + "" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- Exercício: usando o [CountVectorizer](https://scikit-learn.org/0.19/modules/generated/sklearn.feature_extraction.text.CountVectorizer.html) mesmo, como obter a matriz TF?" + ] + }, + { + "cell_type": "code", + "execution_count": 127, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
botaocamisacaroconsideracosturarfeitolinhamesmaprecopretase
031000000010
110000110010
221110000101
311001011000
411001011000
\n", + "
" + ], + "text/plain": [ + " botao camisa caro considera costurar feito linha mesma preco \\\n", + "0 3 1 0 0 0 0 0 0 0 \n", + "1 1 0 0 0 0 1 1 0 0 \n", + "2 2 1 1 1 0 0 0 0 1 \n", + "3 1 1 0 0 1 0 1 1 0 \n", + "4 1 1 0 0 1 0 1 1 0 \n", + "\n", + " preta se \n", + "0 1 0 \n", + "1 1 0 \n", + "2 0 1 \n", + "3 0 0 \n", + "4 0 0 " + ] + }, + "execution_count": 127, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cv = CountVectorizer(strip_accents='unicode')\n", + "bow_matrix = cv.fit_transform(examples_for_bow)\n", + "columns = [token[0] for token in sorted(cv.vocabulary_.items(), key=lambda item: item[1])]\n", + "pd.DataFrame(bow_matrix.todense(), columns=columns)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### TF-IDF\n", + "" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- No Scikit Learn: [TfidfVectorizer](https://scikit-learn.org/0.19/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html)" + ] + }, + { + "cell_type": "code", + "execution_count": 128, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
botaocamisacaroconsideracosturarfeitolinhamesmaprecopretase
00.8237090.3246300.0000000.0000000.0000000.0000000.0000000.0000000.0000000.4648870.000000
10.3124050.0000000.0000000.0000000.0000000.6556160.4390740.0000000.0000000.5289470.000000
20.4168970.2464530.4374520.4374520.0000000.0000000.0000000.0000000.4374520.0000000.437452
30.3145540.3719040.0000000.0000000.5325860.0000000.4420950.5325860.0000000.0000000.000000
40.3145540.3719040.0000000.0000000.5325860.0000000.4420950.5325860.0000000.0000000.000000
\n", + "
" + ], + "text/plain": [ + " botao camisa caro considera costurar feito linha \\\n", + "0 0.823709 0.324630 0.000000 0.000000 0.000000 0.000000 0.000000 \n", + "1 0.312405 0.000000 0.000000 0.000000 0.000000 0.655616 0.439074 \n", + "2 0.416897 0.246453 0.437452 0.437452 0.000000 0.000000 0.000000 \n", + "3 0.314554 0.371904 0.000000 0.000000 0.532586 0.000000 0.442095 \n", + "4 0.314554 0.371904 0.000000 0.000000 0.532586 0.000000 0.442095 \n", + "\n", + " mesma preco preta se \n", + "0 0.000000 0.000000 0.464887 0.000000 \n", + "1 0.000000 0.000000 0.528947 0.000000 \n", + "2 0.000000 0.437452 0.000000 0.437452 \n", + "3 0.532586 0.000000 0.000000 0.000000 \n", + "4 0.532586 0.000000 0.000000 0.000000 " + ] + }, + "execution_count": 128, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cv = TfidfVectorizer(strip_accents='unicode', norm=None) #com norm default, ele aplica uma normalização l2 (vejam doc)\n", + "bow_matrix = cv.fit_transform(examples_for_bow)\n", + "columns = [token[0] for token in sorted(cv.vocabulary_.items(), key=lambda item: item[1])]\n", + "pd.DataFrame(bow_matrix.todense(), columns=columns)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### N-grams\n", + "" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Modelo" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Os dados estão prontos para \"enviar\" pro modelo?" + ] + }, + { + "cell_type": "code", + "execution_count": 131, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
textpolaritynorm_texty
69Highly recommended.positivehighly recommended1
68That place was awesome,,, sally !negativeplace awesome sally0
145For a restaurant with such a good reputation and that is usually so packed, there was no reason for such a lack of intelligent customer service.positiverestaurant good reputation usually packed no reason lack intelligent customer service1
\n", + "
" + ], + "text/plain": [ + " text \\\n", + "69 Highly recommended. \n", + "68 That place was awesome,,, sally ! \n", + "145 For a restaurant with such a good reputation and that is usually so packed, there was no reason for such a lack of intelligent customer service. \n", + "\n", + " polarity \\\n", + "69 positive \n", + "68 negative \n", + "145 positive \n", + "\n", + " norm_text \\\n", + "69 highly recommended \n", + "68 place awesome sally \n", + "145 restaurant good reputation usually packed no reason lack intelligent customer service \n", + "\n", + " y \n", + "69 1 \n", + "68 0 \n", + "145 1 " + ] + }, + "execution_count": 131, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "train_df.sample(3)" + ] + }, + { + "cell_type": "code", + "execution_count": 132, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
textpolaritynorm_texty
11Maybe I'll go back once more many years from now when I've forgotten I went there already.negativemaybe go years forgotten went0
19A perfect place to take out of town guests any time of the year.positiveperfect place town guests time1
14Warning: You may find it difficult to dine at other Japanese restaurants after a visit to Mizu!positivewarning find difficult dine restaurants visit mizu1
\n", + "
" + ], + "text/plain": [ + " text \\\n", + "11 Maybe I'll go back once more many years from now when I've forgotten I went there already. \n", + "19 A perfect place to take out of town guests any time of the year. \n", + "14 Warning: You may find it difficult to dine at other Japanese restaurants after a visit to Mizu! \n", + "\n", + " polarity norm_text y \n", + "11 negative maybe go years forgotten went 0 \n", + "19 positive perfect place town guests time 1 \n", + "14 positive warning find difficult dine restaurants visit mizu 1 " + ] + }, + "execution_count": 132, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "test_df.sample(3)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + ".\n", + "\n", + ".\n", + "\n", + ".\n", + "\n", + ".\n", + "\n", + ".\n", + "\n", + ".\n", + "\n", + ".\n", + "\n", + ".\n", + "\n", + ".\n", + "\n", + ".\n", + "\n", + ".\n", + "\n", + ".\n", + "\n", + "." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Não, ne? Próximos passos:\n", + "1. Target de string pra inteiro.\n", + "2. Separar X_train, y_train, X_test, y_test" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- Exercício: transforme a coluna polarity em inteiro (0 se \"negative\" e 1 se \"positive\") e verifique em um sample o resultado." + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
textpolaritynorm_texty
11Decor needs to be upgraded but the food is amazing!positiveneeds upgraded food amazing1
23I thanked my friend who recommended me this restaurant and will certainly recommend it to others.positivethanked friend recommended restaurant certainly recommend1
248I'd hate for tourists to go to Park Chalet and think that this is how all San Francisco restaurants are like.negativehate tourists go think restaurants like0
\n", + "
" + ], + "text/plain": [ + " text \\\n", + "11 Decor needs to be upgraded but the food is amazing! \n", + "23 I thanked my friend who recommended me this restaurant and will certainly recommend it to others. \n", + "248 I'd hate for tourists to go to Park Chalet and think that this is how all San Francisco restaurants are like. \n", + "\n", + " polarity norm_text y \n", + "11 positive needs upgraded food amazing 1 \n", + "23 positive thanked friend recommended restaurant certainly recommend 1 \n", + "248 negative hate tourists go think restaurants like 0 " + ] + }, + "execution_count": 40, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "train_df['y'] = (train_df['polarity'] == 'positive').astype(int)\n", + "train_df.sample(3)" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
textpolaritynorm_texty
0To be completely fair, the only redeeming factor was the food, which was above average, but couldn't make up for all the other deficiencies of Teodora.negativecompletely fair redeeming factor food average not deficiencies0
44Can't wait wait for my next visit.positivenot wait wait visit1
6The wine list is also really nice.positivewine list nice1
\n", + "
" + ], + "text/plain": [ + " text \\\n", + "0 To be completely fair, the only redeeming factor was the food, which was above average, but couldn't make up for all the other deficiencies of Teodora. \n", + "44 Can't wait wait for my next visit. \n", + "6 The wine list is also really nice. \n", + "\n", + " polarity norm_text \\\n", + "0 negative completely fair redeeming factor food average not deficiencies \n", + "44 positive not wait wait visit \n", + "6 positive wine list nice \n", + "\n", + " y \n", + "0 0 \n", + "44 1 \n", + "6 1 " + ] + }, + "execution_count": 41, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "test_df['y'] = (test_df['polarity'] == 'positive').astype(int)\n", + "test_df.sample(3)" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
textpolaritynorm_texty
139If you're interested in good tasting (without the fish taste or smell), large portions and creative sushi dishes this is your place...positiveinterested good tasting fish taste smell large portions creative sushi dishes place1
13Sunday afternoons there is a band playing and it is lots of fun.positiveafternoons band playing lots fun1
14210positive1
\n", + "
" + ], + "text/plain": [ + " text \\\n", + "139 If you're interested in good tasting (without the fish taste or smell), large portions and creative sushi dishes this is your place... \n", + "13 Sunday afternoons there is a band playing and it is lots of fun. \n", + "142 10 \n", + "\n", + " polarity \\\n", + "139 positive \n", + "13 positive \n", + "142 positive \n", + "\n", + " norm_text \\\n", + "139 interested good tasting fish taste smell large portions creative sushi dishes place \n", + "13 afternoons band playing lots fun \n", + "142 \n", + "\n", + " y \n", + "139 1 \n", + "13 1 \n", + "142 1 " + ] + }, + "execution_count": 42, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "train_df[train_df['y']==1].sample(3)" + ] + }, + { + "cell_type": "code", + "execution_count": 132, + "metadata": {}, + "outputs": [], + "source": [ + "X_train = train_df['norm_text'].values\n", + "y_train = train_df['y'].values\n", + "X_test = test_df['norm_text'].values\n", + "y_test = test_df['y'].values" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- Exercício: monte um [Pipeline](https://scikit-learn.org/0.19/modules/generated/sklearn.pipeline.Pipeline.html) com o CountVectorizer e LogisticRegression" + ] + }, + { + "cell_type": "code", + "execution_count": 306, + "metadata": {}, + "outputs": [], + "source": [ + "steps = [\n", + " ('vect', CountVectorizer(binary=True)),\n", + "# ('dens', DenseTransformer()),\n", + " ('clf', LogisticRegression())\n", + "]\n", + "\n", + "pipeline = Pipeline(steps)" + ] + }, + { + "cell_type": "code", + "execution_count": 307, + "metadata": {}, + "outputs": [], + "source": [ + "sentiment_analyzer = pipeline.fit(X_train, y_train)" + ] + }, + { + "cell_type": "code", + "execution_count": 308, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([1])" + ] + }, + "execution_count": 308, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sentiment_analyzer.predict([\"It's also attached to Angel's Share, which is a cool, more romantic bar...\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 309, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[ 0.11067992, 0.88932008]])" + ] + }, + "execution_count": 309, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sentiment_analyzer.predict_proba([\"It's also attached to Angel's Share, which is a cool, more romantic bar...\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Avaliação" + ] + }, + { + "cell_type": "code", + "execution_count": 310, + "metadata": {}, + "outputs": [], + "source": [ + "y_pred = sentiment_analyzer.predict(X_test)" + ] + }, + { + "cell_type": "code", + "execution_count": 311, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " precision recall f1-score support\n", + "\n", + " negative 0.67 0.26 0.38 23\n", + " positive 0.77 0.95 0.85 59\n", + "\n", + "avg / total 0.74 0.76 0.72 82\n", + "\n" + ] + } + ], + "source": [ + "class_names = ['negative', 'positive']\n", + "classification_report(y_test, y_pred, target_names=class_names)" + ] + }, + { + "cell_type": "code", + "execution_count": 312, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Confusion matrix, without normalization\n", + "[[ 6 17]\n", + " [ 3 56]]\n", + "Normalized confusion matrix\n", + "[[ 0.26086957 0.73913043]\n", + " [ 0.05084746 0.94915254]]\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# Plot non-normalized confusion matrix\n", + "plot_confusion_matrix(y_test, y_pred);\n", + "\n", + "# Plot normalized confusion matrix\n", + "plot_confusion_matrix(y_test, y_pred, normalize=True);" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.5" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +}