<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Sentiment analysis - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Sentiment analysis - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Mon, 21 Sep 2026 05:11:09 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/sentiment-analysis/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Simple Sentiment Analyzer Using Hugging Face Transformer ]]>
                </title>
                <description>
                    <![CDATA[ In this article, we will look at writing a sentiment analyzer using Hugging Face Transformer, a powerful tool in the world of NLP.  Imagine you’re running a business and you want to know what your customers think about your product. Or maybe you’re a... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-a-simple-sentiment-analyzer-using-hugging-face-transformer/</link>
                <guid isPermaLink="false">66d035d812c679876b0602de</guid>
                
                    <category>
                        <![CDATA[ natural language processing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ nlp ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Sentiment analysis ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Manish Shivanandhan ]]>
                </dc:creator>
                <pubDate>Fri, 26 Jan 2024 00:32:04 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/01/pngtree-facial-emotions-illustration-in-black-outline-on-white-background-vector-picture-image_10574137.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this article, we will look at writing a sentiment analyzer using Hugging Face Transformer, a powerful tool in the world of NLP. </p>
<p>Imagine you’re running a business and you want to know what your customers think about your product. Or maybe you’re a movie director wanting to gauge the public reaction to your latest release.</p>
<p>This is where sentiment analysis comes into play.</p>
<blockquote>
<p>Sentiment analysis is a technique used in text analysis that helps in identifying and categorizing opinions expressed in a piece of text.</p>
</blockquote>
<p>Sentiment analysis determines whether the expressed opinion in a document, a sentence or an entity feature/aspect is positive, negative, or neutral.</p>
<p>In a world where data is king, sentiment analysis is a crown jewel. It’s like having a superpower to understand the emotional tone behind words at scale.</p>
<p>Companies use it to understand customer feedback on products and services. Governments and organizations use it to get a sense of public opinion.</p>
<p>In social media management, sentiment analysis is used for brand monitoring, customer service, and market research.</p>
<p>It’s not just about understanding how many people are talking about your brand or product, but how they feel about it.</p>
<h2 id="heading-what-is-hugging-face">What is Hugging Face?</h2>
<p>Now, let’s talk about Hugging Face. No, it’s not what you think. You don’t go around hugging faces.</p>
<p>In the world of AI, <a target="_blank" href="https://huggingface.co/">Hugging Face</a> is quite the star. It’s an AI community and platform that provides state-of-the-art tools and models for Natural Language Processing (NLP).</p>
<p>Think of it as a toolbox that gives you the power to understand and generate human language. It’s like having a linguistic wizard by your side.</p>
<p>Hugging Face’s most popular offering is the ‘Transformers’ library. The Transformers library comes packed with APIs and tools that let you easily grab and train top-notch pre-trained models.</p>
<p>When you pick these pre-trained models, you’re cutting down on compute costs and carbon footprint. Plus, you save loads of time and resources that you’d otherwise spend training a model from scratch.</p>
<p>These models solve common tasks across various domains, like:</p>
<ul>
<li><strong>Natural Language Processing (NLP)</strong>: Here, you can do a bunch of cool stuff like text classification, spotting names or entities in text, answering questions, language modelling, summarizing, translating, handling multiple-choice questions, and even generating text.</li>
<li><strong>Computer Vision:</strong> This involves image classification, spotting and outlining objects in images, and more.</li>
<li><strong>Audio:</strong> You can work on recognizing speech automatically and classifying different types of sounds.</li>
<li><strong>Multimodal Tasks:</strong> These are tasks that mix it up, like answering questions based on tables, recognizing text in images (like scanned documents), pulling out information from these documents, classifying videos, and answering questions based on images.</li>
</ul>
<p>The neat thing about Transformers is that they’re flexible with different frameworks. Whether you’re into <a target="_blank" href="https://turingtalks.substack.com/p/pytorch-vs-tensorflow-for-deep-learning">PyTorch</a>, TensorFlow, or JAX, Transformers has got you covered.</p>
<p>Its ease of use and comprehensive nature make it a go-to for researchers, developers, and businesses alike.</p>
<h2 id="heading-code-for-sentiment-analysis">Code for Sentiment Analysis</h2>
<p>Now that you know what sentiment analysis and Hugging Face are, let’s write some code. We’ll use Python and the Hugging Face <code>transformers</code> library to build a simple sentiment analyzer.</p>
<p>You can either use your terminal, install Python and run the code, or use a <a target="_blank" href="https://colab.research.google.com/">Google Colab notebook</a>. I would recommend the latter since it comes pre-installed with Python.</p>
<p>Install the <code>transformers</code>library with this command:</p>
<pre><code>pip install transformers
</code></pre><p>If you are using a Colab notebook, use a <strong>!</strong> symbol before the command for the notebook to treat it as a shell command (Colab executes code as Python by default).</p>
<pre><code>!pip install transfomers
</code></pre><p>Once the installation is complete, you can start using the library. First, let's import <code>pipeline</code> from the transformers library.</p>
<pre><code><span class="hljs-keyword">from</span> transformers <span class="hljs-keyword">import</span> pipeline
</code></pre><p>In Hugging Face, a “pipeline” is like a tool that helps you perform a series of steps to change data into the form you want. The pipeline makes it simple to use these tools for different jobs, without needing to know all the complex details about how these tools work on the inside.</p>
<p>Now let’s load the <code>sentiment-analysis</code> pipeline.</p>
<pre><code>sentiment_pipeline = pipeline(<span class="hljs-string">"sentiment-analysis"</span>)
</code></pre><p>Now would you believe me if I said we are pretty much done? Our sentiment analysis model is ready and we can pass text to the pipeline and get the label as well as a sentiment score.</p>
<pre><code># Run sentiment analysis
result = sentiment_pipeline(<span class="hljs-string">"Every new day brings a chance to create joyful memories and embrace new opportunities."</span>)

# Print the result
print(result)
</code></pre><p>This is the output of the above code:</p>
<pre><code>[{<span class="hljs-string">'label'</span>: <span class="hljs-string">'POSITIVE'</span>, <span class="hljs-string">'score'</span>: <span class="hljs-number">0.9998821020126343</span>}]
</code></pre><p>If you want to pass multiple sentences, pass an array of inputs to the pipeline.</p>
<pre><code>result = sentiment_pipeline([<span class="hljs-string">"Every new day brings a chance to create joyful memories and embrace new opportunities."</span>,<span class="hljs-string">"Despite the effort, the project failed to meet expectations, leading to disappointment and frustration among the team."</span>])
print(result)
</code></pre><p>Following will be the output of the above code:</p>
<pre><code>[{<span class="hljs-string">'label'</span>: <span class="hljs-string">'POSITIVE'</span>, <span class="hljs-string">'score'</span>: <span class="hljs-number">0.9998821020126343</span>}, {<span class="hljs-string">'label'</span>: <span class="hljs-string">'NEGATIVE'</span>, <span class="hljs-string">'score'</span>: <span class="hljs-number">0.9997937083244324</span>}]
</code></pre><p>I hope you understand how powerful the Hugging Face Transformer library is. This is just a sample of the many pre-trained models that Hugging Face provides. Unless you are working on a unique problem, you should find a pre-trained model in Hugging Face available for you to work with.</p>
<h2 id="heading-summary">Summary</h2>
<p>In this article, we’ve learned about sentiment analysis and Hugging Face, a powerful tool in the world of NLP. Most importantly, you’ve taken your first steps in performing sentiment analysis by using the Hugging Face Transformers library.</p>
<p>Remember, what we’ve covered is just the tip of the iceberg. The field of NLP is vast and constantly evolving. The Hugging Face Transformers library is a powerful ally in your journey through AI. It simplifies complex tasks and gives you access to pre-trained models, saving you time and resources.</p>
<p>Hope you enjoyed this article. Find more beginner-friendly articles on AI at <strong><a target="_blank" href="https://www.turingtalks.ai/">turingtalks.ai</a></strong></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Sentiment Analysis App using Blenderbot ]]>
                </title>
                <description>
                    <![CDATA[ By Edem Gold Turning machine learning models into actual applications other people can use is not something that is covered in most AI and Machine Learning Tutorials. In this article, we are going to create an end-to-end AI Sentiment Analysis web app... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-a-sentiment-analayis-app-using-blenderbot/</link>
                <guid isPermaLink="false">66d84fc363d2055c664a1a61</guid>
                
                    <category>
                        <![CDATA[ Artificial Intelligence ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Machine Learning ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Sentiment analysis ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 31 Jan 2022 15:07:33 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/01/cover.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Edem Gold</p>
<p>Turning machine learning models into actual applications other people can use is not something that is covered in most AI and Machine Learning Tutorials.</p>
<p>In this article, we are going to create an end-to-end AI Sentiment Analysis web application using Gradio and Hugging face transformers.</p>
<h1 id="heading-what-is-sentiment-analysis">What is Sentiment Analysis?</h1>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1635883449621/fWPS8d_c-.jpeg?auto=compress,format&amp;format=webp" alt="pic-1.jpg" width="626" height="417" loading="lazy"></p>
<p>According to <a target="_blank" href="https://en.wikipedia.org/wiki/Sentiment_analysis">Wikipedia</a>, </p>
<blockquote>
<p>Sentiment analysis is the use of natural language processing, text analysis, computational linguistics, and biometrics to systematically identify, extract, quantify, and study affective states and subjective information.</p>
</blockquote>
<p>In simple words, Sentiment Analysis is the ability of Artificial Intelligence to analyze a sentence or block of text and get the emotions behind that sentence or block of text.</p>
<h1 id="heading-what-is-gradio">What is Gradio?</h1>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1635883565410/Oo46t3DPn.png?auto=compress,format&amp;format=webp" alt="gradio-logo.png" width="256" height="256" loading="lazy"></p>
<p><a target="_blank" href="https://gradio.app/">Gradio is an open-source Python library</a> that you can use to quickly create and customize easy-to-use UI components for your ML model, any API, or any arbitrary function in just a few lines of code.</p>
<p>Gradio makes it very easy for you to build Graphical User Interfaces and deploy machine learning models.</p>
<h1 id="heading-what-is-hugging-face">What is Hugging Face?</h1>
<p><a target="_blank" href="https://huggingface.co/">Hugging Face</a> is a library that provides pre-trained and open-sourced Natural Language Processing models and datasets for machine learning engineers.</p>
<p>It is an open-source Machine Learning community where you can download pre-trained machine learning models and use them in your own projects.</p>
<h1 id="heading-time-to-build-our-project">Time to Build our Project</h1>
<h2 id="heading-prerequisites"><strong>Prerequisites</strong></h2>
<ul>
<li>Have Python installed</li>
<li>Have an IDE / text editor (like <a target="_blank" href="https://code.visualstudio.com/">Visual Studio</a>, <a target="_blank" href="https://www.jetbrains.com/pycharm/">PyCharm</a>, or <a target="_blank" href="https://jupyter.org/">Jupyter Notebook</a> )</li>
<li>Have an internet connection</li>
</ul>
<p><strong>Here is the <a target="_blank" href="https://github.com/EdemGold/sentiment-analysis-app">GitHub Repository</a> for the project</strong>.</p>
<h2 id="heading-install-dependencies"><strong>Install Dependencies</strong></h2>
<p>Here we are going to install the libraries needed to build the Sentiment Analysis app.</p>
<h3 id="heading-how-to-install-transformers">How to install Transformers</h3>
<p>Here we are going to install the transformers library. This library will give us access to the hugging face API.</p>
<pre><code>#In a jupyter notebook
!pip install transformers

#In terminal
pip install transformers
</code></pre><h3 id="heading-how-to-install-pytorch">How to install PyTorch</h3>
<p>We are going to install the PyTorch deep learning library. Visit the <a target="_blank" href="https://pytorch.org/get-started/locally/">PyTorch Website</a> and install your specialized version.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1635887110857/e_LVM9OR0.jpeg?auto=compress,format&amp;format=webp" alt="pytorch-install.jpg" width="1352" height="602" loading="lazy"></p>
<p>Below is my installed version of PyTorch.</p>
<pre><code>#install <span class="hljs-keyword">in</span> jupyter notebook
!pip3 install torch==<span class="hljs-number">1.9</span><span class="hljs-number">.1</span>+cu111 torchvision==<span class="hljs-number">0.10</span><span class="hljs-number">.1</span>+cu111 torchaudio===<span class="hljs-number">0.9</span><span class="hljs-number">.1</span> -f https:<span class="hljs-comment">//download.pytorch.org/whl/torch_stable.html</span>

#Install <span class="hljs-keyword">in</span> Terminal
pip3 install torch==<span class="hljs-number">1.9</span><span class="hljs-number">.1</span>+cu111 torchvision==<span class="hljs-number">0.10</span><span class="hljs-number">.1</span>+cu111 torchaudio===<span class="hljs-number">0.9</span><span class="hljs-number">.1</span> -f https:<span class="hljs-comment">//download.pytorch.org/whl/torch_stable.html</span>
</code></pre><h3 id="heading-import-and-set-up-pipeline">Import and Set up Pipeline</h3>
<p>Here we are going to import and set up our <em>sentiment analysis model</em> using a Hugging Face pipeline.</p>
<p>Hugging Face provides an automatic pipeline that helps handle things like tokenizing, pre-processing, encoding, and decoding for you and lets you focus on core things like model optimization.</p>
<pre><code>#setting up hugging face pipeline
<span class="hljs-keyword">from</span> transformers <span class="hljs-keyword">import</span> pipeline
classifier = pipeline(<span class="hljs-string">"sentiment-analysis"</span>)
</code></pre><p>Above we imported and instantiated the pipeline object, and then we passed the sentiment-analysis models an argument.</p>
<h3 id="heading-how-to-define-the-gradio-function">How to Define the Gradio Function</h3>
<p>We are going to define a Gadio function that will help us provide the sentiment analysis functionality for our web app.</p>
<p>If you read my <a target="_blank" href="https://www.freecodecamp.org/news/build-gui-using-gradio-for-machine-learning-models/">past article</a> on building graphical user interfaces (GUI) for machine learning models using Gradio, you'll know that Gradio allows you to build graphical components for your models and they provide the model's prediction functionality through functions.</p>
<pre><code>#model <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">for</span> <span class="hljs-title">gradio</span>

<span class="hljs-title">def</span> <span class="hljs-title">func</span>(<span class="hljs-params">utterance</span>):
  <span class="hljs-title">return</span> <span class="hljs-title">classifier</span>(<span class="hljs-params">utterance</span>)</span>
</code></pre><p>Above we created a function called <code>func</code> and added utterance (that is, the word to be analyzed by the model for sentiments) as an argument for our function. We then make our function return the sentiment analysis of the utterance earlier passed and this takes us to the next step.</p>
<h3 id="heading-how-to-build-our-gradio-interface">How to Build our Gradio Interface</h3>
<p>Here we are going to create our Gradio web app, add graphical components to it, then we are going to launch the app.</p>
<pre><code>#getting gradio library
<span class="hljs-keyword">import</span> gradio <span class="hljs-keyword">as</span> gr
descriptions = <span class="hljs-string">"This is an AI sentiment analyzer which checks and gets the emotions in a particular utterance. Just put in a sentence and you'll get the probable emotions behind that sentence"</span>

app = gr.Interface(fn=func, inputs=<span class="hljs-string">"text"</span>, outputs=<span class="hljs-string">"text"</span>, title=<span class="hljs-string">"Sentiment Analayser"</span>, description=descriptions)
app.launch()
</code></pre><p>Above we imported the Gradio library, and then we added a description of our project which will be then passed on to our web app.</p>
<p>We then created a Gradio interface instance where we are going to provide details about our web app. We passed the model's function into the <code>fn</code> parameter, we then provided the type of input.</p>
<p>Gradio allows you to create any form of input of your choice be it text, radios, checkboxes, numbers, and so on. But here we are going to use our input as text.</p>
<p>Next, we provided the output format, the same way Gradio allows you to pick your input format (that is text, numbers, checkbox, and so on). It also allows you to pick your output format. </p>
<p>In this case, we are going to use text, too. After passing the output parameter we gave a title to our web app.</p>
<p>Lastly, we launch the app.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1635983823728/v1LcvOBg6.png?auto=compress,format&amp;format=webp" alt="Screenshot (36).png" width="1343" height="605" loading="lazy"></p>
<p>Now you can use your new sentiment analysis tool!</p>
<p>Thank you for reading.</p>
<h2 id="heading-important-resources"><strong>Important resources</strong></h2>
<ul>
<li><a target="_blank" href="https://gradio.app/">Gradio Official Website</a></li>
<li><a target="_blank" href="https://gradio.app/docs">Gradio Documentation</a></li>
<li><a target="_blank" href="https://github.com/gradio-app/gradio">Gradio GitHub Repo</a></li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What is Sentiment Analysis? A Complete Guide for Beginners ]]>
                </title>
                <description>
                    <![CDATA[ Sentiment analysis lets you analyze the sentiment behind a given piece of text. In this article, we will look at how it works along with a few practical applications. What is Sentiment Analysis? Sentiment analysis is a technique through which you can... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/what-is-sentiment-analysis-a-complete-guide-to-for-beginners/</link>
                <guid isPermaLink="false">66d036362b211a17e00e36e5</guid>
                
                    <category>
                        <![CDATA[ Artificial Intelligence ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Sentiment analysis ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Manish Shivanandhan ]]>
                </dc:creator>
                <pubDate>Wed, 30 Sep 2020 13:39:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/09/wall-5.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Sentiment analysis lets you analyze the sentiment behind a given piece of text. In this article, we will look at how it works along with a few practical applications.</p>
<h1 id="heading-what-is-sentiment-analysis">What is Sentiment Analysis?</h1>
<p>Sentiment analysis is a technique through which you can analyze a piece of text to determine the sentiment behind it. It combines machine learning and natural language processing (NLP) to achieve this. </p>
<p>Using basic Sentiment analysis, a program can understand whether the sentiment behind a piece of text is positive, negative, or neutral.</p>
<p>It is a powerful technique in Artificial intelligence that has important business applications. </p>
<p>For example, you can use sentiment analysis to analyze customer feedback. After collecting that feedback through various mediums like Twitter and Facebook, you can run sentiment analysis algorithms on those text snippets to understand your customers' attitude towards your product.</p>
<h1 id="heading-how-sentiment-analysis-works">How Sentiment Analysis Works</h1>
<p>The simplest implementation of sentiment analysis is using a scored word list. </p>
<p>For example, <a target="_blank" href="https://gist.githubusercontent.com/damianesteban/06e8be3225f641100126/raw/a51c27d4e9cc242f829d895e23b4435021ab55e5/afinn-111.txt">AFINN</a> is a list of words scored with numbers between minus five and plus five. You can split a piece of text into individual words and compare them with the word list to come up with the final sentiment score.</p>
<p>Let's say we had the phrase, "I love cats, but I am <strong>allergic</strong> to them".</p>
<p>In the AFINN word list, you can find two words, “love” and “allergic” with their respective scores of +3 and -2. You can ignore the rest of the words (again, this is very basic sentiment analysis). </p>
<p>By combining these two, you get a total score of +1. So you can classify this sentence as mildly positive.</p>
<p>There are complex implementations of sentiment analysis used in the industry today. Those algorithms can provide you with accurate scores for long pieces of text. Besides that, we have reinforcement learning models that keep getting better over time.</p>
<p>For complex models, you can use a combination of NLP and machine learning algorithms. There are three major types of algorithms used in sentiment analysis. Let's take a look at them.</p>
<h2 id="heading-automated-systems">Automated Systems</h2>
<p>Automatic approaches to sentiment analysis rely on machine learning models like clustering. </p>
<p>Long pieces of text are fed into the classifier, and it returns the results as negative, neutral, or positive. Automatic systems are composed of two basic processes, which we'll look at now.</p>
<h2 id="heading-rule-based-systems">Rule-based Systems</h2>
<p>Unlike automated models, rule-based approaches are dependent on custom rules to classify data. Popular techniques include tokenization, parsing, stemming, and a few others. You can consider the example we looked at earlier to be a rule-based approach.</p>
<p>A good thing about rule-based systems is the ability to customize them. These algorithms can be tailor-made based on context by developing smarter rules.</p>
<p>Just keep in mind that you will have to regularly maintain these types of rule-based models to ensure consistent and improved results.</p>
<h2 id="heading-hybrid-systems">Hybrid Systems</h2>
<p>Hybrid techniques are the most modern, efficient, and widely-used approach for sentiment analysis. Well-designed hybrid systems can provide the benefits of both automatic and rule-based systems.</p>
<p>Hybrid models enjoy the power of machine learning along with the flexibility of customization. An example of a hybrid model would be a self-updating wordlist based on <a target="_blank" href="http://jalammar.github.io/illustrated-word2vec/">Word2Vec</a>. You can track these wordlists and update them based on your business needs.</p>
<h1 id="heading-use-cases-for-sentiment-analysis">Use Cases for Sentiment Analysis</h1>
<h3 id="heading-analyzing-customer-feedback">Analyzing Customer Feedback</h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/09/1-6.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Customer feedback analysis is the most widespread application of sentiment analysis. Direct customer feedback is gold for businesses, especially startups. Accurate audience targeting is essential for the success of any type of business.</p>
<p>Well-made sentiment analysis algorithms can capture the core market sentiment towards a product. </p>
<p>You can also extend this use case for smaller sub-sections, like analyzing product reviews on your Amazon store. The more customer-driven a company is, the better sentiment analysis can be of service.</p>
<h3 id="heading-campaign-monitoring">Campaign Monitoring</h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/09/1-5.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Manipulating voter emotions is a reality now, thanks to the <a target="_blank" href="https://en.wikipedia.org/wiki/Facebook%E2%80%93Cambridge_Analytica_data_scandal">Cambridge Analytica Scandal</a>.</p>
<p>Another use-case of sentiment analysis is a measure of influence. Taking the 2016 US Elections as an example, many polls concluded that Donald Trump was going to lose.</p>
<p>But experts had noted that people were generally disappointed with the current system. They backed their claims with strong evidence through sentiment analysis. </p>
<p>I worked on a tool called Sentiments (Duh!) that monitored the US elections during my time as a Software Engineer at my former company. We noticed trends that pointed out that Mr. Trump was gaining strong traction with voters.</p>
<p>This should be evidence that the right data combined with AI can produce accurate results, even when it goes against popular opinion.</p>
<h3 id="heading-brand-monitoring">Brand Monitoring</h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/09/1-4.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Brand monitoring is another great use-case for sentiment analysis. Companies can use sentiment analysis to check the social media sentiments around their brand from their audience.</p>
<p>KFC is a perfect example of a business that uses sentiment analysis to track, build, and enhance its brand. KFC’s social media campaigns are a great contributing factor to its success. They tailor their marketing campaigns to appeal to the young crowd and to be “present” in social media.</p>
<p>Tools like <a target="_blank" href="https://www.brandwatch.com/">Brandwatch</a> can tell you if something negative about your brand is going viral. Other brands that use social media to promote a positive brand sentiment include Amazon, Netflix, and Dominoes.</p>
<h3 id="heading-stock-market-analysis">Stock Market Analysis</h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/09/1-2.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>If you are a trader or an investor, you understand the impact news can have on the stock market. Whenever a major story breaks, it is bound to have a strong positive or negative impact on the stock market.</p>
<p>Sentiment analysis is a powerful tool for traders. You can analyze the market sentiment towards a stock in real-time, usually in a matter of minutes. This can help you plan your long or short positions for a particular stock.</p>
<p>Recently, Moderna announced the completion of phase I of its COVID-19 vaccine clinical trials. This news resulted in a strong rise in the stock price of Moderna. </p>
<p>But today, Moderna’s stock stumbled after losing a patent. Using sentiment analysis, you can analyze these types of news in realtime and use them to influence your trading decisions.</p>
<h3 id="heading-compliance-monitoring">Compliance Monitoring</h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/09/1-1.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Regulatory and legal compliance can make or break large organizations. Often, these compliance documents are stashed into large websites like <a target="_blank" href="https://www.fca.org.uk/">Financial Conduct Authority</a>.</p>
<p>Large organizations spend a good chunk of their budgets on regulatory compliance. In these cases, traditional data analytics cannot offer a complete solution. </p>
<p>Tools like <a target="_blank" href="https://www.scrapinghub.com/">ScrapingHub</a> can help fetch documents from these websites. But companies need intelligent classification to find the right content among millions of web pages.</p>
<p>Sentiment analysis can make compliance monitoring easier and more cost-efficient. It can help build tagging engines, analyze changes over time, and provide a 24/7 watchdog for your organization.</p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>Sentiment analysis is a powerful tool that you can use to solve problems from brand influence to market monitoring. New tools are built around sentiment analysis to help businesses become more efficient.</p>
<p>And by the way, if you love Grammarly, you can go ahead and thank sentiment analysis.</p>
<p><em>Loved this article?</em> <a target="_blank" href="http://tinyletter.com/manishmshiva"><strong><em>Join my Newsletter</em></strong></a> <em>and get a summary of my articles and videos every Monday.</em></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Twitter Sentiment Analysis Tool ]]>
                </title>
                <description>
                    <![CDATA[ By Dirk Hoekstra This weekend I had some time on my hands and decided to build a Twitter sentiment analysis tool. The idea is that you enter a search term and the tool will search recent tweets. It will then use sentiment analysis to determine how po... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-a-twitter-sentiment-analysis-tool/</link>
                <guid isPermaLink="false">66d45e3f73634435aafcef74</guid>
                
                    <category>
                        <![CDATA[ nlp ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Node.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Sentiment analysis ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 04 May 2020 23:52:05 +0000</pubDate>
                <media:content url="https://cdn-media-2.freecodecamp.org/w1280/5f9c9b3f740569d1a4ca2aa8.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Dirk Hoekstra</p>
<p>This weekend I had some time on my hands and decided to build a Twitter sentiment analysis tool.</p>
<p>The idea is that you enter a search term and the tool will search recent tweets. It will then use sentiment analysis to determine how positive or negative Twitter is about the subject.</p>
<p>For example, you could search "Donald Trump" to get Twitter's sentiment on the president.</p>
<p>Let's dive in!</p>
<h2 id="heading-getting-a-twitter-api-key">Getting a Twitter API key</h2>
<p>The very first thing we need to do is create a Twitter application in order to get an API key. </p>
<p>Head over to the <a target="_blank" href="https://developer.twitter.com/en/apps">Twitter apps page</a> to create a new application. You must have a developer account to be able to create an application.</p>
<p>If you don't have a developer account you can apply for one. Most requests are granted instantly. ?</p>
<p>Copy down the <code>API Key</code> and <code>API Key Secret</code> that you find in your Twitter application.</p>
<h2 id="heading-creating-a-nodejs-project">Creating a NodeJS project</h2>
<p>I'm going to use NodeJS to create this application. </p>
<p>To create a new project I run:</p>
<pre><code>npm init
npm install twitter-lite
</code></pre><p>This will create a new NodeJS project and install the <code>twitter-lite</code> package. This package makes interacting with the Twitter API super easy.</p>
<p>To authenticate our requests we are going to use an OAuth2.0 bearer token. The <code>twitter-lite</code> package has an easy way of handling the Twitter authentication.</p>
<p>Let's create a new <code>index.js</code> file and add the following code to it:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> Twitter = <span class="hljs-built_in">require</span>(<span class="hljs-string">'twitter-lite'</span>);

<span class="hljs-keyword">const</span> user = <span class="hljs-keyword">new</span> Twitter({
    <span class="hljs-attr">consumer_key</span>: <span class="hljs-string">"YOUR_API_KEY"</span>,
    <span class="hljs-attr">consumer_secret</span>: <span class="hljs-string">"YOUR_API_SECRET"</span>,
});

<span class="hljs-comment">// Wrap the following code in an async function that is called</span>
<span class="hljs-comment">// immediately so that we can use "await" statements.</span>
(<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">try</span> {
        <span class="hljs-comment">// Retrieve the bearer token from twitter.</span>
        <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> user.getBearerToken();
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Got the following Bearer token from Twitter: <span class="hljs-subst">${response.access_token}</span>`</span>);

        <span class="hljs-comment">// Construct our API client with the bearer token.</span>
        <span class="hljs-keyword">const</span> app = <span class="hljs-keyword">new</span> Twitter({
            <span class="hljs-attr">bearer_token</span>: response.access_token,
        });
    } <span class="hljs-keyword">catch</span>(e) {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"There was an error calling the Twitter API."</span>);
        <span class="hljs-built_in">console</span>.dir(e);
    }
})();
</code></pre>
<p>When running this the console outputs the following:</p>
<pre><code>Got the following Bearer token <span class="hljs-keyword">from</span> Twitter: THE_TWITTER_BEARER_TOKEN
</code></pre><p>Awesome, so far everything works. ?</p>
<h2 id="heading-getting-recent-tweets">Getting recent tweets</h2>
<p>The next part is retrieving recent tweets from the Twitter API.</p>
<p>On the <a target="_blank" href="https://developer.twitter.com/en/docs/tweets/search/api-reference/get-search-tweets">Twitter documentation</a> you can see that there is an endpoint to search for recent tweets. </p>
<p>To implement this I add the following code to the <code>index.js</code> file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> Twitter = <span class="hljs-built_in">require</span>(<span class="hljs-string">'twitter-lite'</span>);

(<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">new</span> Twitter({
        <span class="hljs-attr">consumer_key</span>: <span class="hljs-string">"YOUR_API_KEY"</span>,
        <span class="hljs-attr">consumer_secret</span>: <span class="hljs-string">"YOUR_API_SECRET"</span>,
    });

    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">let</span> response = <span class="hljs-keyword">await</span> user.getBearerToken();
        <span class="hljs-keyword">const</span> app = <span class="hljs-keyword">new</span> Twitter({
            <span class="hljs-attr">bearer_token</span>: response.access_token,
        });

        <span class="hljs-comment">// Search for recent tweets from the twitter API</span>
        response = <span class="hljs-keyword">await</span> app.get(<span class="hljs-string">`/search/tweets`</span>, {
            <span class="hljs-attr">q</span>: <span class="hljs-string">"Lionel Messi"</span>, <span class="hljs-comment">// The search term</span>
            <span class="hljs-attr">lang</span>: <span class="hljs-string">"en"</span>,        <span class="hljs-comment">// Let's only get English tweets</span>
            <span class="hljs-attr">count</span>: <span class="hljs-number">100</span>,        <span class="hljs-comment">// Limit the results to 100 tweets</span>
        });

        <span class="hljs-comment">// Loop over all the tweets and print the text</span>
        <span class="hljs-keyword">for</span> (tweet <span class="hljs-keyword">of</span> response.statuses) {
            <span class="hljs-built_in">console</span>.dir(tweet.text);
        }
    } <span class="hljs-keyword">catch</span>(e) {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"There was an error calling the Twitter API"</span>);
        <span class="hljs-built_in">console</span>.dir(e);
    }
})();
</code></pre>
<p>When running this you can see a lot of twitter comments about Lionel Messi, meaning that it works perfectly! ⚽</p>
<pre><code><span class="hljs-string">"RT @TheFutbolPage: Some of Lionel Messi's best dribbles."</span>

<span class="hljs-string">"RT @MagufuliMugabe: Lionel Messi ? didn't just wake up one day  and become the best player in the world no  HE trained. So if your girl is…"</span>

<span class="hljs-string">""</span>RT @goal: The boy who would be King ? Is Ansu Fati the heir to Lionel Messi<span class="hljs-string">'s throne?"

and many more...</span>
</code></pre><h2 id="heading-performing-sentiment-analysis">Performing sentiment analysis</h2>
<p>To perform the sentiment analysis I'm going to use Google Cloud's Natural Language API. With this API you can get the sentiment score of a text with a simple API call.</p>
<p>First, head over to the <a target="_blank" href="https://console.cloud.google.com/">Google Cloud Console</a> to create a new cloud project.</p>
<p>Next, head over to the <a target="_blank" href="https://console.cloud.google.com/apis/api/language.googleapis.com">Natural Language API</a> and enable it for the project.</p>
<p>Finally, we need to create a service account to authenticate ourselves. Head over to the <a target="_blank" href="https://console.cloud.google.com/apis/credentials/serviceaccountkey">create a service account page</a> to create a service account. </p>
<p>When creating a service account you will need to download the <code>json</code> file containing the private key of that service account. Store this file in the project folder.</p>
<p>Google has a NodeJS package to interact with the Natural Language API so let's use that. To install it run:</p>
<pre><code>npm install @google-cloud/language
</code></pre><p>In order for the language package to work, it needs to know where the private key file is. </p>
<p>The package will attempt to read a <code>GOOGLE_APPLICATION_CREDENTIALS</code> environment variable that should point to this file.</p>
<p>To set this environment variable I update the <code>script</code> key in the <code>package.json</code> file.</p>
<pre><code class="lang-json"><span class="hljs-string">"scripts"</span>: {
  <span class="hljs-attr">"start"</span>: <span class="hljs-string">"GOOGLE_APPLICATION_CREDENTIALS='./gcloud-private-key.json' node index.js"</span>
}
</code></pre>
<p><em>Note that in order for this to work you must start the script by running <code>npm run start</code>.</em></p>
<p>With all that set up we can finally start coding.</p>
<p>I add a new <code>getSentiment</code> function to the <code>index.js</code> file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> language = <span class="hljs-built_in">require</span>(<span class="hljs-string">'@google-cloud/language'</span>);
<span class="hljs-keyword">const</span> languageClient = <span class="hljs-keyword">new</span> language.LanguageServiceClient();

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getSentiment</span>(<span class="hljs-params">text</span>) </span>{
    <span class="hljs-keyword">const</span> <span class="hljs-built_in">document</span> = {
        <span class="hljs-attr">content</span>: text,
        <span class="hljs-attr">type</span>: <span class="hljs-string">'PLAIN_TEXT'</span>,
    };

    <span class="hljs-comment">// Detects the sentiment of the text</span>
    <span class="hljs-keyword">const</span> [result] = <span class="hljs-keyword">await</span> languageClient.analyzeSentiment({<span class="hljs-attr">document</span>: <span class="hljs-built_in">document</span>});
    <span class="hljs-keyword">const</span> sentiment = result.documentSentiment;

    <span class="hljs-keyword">return</span> sentiment.score;
}
</code></pre>
<p>This function calls the Google Natural Language API and returns a sentiment score between -1 and 1.</p>
<p>Let's test it out with a few examples:</p>
<pre><code class="lang-javascript">getSentiment(<span class="hljs-string">"I HATE MESSI"</span>);
</code></pre>
<p>Returns the following.</p>
<pre><code>The sentiment score is <span class="hljs-number">-0.40</span>
</code></pre><p>Similarly:</p>
<pre><code class="lang-javascript">getSentiment(<span class="hljs-string">"I LOVE MESSI"</span>);
</code></pre>
<p>Returns a higher sentiment. ?</p>
<pre><code>The sentiment score is <span class="hljs-number">0.89</span>
</code></pre><h2 id="heading-bringing-it-all-together">Bringing it all together</h2>
<p>The final thing to do is calling the <code>getSetiment</code> function with the text from the tweets.</p>
<p>There is a catch though: only the first 5,000 API requests are free, after that Google will charge you for subsequent API requests. </p>
<p>To minimise the amount of API calls I'm going to combine all the tweets into one single string like so:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> allTweets = <span class="hljs-string">""</span>;
<span class="hljs-keyword">for</span> (tweet <span class="hljs-keyword">of</span> response.statuses) {
    allTweets += tweet.text + <span class="hljs-string">"\n"</span>;
}

<span class="hljs-keyword">const</span> sentimentScore = <span class="hljs-keyword">await</span> getSentimentScore(allTweets);
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">`The sentiment about <span class="hljs-subst">${query}</span> is: <span class="hljs-subst">${sentimentScore}</span>`</span>);
</code></pre>
<p>Now I only have to call the API once instead of 100 times.</p>
<p>The final question is of course: what does Twitter think about Lionel Messi? When running the program it gives the following output:</p>
<pre><code>The sentiment about Lionel Messi is: <span class="hljs-number">0.2</span>
</code></pre><p>So, Twitter is lightly positive about Lionel Messi.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>We've created a NodeJS program that interacts with the Twitter API to get recent tweets. It then sends these tweets to the Google Cloud Natural Language API to perform a sentiment analysis.</p>
<p>You can find a live version of this <a target="_blank" href="https://coffeecoding.dev/twitter-sentiment-analysis">sentiment analysis here</a>.</p>
<p>You can also view the completed code <a target="_blank" href="https://github.com/Dirk94/twitter-sentiment-analysis">here on Github</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ A Deep Dive into Word Embeddings for Sentiment Analysis ]]>
                </title>
                <description>
                    <![CDATA[ By Bert Carremans When applying one-hot encoding to words, we end up with sparse (containing many zeros) vectors of high dimensionality. On large data sets, this could cause performance issues.  Additionally, one-hot encoding does not take into accou... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/word-embeddings-for-sentiment-analysis/</link>
                <guid isPermaLink="false">66d45de6c7632f8bfbf1e411</guid>
                
                    <category>
                        <![CDATA[ keras ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Machine Learning ]]>
                    </category>
                
                    <category>
                        <![CDATA[ nlp ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Sentiment analysis ]]>
                    </category>
                
                    <category>
                        <![CDATA[ text mining ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Sun, 05 Jan 2020 14:27:33 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/01/1_u9pwb9JShvDIU7j1G9iszQ.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Bert Carremans</p>
<p>When applying one-hot encoding to words, we end up with sparse (containing many zeros) vectors of high dimensionality. On large data sets, this could cause performance issues. </p>
<p>Additionally, one-hot encoding does not take into account the semantics of the words. So words like <em>airplane</em> and <em>aircraft</em> are considered to be two different features while we know that they have a very similar meaning. Word embeddings address these two issues.</p>
<p>Word embeddings are dense vectors with much lower dimensionality. Secondly, the semantic relationships between words are reflected in the distance and direction of the vectors.</p>
<p>We will work with the <a target="_blank" href="https://www.kaggle.com/crowdflower/twitter-airline-sentiment">TwitterAirlineSentiment data set on Kaggle</a>. This data set contains roughly 15K tweets with 3 possible classes for the sentiment (positive, negative and neutral). In my previous post, we tried to <a target="_blank" href="https://www.freecodecamp.org/news/sentiment-analysis-with-text-mining/">classify the tweets</a> by tokenizing the words and applying two classifiers. Let’s see if word embeddings can outperform that.</p>
<p>After reading this tutorial you will know how to compute task-specific word embeddings with the Embedding layer of <strong>Keras</strong>. Secondly, we will investigate whether word embeddings trained on a larger corpus can improve the accuracy of our model.</p>
<p>The structure of this tutorial is:</p>
<ul>
<li>Intuition behind word embeddings</li>
<li>Project set-up</li>
<li>Data preparation</li>
<li>Keras and its Embedding layer</li>
<li>Pre-trained word embeddings — GloVe</li>
<li>Training word embeddings with more dimensions</li>
</ul>
<h1 id="heading-intuition-behind-word-embeddings">Intuition behind word embeddings</h1>
<p>Before we can use words in a classifier, we need to convert them into numbers. One way to do that is to simply map words to integers. Another way is to one-hot encode words. Each tweet could then be represented as a vector with a dimension equal to (a limited set of) the words in the corpus. The words occurring in the tweet have a value of 1 in the vector. All other vector values equal zero.</p>
<p>Word embeddings are computed differently. Each word is positioned into a <strong><em>multi-dimensional space</em></strong>. The number of dimensions in this space is chosen by the data scientist. You can experiment with different dimensions and see what provides the best result.</p>
<p>The <strong><em>vector values for a word represent its position</em></strong> in this embedding space. Synonyms are found close to each other while words with opposite meanings have a large distance between them. You can also apply mathematical operations on the vectors which should produce semantically correct results. A typical example is that the sum of the word embeddings of <em>king</em> and <em>female</em> produces the word embedding of <em>queen</em>.</p>
<h1 id="heading-project-set-up">Project set-up</h1>
<p>Let’s start by importing all packages for this project.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> pandas <span class="hljs-keyword">as</span> pd
<span class="hljs-keyword">import</span> numpy <span class="hljs-keyword">as</span> np
<span class="hljs-keyword">import</span> re
<span class="hljs-keyword">import</span> collections
<span class="hljs-keyword">import</span> matplotlib.pyplot <span class="hljs-keyword">as</span> plt
<span class="hljs-keyword">from</span> pathlib <span class="hljs-keyword">import</span> Path
<span class="hljs-keyword">from</span> sklearn.model_selection <span class="hljs-keyword">import</span> train_test_split
<span class="hljs-keyword">from</span> nltk.corpus <span class="hljs-keyword">import</span> stopwords
<span class="hljs-keyword">from</span> keras.preprocessing.text <span class="hljs-keyword">import</span> Tokenizer
<span class="hljs-keyword">from</span> keras.preprocessing.sequence <span class="hljs-keyword">import</span> pad_sequences
<span class="hljs-keyword">from</span> keras.utils.np_utils <span class="hljs-keyword">import</span> to_categorical
<span class="hljs-keyword">from</span> sklearn.preprocessing <span class="hljs-keyword">import</span> LabelEncoder
<span class="hljs-keyword">from</span> keras <span class="hljs-keyword">import</span> models
<span class="hljs-keyword">from</span> keras <span class="hljs-keyword">import</span> layers
</code></pre>
<p>We define some parameters and paths used throughout the project. Most of them are self-explanatory. But others will be explained further in the code.</p>
<pre><code class="lang-python">NB_WORDS = <span class="hljs-number">10000</span>  <span class="hljs-comment"># Parameter indicating the number of words we'll put in the dictionary</span>
VAL_SIZE = <span class="hljs-number">1000</span>  <span class="hljs-comment"># Size of the validation set</span>
NB_START_EPOCHS = <span class="hljs-number">10</span>  <span class="hljs-comment"># Number of epochs we usually start to train with</span>
BATCH_SIZE = <span class="hljs-number">512</span>  <span class="hljs-comment"># Size of the batches used in the mini-batch gradient descent</span>
MAX_LEN = <span class="hljs-number">24</span>  <span class="hljs-comment"># Maximum number of words in a sequence</span>
GLOVE_DIM = <span class="hljs-number">100</span>  <span class="hljs-comment"># Number of dimensions of the GloVe word embeddings</span>
root = Path(<span class="hljs-string">'../'</span>)
input_path = root / <span class="hljs-string">'input/'</span>
ouput_path = root / <span class="hljs-string">'output/'</span>
source_path = root / <span class="hljs-string">'source/'</span>
</code></pre>
<p>Throughout this code, we will also use some helper functions for data preparation, modeling and visualization. These function definitions are not shown here to keep the blog post clutter free. You can always refer to the <a target="_blank" href="https://github.com/bertcarremans/TwitterUSAirlineSentiment/blob/master/source/Using%20Word%20Embeddings%20for%20Sentiment%20Analysis.ipynb">notebook in Github</a> to look at the code.</p>
<h1 id="heading-data-preparation">Data preparation</h1>
<h2 id="heading-reading-the-data-and-cleaning">Reading the data and cleaning</h2>
<p>We read in the CSV file with the tweets and apply a random shuffle on its indexes. After that, we remove stop words and @ mentions. A test set of 10% is split off to evaluate the model on new data.</p>
<pre><code class="lang-python">df = pd.read_csv(input_path / <span class="hljs-string">'Tweets.csv'</span>)
df = df.reindex(np.random.permutation(df.index))
df = df[[<span class="hljs-string">'text'</span>, <span class="hljs-string">'airline_sentiment'</span>]]
df.text = df.text.apply(remove_stopwords).apply(remove_mentions)
X_train, X_test, y_train, y_test = train_test_split(df.text, df.airline_sentiment, test_size=<span class="hljs-number">0.1</span>, random_state=<span class="hljs-number">37</span>)
</code></pre>
<h2 id="heading-convert-words-into-integers">Convert words into integers</h2>
<p>With the <strong><em>Tokenizer</em></strong> from Keras, we convert the tweets into sequences of integers. We limit the number of words to the <strong>_NB<em>WORDS</em></strong> most frequent words. Additionally, the tweets are cleaned with some filters, set to lowercase and split on spaces.</p>
<pre><code class="lang-python">tk = Tokenizer(num_words=NB_WORDS,
filters=<span class="hljs-string">'!"#$%&amp;()*+,-./:;&lt;=&gt;?@[\]^_`{"}~\t\n'</span>,lower=<span class="hljs-literal">True</span>, split=<span class="hljs-string">" "</span>)
tk.fit_on_texts(X_train)
X_train_seq = tk.texts_to_sequences(X_train)
X_test_seq = tk.texts_to_sequences(X_test)
</code></pre>
<h2 id="heading-equal-length-of-sequences">Equal length of sequences</h2>
<p>Each batch needs to provide sequences of equal length. We achieve this with the <strong>_pad<em>sequences</em></strong> method. By specifying <strong><em>maxlen</em></strong>, the sequences or padded with zeros or truncated.</p>
<pre><code class="lang-python">X_train_seq_trunc = pad_sequences(X_train_seq, maxlen=MAX_LEN)
X_test_seq_trunc = pad_sequences(X_test_seq, maxlen=MAX_LEN)
</code></pre>
<h2 id="heading-encoding-the-target-variable">Encoding the target variable</h2>
<p>The target classes are strings which need to be converted into numeric vectors. This is done with the <strong><em>LabelEncoder</em></strong> from Sklearn and the <strong>_to<em>categorical</em></strong> method from Keras.</p>
<pre><code class="lang-python">le = LabelEncoder()
y_train_le = le.fit_transform(y_train)
y_test_le = le.transform(y_test)
y_train_oh = to_categorical(y_train_le)
y_test_oh = to_categorical(y_test_le)
</code></pre>
<h2 id="heading-splitting-off-the-validation-set">Splitting off the validation set</h2>
<p>From the training data, we split off a validation set of 10% to use during training.</p>
<pre><code class="lang-python">X_train_emb, X_valid_emb, y_train_emb, y_valid_emb = train_test_split(X_train_seq_trunc, y_train_oh, test_size=<span class="hljs-number">0.1</span>, random_state=<span class="hljs-number">37</span>)
</code></pre>
<h1 id="heading-modeling">Modeling</h1>
<h2 id="heading-keras-and-the-embedding-layer">Keras and the Embedding layer</h2>
<p>Keras provides a convenient way to convert each word into a multi-dimensional vector. This can be done with the <strong><em>Embedding</em></strong> layer. It will compute the word embeddings (or use pre-trained embeddings) and look up each word in a dictionary to find its vector representation. Here we will train word embeddings with 8 dimensions.</p>
<pre><code class="lang-python">emb_model = models.Sequential()
emb_model.add(layers.Embedding(NB_WORDS, <span class="hljs-number">8</span>, input_length=MAX_LEN))
emb_model.add(layers.Flatten())
emb_model.add(layers.Dense(<span class="hljs-number">3</span>, activation=<span class="hljs-string">'softmax'</span>))
emb_history = deep_model(emb_model, X_train_emb, y_train_emb, X_valid_emb, y_valid_emb)
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/01/0_-XjJ4DTQ5RQ8jZOF.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We have a validation accuracy of about 74%. The number of words in the tweets is rather low, so this result is quite good. By comparing the training and validation loss, we see that the model starts <strong>overfitting</strong> from epoch 6.</p>
<p>In a previous article, I discussed how we can <a target="_blank" href="https://www.freecodecamp.org/news/handling-overfitting-in-deep-learning-models/">avoid overfitting</a>. You might want to read that if you want to deep dive on that topic.</p>
<p>When we train the model on all data (including the validation data, but excluding the test data) and set the number of epochs to 6, we get a test accuracy of 78%. This test result is OK, but let’s see if we can improve with pre-trained word embeddings.</p>
<pre><code class="lang-python">emb_results = test_model(emb_model, X_train_seq_trunc, y_train_oh, X_test_seq_trunc, y_test_oh, <span class="hljs-number">6</span>)
print(<span class="hljs-string">'/n'</span>)
print(<span class="hljs-string">'Test accuracy of word embeddings model: {0:.2f}%'</span>.format(emb_results[<span class="hljs-number">1</span>]*<span class="hljs-number">100</span>))
</code></pre>
<h2 id="heading-pre-trained-word-embeddings-glove">Pre-trained word embeddings — Glove</h2>
<p>Because the training data is not so large, the model might not be able to learn good embeddings for the sentiment analysis. Alternatively, we can load pre-trained word embeddings built on a much larger training data.</p>
<p>The <a target="_blank" href="https://nlp.stanford.edu/projects/glove/">GloVe database</a> contains multiple pre-trained word embeddings, and more specific <strong><em>embeddings trained on tweets</em></strong>. So this might be useful for the task at hand.</p>
<p>First, we put the word embeddings in a dictionary where the keys are the words and the values the word embeddings.</p>
<pre><code class="lang-python">glove_file = <span class="hljs-string">'glove.twitter.27B.'</span> + str(GLOVE_DIM) + <span class="hljs-string">'d.txt'</span>
emb_dict = {}
glove = open(input_path / glove_file)
<span class="hljs-keyword">for</span> line <span class="hljs-keyword">in</span> glove:
    values = line.split()
    word = values[<span class="hljs-number">0</span>]
    vector = np.asarray(values[<span class="hljs-number">1</span>:], dtype=<span class="hljs-string">'float32'</span>)
    emb_dict[word] = vector
glove.close()
</code></pre>
<p>With the GloVe embeddings loaded in a dictionary, we can look up the embedding for each word in the corpus of the airline tweets. These will be stored in a matrix with a shape of <strong>_NB<em>WORDS</em></strong> and <strong>_GLOVE<em>DIM</em></strong>. If a word is not found in the GloVe dictionary, the word embedding values for the word are zero.</p>
<pre><code class="lang-python">emb_matrix = np.zeros((NB_WORDS, GLOVE_DIM))
<span class="hljs-keyword">for</span> w, i <span class="hljs-keyword">in</span> tk.word_index.items():
    <span class="hljs-keyword">if</span> i &lt; NB_WORDS:
        vect = emb_dict.get(w)
        <span class="hljs-keyword">if</span> vect <span class="hljs-keyword">is</span> <span class="hljs-keyword">not</span> <span class="hljs-literal">None</span>:
        emb_matrix[i] = vect
    <span class="hljs-keyword">else</span>:
        <span class="hljs-keyword">break</span>
</code></pre>
<p>Then we specify the model just like we did with the model above.</p>
<pre><code class="lang-python">glove_model = models.Sequential()
glove_model.add(layers.Embedding(NB_WORDS, GLOVE_DIM, input_length=MAX_LEN))
glove_model.add(layers.Flatten())
glove_model.add(layers.Dense(<span class="hljs-number">3</span>, activation=<span class="hljs-string">'softmax'</span>))
</code></pre>
<p>In the Embedding layer (which is layer 0 here) we <strong><em>set the weights</em></strong> for the words to those found in the GloVe word embeddings. By setting <strong><em>trainable</em></strong> to False we make sure that the GloVe word embeddings cannot be changed. After that, we run the model.</p>
<pre><code class="lang-python">glove_model.layers[<span class="hljs-number">0</span>].set_weights([emb_matrix])
glove_model.layers[<span class="hljs-number">0</span>].trainable = <span class="hljs-literal">False</span>
glove_history = deep_model(glove_model, X_train_emb, y_train_emb, X_valid_emb, y_valid_emb)
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/01/0_uhsGcl8UG_JYUycb.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>The model overfits fast after 3 epochs. Furthermore, the validation accuracy is lower compared to the embeddings trained on the training data.</p>
<pre><code class="lang-python">glove_results = test_model(glove_model, X_train_seq_trunc, y_train_oh, X_test_seq_trunc, y_test_oh, <span class="hljs-number">3</span>)
print(<span class="hljs-string">'/n'</span>)
print(<span class="hljs-string">'Test accuracy of word glove model: {0:.2f}%'</span>.format(glove_results[<span class="hljs-number">1</span>]*<span class="hljs-number">100</span>))
</code></pre>
<p>As a final exercise, let’s see what results we get when we train the embeddings with the same number of dimensions as the GloVe data.</p>
<h2 id="heading-training-word-embeddings-with-more-dimensions">Training word embeddings with more dimensions</h2>
<p>We will train the word embeddings with the same number of dimensions as the GloVe embeddings (i.e. GLOVE_DIM).</p>
<pre><code class="lang-python">emb_model2 = models.Sequential()
emb_model2.add(layers.Embedding(NB_WORDS, GLOVE_DIM, input_length=MAX_LEN))
emb_model2.add(layers.Flatten())
emb_model2.add(layers.Dense(<span class="hljs-number">3</span>, activation=<span class="hljs-string">'softmax'</span>))
emb_history2 = deep_model(emb_model2, X_train_emb, y_train_emb, X_valid_emb, y_valid_emb)
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/01/0_boJxTu7msbxWzexm.png" alt="Image" width="600" height="400" loading="lazy"></p>
<pre><code class="lang-python">emb_results2 = test_model(emb_model2, X_train_seq_trunc, y_train_oh, X_test_seq_trunc, y_test_oh, <span class="hljs-number">3</span>)
print(<span class="hljs-string">'/n'</span>)
print(<span class="hljs-string">'Test accuracy of word embedding model 2: {0:.2f}%'</span>.format(emb_results2[<span class="hljs-number">1</span>]*<span class="hljs-number">100</span>))
</code></pre>
<p>On the test data we get good results, but we do not outperform the LogisticRegression with the CountVectorizer. So there is still room for improvement.</p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>The best result is achieved with 100-dimensional word embeddings that are trained on the available data. This even outperforms the use of word embeddings that were trained on a much larger Twitter corpus.</p>
<p>Until now we have just put a Dense layer on the flattened embeddings. By doing this, <strong><em>we do not take into account the relationships between the words</em></strong> in the tweet. This can be achieved with a recurrent neural network or a 1D convolutional network. But that’s something for a future post :)</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Sentiment Analysis with Text Mining ]]>
                </title>
                <description>
                    <![CDATA[ By Bert Carremans In this tutorial, I will explore some text mining techniques for sentiment analysis. We'll look at how to prepare textual data. After that we will try two different classifiers to infer the tweets' sentiment. We will tune the hyperp... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/sentiment-analysis-with-text-mining/</link>
                <guid isPermaLink="false">66d45de18812486a37369c87</guid>
                
                    <category>
                        <![CDATA[ Data Science ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Machine Learning ]]>
                    </category>
                
                    <category>
                        <![CDATA[ nlp ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Sentiment analysis ]]>
                    </category>
                
                    <category>
                        <![CDATA[ text mining ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Thu, 13 Jun 2019 21:42:41 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2019/06/dictionary.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Bert Carremans</p>
<p>In this tutorial, I will explore some text mining techniques for sentiment analysis. We'll look at how to prepare textual data. After that we will try two different classifiers to infer the tweets' sentiment. We will tune the hyperparameters of both classifiers with grid search. Finally, we evaluate the performance on a set of metrics like precision, recall and the F1 score.</p>
<p>For this project, we'll be working with the <a target="_blank" href="https://www.kaggle.com/crowdflower/twitter-airline-sentiment">Twitter US Airline Sentiment data set on Kaggle</a>. It contains the tweet’s text and one variable with three possible sentiment values. Let's start by importing the packages and configuring some settings.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> numpy <span class="hljs-keyword">as</span> np 
<span class="hljs-keyword">import</span> pandas <span class="hljs-keyword">as</span> pd 
pd.set_option(<span class="hljs-string">'display.max_colwidth'</span>, <span class="hljs-number">-1</span>)
<span class="hljs-keyword">from</span> time <span class="hljs-keyword">import</span> time
<span class="hljs-keyword">import</span> re
<span class="hljs-keyword">import</span> string
<span class="hljs-keyword">import</span> os
<span class="hljs-keyword">import</span> emoji
<span class="hljs-keyword">from</span> pprint <span class="hljs-keyword">import</span> pprint
<span class="hljs-keyword">import</span> collections
<span class="hljs-keyword">import</span> matplotlib.pyplot <span class="hljs-keyword">as</span> plt
<span class="hljs-keyword">import</span> seaborn <span class="hljs-keyword">as</span> sns
sns.set(style=<span class="hljs-string">"darkgrid"</span>)
sns.set(font_scale=<span class="hljs-number">1.3</span>)
<span class="hljs-keyword">from</span> sklearn.base <span class="hljs-keyword">import</span> BaseEstimator, TransformerMixin
<span class="hljs-keyword">from</span> sklearn.feature_extraction.text <span class="hljs-keyword">import</span> CountVectorizer
<span class="hljs-keyword">from</span> sklearn.feature_extraction.text <span class="hljs-keyword">import</span> TfidfVectorizer
<span class="hljs-keyword">from</span> sklearn.model_selection <span class="hljs-keyword">import</span> GridSearchCV
<span class="hljs-keyword">from</span> sklearn.model_selection <span class="hljs-keyword">import</span> train_test_split
<span class="hljs-keyword">from</span> sklearn.pipeline <span class="hljs-keyword">import</span> Pipeline, FeatureUnion
<span class="hljs-keyword">from</span> sklearn.metrics <span class="hljs-keyword">import</span> classification_report
<span class="hljs-keyword">from</span> sklearn.naive_bayes <span class="hljs-keyword">import</span> MultinomialNB
<span class="hljs-keyword">from</span> sklearn.linear_model <span class="hljs-keyword">import</span> LogisticRegression
<span class="hljs-keyword">from</span> sklearn.externals <span class="hljs-keyword">import</span> joblib
<span class="hljs-keyword">import</span> gensim
<span class="hljs-keyword">from</span> nltk.corpus <span class="hljs-keyword">import</span> stopwords
<span class="hljs-keyword">from</span> nltk.stem <span class="hljs-keyword">import</span> PorterStemmer
<span class="hljs-keyword">from</span> nltk.tokenize <span class="hljs-keyword">import</span> word_tokenize
<span class="hljs-keyword">import</span> warnings
warnings.filterwarnings(<span class="hljs-string">'ignore'</span>)
np.random.seed(<span class="hljs-number">37</span>)
</code></pre>
<h2 id="heading-loading-the-data">Loading the data</h2>
<p>We read in the comma separated file we downloaded from the Kaggle Datasets. We shuffle the data frame in case the classes are sorted. Applying the <code>reindex</code> method on the <code>permutation</code> of the original indices is good for that. In this notebook, we will work with the <code>text</code> variable and the <code>airline_sentiment</code> variable.</p>
<pre><code class="lang-python">df = pd.read_csv(<span class="hljs-string">'../input/Tweets.csv'</span>)
df = df.reindex(np.random.permutation(df.index))
df = df[[<span class="hljs-string">'text'</span>, <span class="hljs-string">'airline_sentiment'</span>]]
</code></pre>
<h2 id="heading-exploratory-data-analysis">Exploratory Data Analysis</h2>
<h3 id="heading-target-variable">Target variable</h3>
<p>There are three class labels we will predict: negative, neutral or positive.</p>
<p>The class labels are imbalanced as we can see below in the chart. This is something that we should keep in mind during the model training phase. With the <code>factorplot</code> of the seaborn package, we can visualize the distribution of the target variable.</p>
<pre><code class="lang-python">sns.factorplot(x=<span class="hljs-string">"airline_sentiment"</span>, data=df, kind=<span class="hljs-string">"count"</span>, size=<span class="hljs-number">6</span>, aspect=<span class="hljs-number">1.5</span>, palette=<span class="hljs-string">"PuBuGn_d"</span>)
plt.show();
</code></pre>
<p><img src="https://cdn-media-1.freecodecamp.org/images/0*v99Gfk4iL4POvy2F.png" alt="Image" width="646" height="412" loading="lazy">
<em>Imbalanced distribution of the target class labels</em></p>
<h3 id="heading-input-variable">Input variable</h3>
<p>To analyze the <code>text</code> variable we create a class <code>TextCounts</code>. In this class we compute some basic statistics on the text variable.</p>
<ul>
<li><code>count_words</code>: number of words in the tweet</li>
<li><code>count_mentions</code>: referrals to other Twitter accounts start with a @</li>
<li><code>count_hashtags</code>: number of tag words, preceded by a #</li>
<li><code>count_capital_words</code>: number of uppercase words are sometimes used to “shout” and express (negative) emotions</li>
<li><code>count_excl_quest_marks</code>: number of question or exclamation marks</li>
<li><code>count_urls</code>: number of links in the tweet, preceded by http(s)</li>
<li><code>count_emojis</code>: number of emoji, which might be a good sign of the sentiment</li>
</ul>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TextCounts</span>(<span class="hljs-params">BaseEstimator, TransformerMixin</span>):</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">count_regex</span>(<span class="hljs-params">self, pattern, tweet</span>):</span>
        <span class="hljs-keyword">return</span> len(re.findall(pattern, tweet))

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">fit</span>(<span class="hljs-params">self, X, y=None, **fit_params</span>):</span>
        <span class="hljs-comment"># fit method is used when specific operations need to be done on the train data, but not on the test data</span>
        <span class="hljs-keyword">return</span> self

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">transform</span>(<span class="hljs-params">self, X, **transform_params</span>):</span>
        count_words = X.apply(<span class="hljs-keyword">lambda</span> x: self.count_regex(<span class="hljs-string">r'\w+'</span>, x)) 
        count_mentions = X.apply(<span class="hljs-keyword">lambda</span> x: self.count_regex(<span class="hljs-string">r'@\w+'</span>, x))
        count_hashtags = X.apply(<span class="hljs-keyword">lambda</span> x: self.count_regex(<span class="hljs-string">r'#\w+'</span>, x))
        count_capital_words = X.apply(<span class="hljs-keyword">lambda</span> x: self.count_regex(<span class="hljs-string">r'\b[A-Z]{2,}\b'</span>, x))
        count_excl_quest_marks = X.apply(<span class="hljs-keyword">lambda</span> x: self.count_regex(<span class="hljs-string">r'!|\?'</span>, x))
        count_urls = X.apply(<span class="hljs-keyword">lambda</span> x: self.count_regex(<span class="hljs-string">r'http.?://[^\s]+[\s]?'</span>, x))
        <span class="hljs-comment"># We will replace the emoji symbols with a description, which makes using a regex for counting easier</span>
        <span class="hljs-comment"># Moreover, it will result in having more words in the tweet</span>
        count_emojis = X.apply(<span class="hljs-keyword">lambda</span> x: emoji.demojize(x)).apply(<span class="hljs-keyword">lambda</span> x: self.count_regex(<span class="hljs-string">r':[a-z_&amp;]+:'</span>, x))

        df = pd.DataFrame({<span class="hljs-string">'count_words'</span>: count_words
                           , <span class="hljs-string">'count_mentions'</span>: count_mentions
                           , <span class="hljs-string">'count_hashtags'</span>: count_hashtags
                           , <span class="hljs-string">'count_capital_words'</span>: count_capital_words
                           , <span class="hljs-string">'count_excl_quest_marks'</span>: count_excl_quest_marks
                           , <span class="hljs-string">'count_urls'</span>: count_urls
                           , <span class="hljs-string">'count_emojis'</span>: count_emojis
                          })

        <span class="hljs-keyword">return</span> df
tc = TextCounts()
df_eda = tc.fit_transform(df.text)
df_eda[<span class="hljs-string">'airline_sentiment'</span>] = df.airline_sentiment
</code></pre>
<p>It could be interesting to see how the TextStats variables relate to the class variable. So we write a function <code>show_dist</code> that provides descriptive statistics and a plot per target class.</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">show_dist</span>(<span class="hljs-params">df, col</span>):</span>
    print(<span class="hljs-string">'Descriptive stats for {}'</span>.format(col))
    print(<span class="hljs-string">'-'</span>*(len(col)+<span class="hljs-number">22</span>))
    print(df.groupby(<span class="hljs-string">'airline_sentiment'</span>)[col].describe())
    bins = np.arange(df[col].min(), df[col].max() + <span class="hljs-number">1</span>)
    g = sns.FacetGrid(df, col=<span class="hljs-string">'airline_sentiment'</span>, size=<span class="hljs-number">5</span>, hue=<span class="hljs-string">'airline_sentiment'</span>, palette=<span class="hljs-string">"PuBuGn_d"</span>)
    g = g.map(sns.distplot, col, kde=<span class="hljs-literal">False</span>, norm_hist=<span class="hljs-literal">True</span>, bins=bins)
    plt.show()
</code></pre>
<p>Below you can find the distribution of the number of words in a tweet per target class. For brevity, we will limit us to only this variable. The charts for all TextCounts variables are in the <a target="_blank" href="https://github.com/bertcarremans/TwitterUSAirlineSentiment">notebook on Github</a>.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/0*snmvA3GQOb_S9wV8.png" alt="Image" width="1060" height="340" loading="lazy"></p>
<ul>
<li>The number of words used in the tweets is rather low. The largest number of words is 36 and there are even tweets with only 2 words. So we’ll have to be careful during data cleaning not to remove too many words. But the text processing will be faster. Negative tweets contain more words than neutral or positive tweets.</li>
<li>All tweets have at least one mention. This is the result of extracting the tweets based on mentions in the Twitter data. There seems to be no difference in the number of mentions with regard to the sentiment.</li>
<li>Most of the tweets do not contain hash tags. So this variable will not be retained during model training. Again, no difference in the number of hash tags with regard to the sentiment.</li>
<li>Most of the tweets do not contain capitalized words and we do not see a difference in distribution between the sentiments.</li>
<li>The positive tweets seem to be using a bit more exclamation or question marks.</li>
<li>Most tweets do not contain a URL.</li>
<li>Most tweets do not use emojis.</li>
</ul>
<h2 id="heading-text-cleaning">Text Cleaning</h2>
<p>Before we start using the tweets’ text we need to clean it. We’ll do the this in the class <code>CleanText</code><strong>.</strong> With this class we’ll perform the following actions:</p>
<ul>
<li>remove the mentions, as we want to generalize to tweets of other airline companies too.</li>
<li>remove the hash tag sign (#) but not the actual tag as this may contain information</li>
<li>set all words to lowercase</li>
<li>remove all punctuations, including the question and exclamation marks</li>
<li>remove the URLs as they do not contain useful information. We did not notice a difference in the number of URLs used between the sentiment classes</li>
<li>make sure to convert the emojis into one word.</li>
<li>remove digits</li>
<li>remove stopwords</li>
<li>apply the <code>PorterStemmer</code> to keep the stem of the words</li>
</ul>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CleanText</span>(<span class="hljs-params">BaseEstimator, TransformerMixin</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">remove_mentions</span>(<span class="hljs-params">self, input_text</span>):</span>
        <span class="hljs-keyword">return</span> re.sub(<span class="hljs-string">r'@\w+'</span>, <span class="hljs-string">''</span>, input_text)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">remove_urls</span>(<span class="hljs-params">self, input_text</span>):</span>
        <span class="hljs-keyword">return</span> re.sub(<span class="hljs-string">r'http.?://[^\s]+[\s]?'</span>, <span class="hljs-string">''</span>, input_text)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">emoji_oneword</span>(<span class="hljs-params">self, input_text</span>):</span>
        <span class="hljs-comment"># By compressing the underscore, the emoji is kept as one word</span>
        <span class="hljs-keyword">return</span> input_text.replace(<span class="hljs-string">'_'</span>,<span class="hljs-string">''</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">remove_punctuation</span>(<span class="hljs-params">self, input_text</span>):</span>
        <span class="hljs-comment"># Make translation table</span>
        punct = string.punctuation
        trantab = str.maketrans(punct, len(punct)*<span class="hljs-string">' '</span>)  <span class="hljs-comment"># Every punctuation symbol will be replaced by a space</span>
        <span class="hljs-keyword">return</span> input_text.translate(trantab)
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">remove_digits</span>(<span class="hljs-params">self, input_text</span>):</span>
        <span class="hljs-keyword">return</span> re.sub(<span class="hljs-string">'\d+'</span>, <span class="hljs-string">''</span>, input_text)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">to_lower</span>(<span class="hljs-params">self, input_text</span>):</span>
        <span class="hljs-keyword">return</span> input_text.lower()

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">remove_stopwords</span>(<span class="hljs-params">self, input_text</span>):</span>
        stopwords_list = stopwords.words(<span class="hljs-string">'english'</span>)
        <span class="hljs-comment"># Some words which might indicate a certain sentiment are kept via a whitelist</span>
        whitelist = [<span class="hljs-string">"n't"</span>, <span class="hljs-string">"not"</span>, <span class="hljs-string">"no"</span>]
        words = input_text.split() 
        clean_words = [word <span class="hljs-keyword">for</span> word <span class="hljs-keyword">in</span> words <span class="hljs-keyword">if</span> (word <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> stopwords_list <span class="hljs-keyword">or</span> word <span class="hljs-keyword">in</span> whitelist) <span class="hljs-keyword">and</span> len(word) &gt; <span class="hljs-number">1</span>] 
        <span class="hljs-keyword">return</span> <span class="hljs-string">" "</span>.join(clean_words) 

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">stemming</span>(<span class="hljs-params">self, input_text</span>):</span>
        porter = PorterStemmer()
        words = input_text.split() 
        stemmed_words = [porter.stem(word) <span class="hljs-keyword">for</span> word <span class="hljs-keyword">in</span> words]
        <span class="hljs-keyword">return</span> <span class="hljs-string">" "</span>.join(stemmed_words)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">fit</span>(<span class="hljs-params">self, X, y=None, **fit_params</span>):</span>
        <span class="hljs-keyword">return</span> self

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">transform</span>(<span class="hljs-params">self, X, **transform_params</span>):</span>
        clean_X = X.apply(self.remove_mentions).apply(self.remove_urls).apply(self.emoji_oneword).apply(self.remove_punctuation).apply(self.remove_digits).apply(self.to_lower).apply(self.remove_stopwords).apply(self.stemming)
        <span class="hljs-keyword">return</span> clean_X
</code></pre>
<p>To show how the cleaned text variable will look like, here’s a sample.</p>
<pre><code class="lang-python">ct = CleanText()
sr_clean = ct.fit_transform(df.text)
sr_clean.sample(<span class="hljs-number">5</span>)
</code></pre>
<blockquote>
<p><em>glad rt bet bird wish flown south winter</em><br><em>point upc code check baggag tell luggag vacat day tri swimsuit</em><br><em>vx jfk la dirti plane not standard</em><br><em>tell mean work need estim time arriv pleas need laptop work thank</em><br><em>sure busi go els airlin travel name kathryn sotelo</em></p>
</blockquote>
<p>One side-effect of text cleaning is that some rows do not have any words left in their text. For the <code>CountVectorizer</code> and <code>TfIdfVectorizer</code> this does not pose a problem. Yet, for the <code>Word2Vec</code> algorithm this causes an error. There are different strategies to deal with these missing values.</p>
<ul>
<li>Remove the complete row, but in a production environment this is not desirable.</li>
<li>Impute the missing value with some placeholder text like <em>[no_text]</em></li>
<li>When applying Word2Vec: use the average of all vectors</li>
</ul>
<p>Here we will impute with placeholder text.</p>
<pre><code class="lang-python">empty_clean = sr_clean == <span class="hljs-string">''</span>
print(<span class="hljs-string">'{} records have no words left after text cleaning'</span>.format(sr_clean[empty_clean].count()))
sr_clean.loc[empty_clean] = <span class="hljs-string">'[no_text]'</span>
</code></pre>
<p>Now that we have the cleaned text of the tweets, we can have a look at what are the most frequent words. Below we’ll show the top 20 words. The most frequent word is “flight”.</p>
<pre><code class="lang-python">cv = CountVectorizer()
bow = cv.fit_transform(sr_clean)
word_freq = dict(zip(cv.get_feature_names(), np.asarray(bow.sum(axis=<span class="hljs-number">0</span>)).ravel()))
word_counter = collections.Counter(word_freq)
word_counter_df = pd.DataFrame(word_counter.most_common(<span class="hljs-number">20</span>), columns = [<span class="hljs-string">'word'</span>, <span class="hljs-string">'freq'</span>])
fig, ax = plt.subplots(figsize=(<span class="hljs-number">12</span>, <span class="hljs-number">10</span>))
sns.barplot(x=<span class="hljs-string">"word"</span>, y=<span class="hljs-string">"freq"</span>, data=word_counter_df, palette=<span class="hljs-string">"PuBuGn_d"</span>, ax=ax)
plt.show();
</code></pre>
<p><img src="https://cdn-media-1.freecodecamp.org/images/0*hBvkYfey1Astmd02.png" alt="Image" width="738" height="595" loading="lazy"></p>
<h2 id="heading-creating-test-data">Creating test data</h2>
<p>To check the performance of the models we’ll need a test set. Evaluating on the train data would not be correct. You should not test on the same data used for training the model.</p>
<p>First, we combine the <code>TextCounts</code> variables with the <code>CleanText</code> variable. Initially, I made the mistake to execute TextCounts and CleanText in the <code>GridSearchCV</code>. This took too long as it applies these functions each run of the GridSearch. It suffices to run them only once.</p>
<pre><code class="lang-python">df_model = df_eda
df_model[<span class="hljs-string">'clean_text'</span>] = sr_clean
df_model.columns.tolist()
</code></pre>
<p>So <code>df_model</code> now contains several variables. But our vectorizers (see below) will only need the <code>clean_text</code> variable. The <code>TextCounts</code>variables can be added as such. To select columns, I wrote the class <code>ColumnExtractor</code> below.</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ColumnExtractor</span>(<span class="hljs-params">TransformerMixin, BaseEstimator</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, cols</span>):</span>
        self.cols = cols
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">transform</span>(<span class="hljs-params">self, X, **transform_params</span>):</span>
        <span class="hljs-keyword">return</span> X[self.cols]
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">fit</span>(<span class="hljs-params">self, X, y=None, **fit_params</span>):</span>
        <span class="hljs-keyword">return</span> self
X_train, X_test, y_train, y_test = train_test_split(df_model.drop(<span class="hljs-string">'airline_sentiment'</span>, axis=<span class="hljs-number">1</span>), df_model.airline_sentiment, test_size=<span class="hljs-number">0.1</span>, random_state=<span class="hljs-number">37</span>)
</code></pre>
<h2 id="heading-hyperparameter-tuning-and-cross-validation">Hyperparameter tuning and cross-validation</h2>
<p>As we will see below, the vectorizers and classifiers all have configurable parameters. To choose the best parameters, we need to test on a separate validation set. This validation set was not used during the training. Yet, using only one validation set may not produce reliable validation results. Due to chance, you might have a good model performance on the validation set. If you would split the data otherwise, you might end up with other results. To get a more accurate estimation, we perform cross-validation.</p>
<p>With cross-validation we split the data into a train and validation set many times. The evaluation metric is then averaged over the different folds. Luckily, GridSearchCV applies cross-validation out-of-the-box.</p>
<p>To find the best parameters for both a vectorizer and classifier, we create a <code>Pipeline</code>.</p>
<h2 id="heading-evaluation-metrics">Evaluation metrics</h2>
<p>By default GridSearchCV uses the default scorer to compute the <code>best_score_</code>. For both the <code>MultiNomialNb</code> and <code>LogisticRegression</code> this default scoring metric is accuracy.</p>
<p>In our function <code>grid_vect</code>we additionally generate the <code>classification_report</code> on the test data. This provides some interesting metrics per target class. This might be more appropriate here. These metrics are the precision, recall and F1 score<strong>.</strong></p>
<ul>
<li>Precision<strong>:</strong> Of all rows we predicted to be a certain class, how many did we correctly predict?</li>
<li>Recall<strong>:</strong> Of all rows of a certain class, how many did we correctly predict?</li>
<li>F1 score<strong>:</strong> Harmonic mean of Precision and Recall.</li>
</ul>
<p>With the elements of the <a target="_blank" href="https://en.wikipedia.org/wiki/Confusion_matrix">confusion matrix</a> we can calculate Precision and Recall.</p>
<pre><code class="lang-python"><span class="hljs-comment"># Based on http://scikit-learn.org/stable/auto_examples/model_selection/grid_search_text_feature_extraction.html</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">grid_vect</span>(<span class="hljs-params">clf, parameters_clf, X_train, X_test, parameters_text=None, vect=None, is_w2v=False</span>):</span>

    textcountscols = [<span class="hljs-string">'count_capital_words'</span>,<span class="hljs-string">'count_emojis'</span>,<span class="hljs-string">'count_excl_quest_marks'</span>,<span class="hljs-string">'count_hashtags'</span>
                      ,<span class="hljs-string">'count_mentions'</span>,<span class="hljs-string">'count_urls'</span>,<span class="hljs-string">'count_words'</span>]

    <span class="hljs-keyword">if</span> is_w2v:
        w2vcols = []
        <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(SIZE):
            w2vcols.append(i)
        features = FeatureUnion([(<span class="hljs-string">'textcounts'</span>, ColumnExtractor(cols=textcountscols))
                                 , (<span class="hljs-string">'w2v'</span>, ColumnExtractor(cols=w2vcols))]
                                , n_jobs=<span class="hljs-number">-1</span>)
    <span class="hljs-keyword">else</span>:
        features = FeatureUnion([(<span class="hljs-string">'textcounts'</span>, ColumnExtractor(cols=textcountscols))
                                 , (<span class="hljs-string">'pipe'</span>, Pipeline([(<span class="hljs-string">'cleantext'</span>, ColumnExtractor(cols=<span class="hljs-string">'clean_text'</span>)), (<span class="hljs-string">'vect'</span>, vect)]))]
                                , n_jobs=<span class="hljs-number">-1</span>)

    pipeline = Pipeline([
        (<span class="hljs-string">'features'</span>, features)
        , (<span class="hljs-string">'clf'</span>, clf)
    ])

    <span class="hljs-comment"># Join the parameters dictionaries together</span>
    parameters = dict()
    <span class="hljs-keyword">if</span> parameters_text:
        parameters.update(parameters_text)
    parameters.update(parameters_clf)
    <span class="hljs-comment"># Make sure you have scikit-learn version 0.19 or higher to use multiple scoring metrics</span>
    grid_search = GridSearchCV(pipeline, parameters, n_jobs=<span class="hljs-number">-1</span>, verbose=<span class="hljs-number">1</span>, cv=<span class="hljs-number">5</span>)

    print(<span class="hljs-string">"Performing grid search..."</span>)
    print(<span class="hljs-string">"pipeline:"</span>, [name <span class="hljs-keyword">for</span> name, _ <span class="hljs-keyword">in</span> pipeline.steps])
    print(<span class="hljs-string">"parameters:"</span>)
    pprint(parameters)
    t0 = time()
    grid_search.fit(X_train, y_train)
    print(<span class="hljs-string">"done in %0.3fs"</span> % (time() - t0))
    print()
    print(<span class="hljs-string">"Best CV score: %0.3f"</span> % grid_search.best_score_)
    print(<span class="hljs-string">"Best parameters set:"</span>)
    best_parameters = grid_search.best_estimator_.get_params()
    <span class="hljs-keyword">for</span> param_name <span class="hljs-keyword">in</span> sorted(parameters.keys()):
        print(<span class="hljs-string">"\t%s: %r"</span> % (param_name, best_parameters[param_name]))

    print(<span class="hljs-string">"Test score with best_estimator_: %0.3f"</span> % grid_search.best_estimator_.score(X_test, y_test))
    print(<span class="hljs-string">"\n"</span>)
    print(<span class="hljs-string">"Classification Report Test Data"</span>)
    print(classification_report(y_test, grid_search.best_estimator_.predict(X_test)))

    <span class="hljs-keyword">return</span> grid_search
</code></pre>
<h2 id="heading-parameter-grids-for-gridsearchcv">Parameter grids for GridSearchCV</h2>
<p>In the grid search, we will investigate the performance of the classifier. The set of parameters used to test the performance are specified below.</p>
<pre><code class="lang-python"><span class="hljs-comment"># Parameter grid settings for the vectorizers (Count and TFIDF)</span>
parameters_vect = {
    <span class="hljs-string">'features__pipe__vect__max_df'</span>: (<span class="hljs-number">0.25</span>, <span class="hljs-number">0.5</span>, <span class="hljs-number">0.75</span>),
    <span class="hljs-string">'features__pipe__vect__ngram_range'</span>: ((<span class="hljs-number">1</span>, <span class="hljs-number">1</span>), (<span class="hljs-number">1</span>, <span class="hljs-number">2</span>)),
    <span class="hljs-string">'features__pipe__vect__min_df'</span>: (<span class="hljs-number">1</span>,<span class="hljs-number">2</span>)
}

<span class="hljs-comment"># Parameter grid settings for MultinomialNB</span>
parameters_mnb = {
    <span class="hljs-string">'clf__alpha'</span>: (<span class="hljs-number">0.25</span>, <span class="hljs-number">0.5</span>, <span class="hljs-number">0.75</span>)
}

<span class="hljs-comment"># Parameter grid settings for LogisticRegression</span>
parameters_logreg = {
    <span class="hljs-string">'clf__C'</span>: (<span class="hljs-number">0.25</span>, <span class="hljs-number">0.5</span>, <span class="hljs-number">1.0</span>),
    <span class="hljs-string">'clf__penalty'</span>: (<span class="hljs-string">'l1'</span>, <span class="hljs-string">'l2'</span>)
}
</code></pre>
<h2 id="heading-classifiers">Classifiers</h2>
<p>Here we will compare the performance of a <code>MultinomialNB</code>and <code>LogisticRegression</code>.</p>
<pre><code class="lang-python">mnb = MultinomialNB()
logreg = LogisticRegression()
</code></pre>
<h3 id="heading-countvectorizer">CountVectorizer</h3>
<p>To use words in a classifier, we need to convert the words to numbers. Sklearn’s <code>CountVectorizer</code> takes all words in all tweets, assigns an ID and counts the frequency of the word per tweet. We then use this bag of words as input for a classifier. This bag of words is a sparse data set. This means that each record will have many zeroes for the words not occurring in the tweet.</p>
<pre><code class="lang-python">countvect = CountVectorizer()
<span class="hljs-comment"># MultinomialNB</span>
best_mnb_countvect = grid_vect(mnb, parameters_mnb, X_train, X_test, parameters_text=parameters_vect, vect=countvect)
joblib.dump(best_mnb_countvect, <span class="hljs-string">'../output/best_mnb_countvect.pkl'</span>)
<span class="hljs-comment"># LogisticRegression</span>
best_logreg_countvect = grid_vect(logreg, parameters_logreg, X_train, X_test, parameters_text=parameters_vect, vect=countvect)
joblib.dump(best_logreg_countvect, <span class="hljs-string">'../output/best_logreg_countvect.pkl'</span>)
</code></pre>
<h3 id="heading-tf-idf-vectorizer">TF-IDF Vectorizer</h3>
<p>One issue with CountVectorizer is that there might be words that occur frequently. These words might not have discriminatory information. Thus they can be removed. <a target="_blank" href="https://en.wikipedia.org/wiki/Tf%E2%80%93idf">TF-IDF (term frequency — inverse document frequency)</a>can be used to down-weight these frequent words.</p>
<pre><code class="lang-python">tfidfvect = TfidfVectorizer()
<span class="hljs-comment"># MultinomialNB</span>
best_mnb_tfidf = grid_vect(mnb, parameters_mnb, X_train, X_test, parameters_text=parameters_vect, vect=tfidfvect)
joblib.dump(best_mnb_tfidf, <span class="hljs-string">'../output/best_mnb_tfidf.pkl'</span>)
<span class="hljs-comment"># LogisticRegression</span>
best_logreg_tfidf = grid_vect(logreg, parameters_mnb, X_train, X_test, parameters_text=parameters_vect, vect=tfidfvect)
joblib.dump(best_logreg_tfidf, <span class="hljs-string">'../output/best_logreg_tfidf.pkl'</span>)
</code></pre>
<h3 id="heading-word2vec">Word2Vec</h3>
<p>Another way of converting the words to numerical values is to use <code>Word2Vec</code>. Word2Vec maps each word in a multi-dimensional space. It does this by taking into account the context in which a word appears in the tweets. As a result, words that are similar are also close to each other in the multi-dimensional space.</p>
<p>The Word2Vec algorithm is part of the <a target="_blank" href="https://radimrehurek.com/gensim/models/word2vec.html">gensim</a> package.</p>
<p>The Word2Vec algorithm uses lists of words as input. For that purpose, we use the <code>word_tokenize</code> method of the the <code>nltk</code> package.</p>
<pre><code class="lang-python">SIZE = <span class="hljs-number">50</span>
X_train[<span class="hljs-string">'clean_text_wordlist'</span>] = X_train.clean_text.apply(<span class="hljs-keyword">lambda</span> x : word_tokenize(x))
X_test[<span class="hljs-string">'clean_text_wordlist'</span>] = X_test.clean_text.apply(<span class="hljs-keyword">lambda</span> x : word_tokenize(x))
model = gensim.models.Word2Vec(X_train.clean_text_wordlist
, min_count=<span class="hljs-number">1</span>
, size=SIZE
, window=<span class="hljs-number">5</span>
, workers=<span class="hljs-number">4</span>)
model.most_similar(<span class="hljs-string">'plane'</span>, topn=<span class="hljs-number">3</span>)
</code></pre>
<p>The Word2Vec model provides a vocabulary of the words in all the tweets. For each word you also have its vector values. The number of vector values is equal to the chosen size. These are the dimensions on which each word is mapped in the multi-dimensional space. Words with an occurrence less than <code>min_count</code> are not kept in the vocabulary.</p>
<p>A side effect of the min_count parameter is that some tweets could have no vector values. This is would be the case when the word(s) in the tweet occur in less than min_count tweets. Due to the small corpus of tweets, there is a risk of this happening in our case. Thus we set the min_count value equal to 1.</p>
<p>The tweets can have a different number of vectors, depending on the number of words it contains. To use this output for modeling we will calculate the average of all vectors per tweet. As such we will have the same number (i.e. size) of input variables per tweet.</p>
<p>We do this with the function <code>compute_avg_w2v_vector</code>. In this function we also check whether the words in the tweet occur in the vocabulary of the Word2Vec model. If not, a list filled with 0.0 is returned. Else the average of the word vectors.</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">compute_avg_w2v_vector</span>(<span class="hljs-params">w2v_dict, tweet</span>):</span>
    list_of_word_vectors = [w2v_dict[w] <span class="hljs-keyword">for</span> w <span class="hljs-keyword">in</span> tweet <span class="hljs-keyword">if</span> w <span class="hljs-keyword">in</span> w2v_dict.vocab.keys()]

    <span class="hljs-keyword">if</span> len(list_of_word_vectors) == <span class="hljs-number">0</span>:
        result = [<span class="hljs-number">0.0</span>]*SIZE
    <span class="hljs-keyword">else</span>:
        result = np.sum(list_of_word_vectors, axis=<span class="hljs-number">0</span>) / len(list_of_word_vectors)

    <span class="hljs-keyword">return</span> result
X_train_w2v = X_train[<span class="hljs-string">'clean_text_wordlist'</span>].apply(<span class="hljs-keyword">lambda</span> x: compute_avg_w2v_vector(model.wv, x))
X_test_w2v = X_test[<span class="hljs-string">'clean_text_wordlist'</span>].apply(<span class="hljs-keyword">lambda</span> x: compute_avg_w2v_vector(model.wv, x))
</code></pre>
<p>This gives us a Series with a vector of dimension equal to <code>SIZE</code>. Now we will split this vector and create a DataFrame with each vector value in a separate column. That way we can concatenate the Word2Vec variables to the other TextCounts variables. We need to reuse the index of <code>X_train</code> and <code>X_test</code>. Otherwise this will give issues (duplicates) in the concatenation later on.</p>
<pre><code class="lang-python">X_train_w2v = pd.DataFrame(X_train_w2v.values.tolist(), index= X_train.index)
X_test_w2v = pd.DataFrame(X_test_w2v.values.tolist(), index= X_test.index)
<span class="hljs-comment"># Concatenate with the TextCounts variables</span>
X_train_w2v = pd.concat([X_train_w2v, X_train.drop([<span class="hljs-string">'clean_text'</span>, <span class="hljs-string">'clean_text_wordlist'</span>], axis=<span class="hljs-number">1</span>)], axis=<span class="hljs-number">1</span>)
X_test_w2v = pd.concat([X_test_w2v, X_test.drop([<span class="hljs-string">'clean_text'</span>, <span class="hljs-string">'clean_text_wordlist'</span>], axis=<span class="hljs-number">1</span>)], axis=<span class="hljs-number">1</span>)
</code></pre>
<p>We only consider LogisticRegression as we have negative values in the Word2Vec vectors. MultinomialNB assumes that the variables have a <a target="_blank" href="https://en.wikipedia.org/wiki/Multinomial_distribution">multinomial distribution</a>. So they cannot contain negative values.</p>
<pre><code class="lang-python">best_logreg_w2v = grid_vect(logreg, parameters_logreg, X_train_w2v, X_test_w2v, is_w2v=<span class="hljs-literal">True</span>)
joblib.dump(best_logreg_w2v, <span class="hljs-string">'../output/best_logreg_w2v.pkl'</span>)
</code></pre>
<h2 id="heading-conclusion">Conclusion</h2>
<ul>
<li>Both classifiers achieve the best results when using the features of the CountVectorizer</li>
<li>Logistic Regression outperforms the Multinomial Naive Bayes classifier</li>
<li>The best performance on the test set comes from the LogisticRegression with features from CountVectorizer.</li>
</ul>
<h3 id="heading-best-parameters">Best parameters</h3>
<ul>
<li>C value of 1</li>
<li>L2 regularization</li>
<li>max_df: 0.5 or maximum document frequency of 50%.</li>
<li>min_df: 1 or the words need to appear in at least 2 tweets</li>
<li>ngram_range: (1, 2), both single words as bi-grams are used</li>
</ul>
<h3 id="heading-evaluation-metrics-1">Evaluation metrics</h3>
<ul>
<li>A test accuracy of 81,3%. This is better than a baseline performance of predicting the majority class (here a negative sentiment) for all observations. The baseline would give 63% accuracy.</li>
<li>The Precision is rather high for all three classes. For instance, of all cases that we predict as negative, 80% is negative.</li>
<li>The Recall for the neutral class is low. Of all neutral cases in our test data, we only predict 48% as being neutral.</li>
</ul>
<h2 id="heading-apply-the-best-model-on-new-tweets">Apply the best model on new tweets</h2>
<p>For the fun, we will use the best model and apply it to some new tweets that contain <em>@VirginAmerica</em>. I selected 3 negative and 3 positive tweets by hand.</p>
<p>Thanks to the GridSearchCV, we now know what are the best hyperparameters. So now we can train the best model on all training data, including the test data that we split off before.</p>
<pre><code class="lang-python">textcountscols = [<span class="hljs-string">'count_capital_words'</span>,<span class="hljs-string">'count_emojis'</span>,<span class="hljs-string">'count_excl_quest_marks'</span>,<span class="hljs-string">'count_hashtags'</span>
,<span class="hljs-string">'count_mentions'</span>,<span class="hljs-string">'count_urls'</span>,<span class="hljs-string">'count_words'</span>]
features = FeatureUnion([(<span class="hljs-string">'textcounts'</span>, ColumnExtractor(cols=textcountscols))
, (<span class="hljs-string">'pipe'</span>, Pipeline([(<span class="hljs-string">'cleantext'</span>, ColumnExtractor(cols=<span class="hljs-string">'clean_text'</span>))
, (<span class="hljs-string">'vect'</span>, CountVectorizer(max_df=<span class="hljs-number">0.5</span>, min_df=<span class="hljs-number">1</span>, ngram_range=(<span class="hljs-number">1</span>,<span class="hljs-number">2</span>)))]))]
, n_jobs=<span class="hljs-number">-1</span>)
pipeline = Pipeline([
(<span class="hljs-string">'features'</span>, features)
, (<span class="hljs-string">'clf'</span>, LogisticRegression(C=<span class="hljs-number">1.0</span>, penalty=<span class="hljs-string">'l2'</span>))
])
best_model = pipeline.fit(df_model.drop(<span class="hljs-string">'airline_sentiment'</span>, axis=<span class="hljs-number">1</span>), df_model.airline_sentiment)
<span class="hljs-comment"># Applying on new positive tweets</span>
new_positive_tweets = pd.Series([<span class="hljs-string">"Thank you @VirginAmerica for you amazing customer support team on Tuesday 11/28 at @EWRairport and returning my lost bag in less than 24h! #efficiencyiskey #virginamerica"</span>
,<span class="hljs-string">"Love flying with you guys ask these years. Sad that this will be the last trip ? @VirginAmerica #LuxuryTravel"</span>
,<span class="hljs-string">"Wow @VirginAmerica main cabin select is the way to fly!! This plane is nice and clean &amp; I have tons of legroom! Wahoo! NYC bound! ✈️"</span>])
df_counts_pos = tc.transform(new_positive_tweets)
df_clean_pos = ct.transform(new_positive_tweets)
df_model_pos = df_counts_pos
df_model_pos[<span class="hljs-string">'clean_text'</span>] = df_clean_pos
best_model.predict(df_model_pos).tolist()
<span class="hljs-comment"># Applying on new negative tweets</span>
new_negative_tweets = pd.Series([<span class="hljs-string">"@VirginAmerica shocked my initially with the service, but then went on to shock me further with no response to what my complaint was. #unacceptable @Delta @richardbranson"</span>
,<span class="hljs-string">"@VirginAmerica this morning I was forced to repack a suitcase w a medical device because it was barely overweight - wasn't even given an option to pay extra. My spouses suitcase then burst at the seam with the added device and had to be taped shut. Awful experience so far!"</span>
,<span class="hljs-string">"Board airplane home. Computer issue. Get off plane, traverse airport to gate on opp side. Get on new plane hour later. Plane too heavy. 8 volunteers get off plane. Ohhh the adventure of travel ✈️ @VirginAmerica"</span>])
df_counts_neg = tc.transform(new_negative_tweets)
df_clean_neg = ct.transform(new_negative_tweets)
df_model_neg = df_counts_neg
df_model_neg[<span class="hljs-string">'clean_text'</span>] = df_clean_neg
best_model.predict(df_model_neg).tolist()
</code></pre>
<p>The model classifies all tweets correctly. A larger test set should be used to assess the model’s performance. But on this small data set it does what we are aiming for. I hope you enjoyed reading this story. If you did, feel free to share it.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to build a Twitter sentiment analyzer in Python using TextBlob ]]>
                </title>
                <description>
                    <![CDATA[ By Arun Mathew Kurian This blog is based on the video Twitter Sentiment Analysis — Learn Python for Data Science #2 by Siraj Raval. In this challenge, we will be building a sentiment analyzer that checks whether tweets about a subject are negative or... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-a-twitter-sentiments-analyzer-in-python-using-textblob-948e1e8aae14/</link>
                <guid isPermaLink="false">66c350014f1fc448a367904c</guid>
                
                    <category>
                        <![CDATA[ data analysis ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Data Science ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Sentiment analysis ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Wed, 24 Oct 2018 16:00:47 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*keGUEiFDKqcpXVGnfK1Xdg.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Arun Mathew Kurian</p>
<p>This blog is based on the video <a target="_blank" href="https://www.youtube.com/watch?v=T5pRlIbr6gg&amp;list=PL2-dafEMk2A6QKz1mrk1uIGfHkC1zZ6UU">Twitter Sentiment Analysis — Learn Python for Data Science #2</a> by Siraj Raval. In this challenge, we will be building a sentiment analyzer that checks whether tweets about a subject are negative or positive. We will be making use of the Python library textblob for this.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/tP3mRr3cKmn9tJ8tua6Rp2ffqIrJk0e9FwMM" alt="Image" width="800" height="531" loading="lazy">
<em>image from google</em></p>
<p>Sentiment Analysis, also called opinion mining or emotion AI, is the process of determining whether a piece of writing is positive, negative, or neutral. A common use case for this technology is to discover how people feel about a particular topic. Sentiment analysis is widely applied to reviews and social media for a variety of applications.</p>
<p>Sentiment analysis can be performed in many different ways. Many brands and marketers use keyword-based tools that classify data (i.e. social, news, review, blog, etc.) as positive/negative/neutral.</p>
<p>Automated sentiment tagging is usually achieved through word lists. For example, mentions of ‘hate’ would be tagged negatively.</p>
<p>There can be two approaches to sentiment analysis.</p>
<ol>
<li>Lexicon-based methods  </li>
<li>Machine Learning-based methods.</li>
</ol>
<p>In this problem, we will be using a Lexicon-based method.</p>
<p>Lexicon based methods define a list of positive and negative words, with a valence — (eg ‘nice’: +2, ‘good’: +1, ‘terrible’: -1.5 etc). The algorithm looks up a text to find all known words. It then combines their individual results by summing or averaging. Some extensions can check some grammatical rules, like negation or sentiment modifier (like the word “but”, which weights sentiment values in text differently, to emphasize the end of text).</p>
<p>Let’s build the analyzer now.</p>
<h4 id="heading-twitter-api">Twitter API</h4>
<p>Before we start coding, we need to register for the Twitter API <a target="_blank" href="https://apps.twitter.com/">https://apps.twitter.com/</a>. Here we need to register an app to generate various keys associated with our API. The Twitter API can be used to perform many actions like create and search.</p>
<p>Now after creating the app we can start coding.</p>
<p>We need to install two packages:</p>
<blockquote>
<p>pip install tweepy</p>
</blockquote>
<p>This package will be used for handling the Twitter API.</p>
<blockquote>
<p>pip install textblob</p>
</blockquote>
<p>This package will be used for the sentiment analysis.</p>
<p><strong>sentiment_analyzer.py</strong></p>
<pre><code><span class="hljs-keyword">import</span> tweepyfrom textblob <span class="hljs-keyword">import</span> TextBlob
</code></pre><p>We need to declare the variables to store the various keys associated with the Twitter API.</p>
<pre><code>consumer_key = ‘[consumer_key]’
</code></pre><pre><code>consumer_key_secret = ‘[consumer_key_secret]’
</code></pre><pre><code>access_token = ‘[access_token]’
</code></pre><pre><code>access_token_secret = ‘[access_token_secret]’
</code></pre><p>The next step is to create a connection with the Twitter API using <strong>tweepy</strong> with these tokens.</p>
<h4 id="heading-tweepy"><strong>Tweepy</strong></h4>
<p>Tweepy supports OAuth authentication. Authentication is handled by the <strong>tweepy.OAuthHandler</strong> class.</p>
<p>An <strong>OAuthHandler</strong> instance must be created by passing a consumer token and secret.</p>
<p>On this auth instance, we will call a function set_access_token by passing the access_token and access_token_secret.</p>
<p>Finally, we create our tweepy API instance by passing this auth instance into the API function of tweepy.</p>
<pre><code>auth = tweepy.OAuthHandler(consumer_key, consumer_key_secret)
</code></pre><pre><code>auth.set_access_token(access_token, access_token_secret)
</code></pre><pre><code>api = tweepy.API(auth)
</code></pre><p>We can now search Twitter for any topic using the search method of the API.</p>
<pre><code>public_tweets = api.search(‘Dogs’)
</code></pre><p>Now we will be getting all the tweets related to the topic ‘Dogs’. We can perform sentiment analysis using the library textblob.</p>
<h4 id="heading-textblob">TextBlob</h4>
<p><em>TextBlob</em> is a Python (2 and 3) library for processing textual data. It provides a simple API for diving into common natural language processing (NLP) tasks such as part-of-speech tagging, noun phrase extraction, sentiment analysis, classification, translation, and more.</p>
<p>A textblob can be created in the following way (example, and not part of the original code):</p>
<pre><code>example = TextBlob(<span class="hljs-string">"Python is a high-level, general-purpose programming language."</span>)
</code></pre><p>And <strong>tokenization</strong> can be performed by the following methods:</p>
<p><strong>words</strong>: returns the words of text</p>
<p>usage:</p>
<pre><code>example.words
</code></pre><p><strong>sentences:</strong> returns the sentences of text</p>
<p>usage:</p>
<pre><code>example.sentences
</code></pre><h4 id="heading-part-of-speech-tagging"><strong>Part-of-speech Tagging</strong></h4>
<p>Part-of-speech tags can be accessed through the <strong>tags</strong> property.</p>
<pre><code>wiki.tags[(<span class="hljs-string">'Python'</span>, <span class="hljs-string">'NNP'</span>), (<span class="hljs-string">'is'</span>, <span class="hljs-string">'VBZ'</span>), (<span class="hljs-string">'a'</span>, <span class="hljs-string">'DT'</span>), (<span class="hljs-string">'high-level'</span>, <span class="hljs-string">'JJ'</span>), (<span class="hljs-string">'general-purpose'</span>, <span class="hljs-string">'JJ'</span>), (<span class="hljs-string">'programming'</span>, <span class="hljs-string">'NN'</span>), (<span class="hljs-string">'language'</span>, <span class="hljs-string">'NN'</span>)]
</code></pre><h4 id="heading-sentiment-analysis"><strong>Sentiment Analysis</strong></h4>
<p>The sentiment property returns a named tuple of the form Sentiment (polarity, subjectivity). The polarity score is a float within the range [-1.0, 1.0]. The subjectivity is a float within the range [0.0, 1.0] where 0.0 is very objective and 1.0 is very subjective.</p>
<p>Now back to the code.</p>
<p>We can iterate the <strong>publice_tweets</strong> array, and check the sentiment of the text of each tweet based on the polarity.</p>
<pre><code><span class="hljs-keyword">for</span> tweet <span class="hljs-keyword">in</span> public_tweets:    print(tweet.text)    analysis = TextBlob(tweet.text)    print(analysis.sentiment)    <span class="hljs-keyword">if</span> analysis.sentiment[<span class="hljs-number">0</span>]&gt;<span class="hljs-number">0</span>:       print <span class="hljs-string">'Positive'</span>    elif analysis.sentiment[<span class="hljs-number">0</span>]&lt;<span class="hljs-number">0</span>:       print <span class="hljs-string">'Negative'</span>    <span class="hljs-keyword">else</span>:       print <span class="hljs-string">'Neutral'</span>
</code></pre><p>Now we run the code using the following:</p>
<blockquote>
<p>python sentiment_analyzer.py</p>
</blockquote>
<p>and we get the output:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/PE7et-Tuo1r2fw06stPrG2Dq4KgWlFA0pHaA" alt="Image" width="800" height="500" loading="lazy"></p>
<p>We can see that the sentiment of the tweet is displayed.</p>
<p>This is an example of how sentiment analysis can be done on data from social media like Twitter. I hope you find it useful!</p>
<p>Find the code at <a target="_blank" href="https://github.com/amkurian/twitter_sentiment_challenge">https://github.com/amkurian/twitter_sentiment_challenge</a></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Sentiment Analysis Using Laravel and the Google Natural Language API ]]>
                </title>
                <description>
                    <![CDATA[ By Darren Chowles Write your own sentiment checker in 5 minutes. Sentiment Analysis is the process of determining whether a piece of text is positive, negative, or neutral. Real world applications for Sentiment Analysis The goal of this article is t... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/sentiment-analysis-using-laravel-and-the-google-natural-language-api-acb70871698a/</link>
                <guid isPermaLink="false">66c35e7ce9895571912a0d0e</guid>
                
                    <category>
                        <![CDATA[ Laravel ]]>
                    </category>
                
                    <category>
                        <![CDATA[ nlp ]]>
                    </category>
                
                    <category>
                        <![CDATA[ PHP ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Sentiment analysis ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Wed, 13 Jun 2018 11:02:55 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*TdiVdPnYkvgl3qWnLGgOcg.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Darren Chowles</p>
<h4 id="heading-write-your-own-sentiment-checker-in-5-minutes">Write your own sentiment checker in 5 minutes.</h4>
<p><img src="https://cdn-media-1.freecodecamp.org/images/W-RZSezYMfrCrFNASW1qeHGAc8tHm8epzb9F" alt="Image" width="800" height="459" loading="lazy"></p>
<p>Sentiment Analysis is the process of determining whether a piece of text is positive, negative, or neutral.</p>
<h3 id="heading-real-world-applications-for-sentiment-analysis">Real world applications for Sentiment Analysis</h3>
<p>The goal of this article is to get you up and running using the Google Natural Language API with Laravel. You’ll be using this API to perform sentiment analysis on text.</p>
<p>Using these techniques, you can build some great functionality into existing applications. Some ideas include:</p>
<ul>
<li>detecting sentiment in comments or reviews</li>
<li>forecasting market movements based on social media activity</li>
<li>ascertaining the effectiveness of a marketing campaign by observing sentiment before and after</li>
</ul>
<h3 id="heading-interpreting-sentiment-analysis-values">Interpreting Sentiment Analysis values</h3>
<p>The Google API takes the provided text, analyzes it, and determines the prevailing emotional opinion. It determines whether the writing is positive, negative, or neutral.</p>
<p>The sentiment is represented by numerical <strong>score</strong> and <strong>magnitude</strong> values.</p>
<ul>
<li>The <strong>score</strong> ranges between -1.0 (negative) and 1.0 (positive).</li>
<li>The <strong>magnitude</strong> indicates the strength of emotion (both positive and negative). The range spans from 0.0 to infinity. The <strong>magnitude</strong> is not normalized, so longer passages of text will always have a larger <strong>magnitude</strong>.</li>
</ul>
<p><img src="https://cdn-media-1.freecodecamp.org/images/okN8PYIoQbHRpiBvsV2A1QCDW3rlkUJMyk6H" alt="Image" width="590" height="225" loading="lazy">
<em>The values above are guides only, and you’ll need to adjust according to your specific environment.</em></p>
<h3 id="heading-google-cloud-platform-setup">Google Cloud Platform setup</h3>
<p>The first step involves creating a new project in the Google Cloud Platform console.</p>
<p>Head over to the dashboard and <a target="_blank" href="https://console.cloud.google.com/projectcreate">create a new project</a>.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/z6371dAtV-MSOkaUJgZaEJvCvlB5pykD3OUq" alt="Image" width="482" height="225" loading="lazy"></p>
<p>Once your project is created, keep the <strong>Project ID</strong> handy.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/ssGnt0a3bKIaNyCRIwJcbaSD7iaAuKrMUSGP" alt="Image" width="479" height="272" loading="lazy"></p>
<ul>
<li>Once you have your project, go to the <a target="_blank" href="https://console.cloud.google.com/apis/credentials/serviceaccountkey">Create service account key</a> page.</li>
<li>Ensure your Sample project is selected at the top.</li>
<li>Under <strong>Service account</strong>, select <strong>New service account</strong>.</li>
<li>Enter a name in the <strong>Service account name</strong> field.</li>
<li>Under <strong>Role</strong>, select <strong>Project</strong> &amp;g<strong>t; Ow</strong>ner.</li>
<li>Finally, click <strong>Create</strong> to have the JSON credentials file downloaded automatically.</li>
</ul>
<p><img src="https://cdn-media-1.freecodecamp.org/images/IbX4pzWkQIl9XCtFFizscV2S4zRXvQCohCRP" alt="Image" width="506" height="494" loading="lazy"></p>
<p>You may also need to enable the Cloud Natural Language API via the <a target="_blank" href="https://console.developers.google.com/apis/library/language.googleapis.com">API Library</a> section.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/ZSc4dpY-9xCA4MM7q7WrYcQV-mFqndbkFEiA" alt="Image" width="711" height="354" loading="lazy"></p>
<h3 id="heading-laravel-project-setup">Laravel project setup</h3>
<p>The next step involves setting up a new Laravel project. If you already have an existing Laravel project, you can skip this step.</p>
<p>I’m using Laravel 5.5 LTS for this article. In the command line, run the following Composer command to create a new project (you can also use the <a target="_blank" href="https://laravel.com/docs/5.5#installing-laravel">Laravel installer</a>):</p>
<pre><code>composer create-project --prefer-dist laravel/laravel sample <span class="hljs-string">"5.5.*"</span>
</code></pre><p>If you used Composer, rename the <strong>.env.example</strong> file to <strong>.env</strong> and run the following command afterwards to set the application key:</p>
<pre><code>php artisan key:generate
</code></pre><h3 id="heading-add-the-google-cloud-language-package">Add the Google “cloud-language” package</h3>
<p>Run the following command to add the Google Cloud Natural Language package to your project:</p>
<pre><code>composer <span class="hljs-built_in">require</span> google/cloud-language
</code></pre><p>You may go ahead and place the downloaded JSON credentials file in your application root (NOT in your public directory). Feel free to rename it. Never commit this file to your code repo — the same goes for any sensitive settings. One option is to add it to the server manually after initial deployment.</p>
<h3 id="heading-the-main-event-adding-the-actual-code-to-your-project">The main event: adding the actual code to your project</h3>
<p>I’ll be adding the following route to my <strong>routes/web.php</strong> file:</p>
<pre><code>&lt;?php
</code></pre><pre><code>Route::get(<span class="hljs-string">'/'</span>, <span class="hljs-string">'SampleController@sentiment'</span>);
</code></pre><p>I’ve created a simple controller to house the code. I’ll be adding all the code within the controller. In a production application, I strongly suggest using separate service classes for any business logic. This way controllers are lean and stick to their original intention: controlling the input/output.</p>
<p>We’ll start with a simple controller, adding a <code>use</code> statement to include the Google Cloud <code>ServiceBuilder</code> class:</p>
<pre><code>&lt;?php
</code></pre><pre><code>namespace App\Http\Controllers;
</code></pre><pre><code>use Google\Cloud\Core\ServiceBuilder;
</code></pre><pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SampleController</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Controller</span></span>{    public <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sentiment</span>(<span class="hljs-params"></span>)    </span>{        <span class="hljs-comment">// Code will be added here    }}</span>
</code></pre><p>The first thing we’ll do is create an instance of the <code>ServiceBuilder</code> class so we can specify our Project ID and JSON credentials.</p>
<pre><code>$cloud = <span class="hljs-keyword">new</span> ServiceBuilder([    <span class="hljs-string">'keyFilePath'</span> =&gt; base_path(<span class="hljs-string">'gc.json'</span>),    <span class="hljs-string">'projectId'</span> =&gt; <span class="hljs-string">'sample-207012'</span>]);
</code></pre><p>You specify the location of the JSON file using the <code>keyFilePath</code> option. I’ve used the Laravel <a target="_blank" href="https://laravel.com/docs/5.5/helpers#method-base-path">base_path()</a> helper to refer to the fully qualified app root path.</p>
<p>The next option is the <code>projectId</code>. This is the value you grabbed when you created the project in the GCP console.</p>
<p>Next, we’ll create an instance of the <code>LanguageClient</code> class. The <code>ServiceBuilder</code> class makes it easy by exposing various factory methods which grant access to services in the API.</p>
<pre><code>$language = $cloud-&gt;language();
</code></pre><p>Now that we have an instance of the class, we can start making use of the Natural Language API. We’ll declare a variable with some text, analyze the sentiment, and output the results:</p>
<pre><code><span class="hljs-comment">// The text to analyse$text = 'I hate this - why did they not make provisions?';</span>
</code></pre><pre><code><span class="hljs-comment">// Detect the sentiment of the text$annotation = $language-&gt;analyzeSentiment($text);$sentiment = $annotation-&gt;sentiment();</span>
</code></pre><pre><code>echo <span class="hljs-string">'Sentiment Score: '</span> . $sentiment[<span class="hljs-string">'score'</span>] . <span class="hljs-string">', Magnitude: '</span> . $sentiment[<span class="hljs-string">'magnitude'</span>];
</code></pre><p>And that’s all there is to it!</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/savaV9K6VqBmJIvC8kMz97tdvMFa4NpX7jRs" alt="Image" width="262" height="92" loading="lazy">
<em>Output for the code above.</em></p>
<p>Here is the final controller class code:</p>
<pre><code>&lt;?php
</code></pre><pre><code>namespace App\Http\Controllers;
</code></pre><pre><code>use Google\Cloud\Core\ServiceBuilder;
</code></pre><pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SampleController</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Controller</span></span>{    public <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sentiment</span>(<span class="hljs-params"></span>)    </span>{        $cloud = <span class="hljs-keyword">new</span> ServiceBuilder([            <span class="hljs-string">'keyFilePath'</span> =&gt; base_path(<span class="hljs-string">'gc.json'</span>),            <span class="hljs-string">'projectId'</span> =&gt; <span class="hljs-string">'sample-207012'</span>        ]);
</code></pre><pre><code>        $language = $cloud-&gt;language();
</code></pre><pre><code>        <span class="hljs-comment">// The text to analyse        $text = 'I hate this - why did they not make provisions?';</span>
</code></pre><pre><code>        <span class="hljs-comment">// Detect the sentiment of the text        $annotation = $language-&gt;analyzeSentiment($text);        $sentiment = $annotation-&gt;sentiment();</span>
</code></pre><pre><code>        echo <span class="hljs-string">'Sentiment Score: '</span> . $sentiment[<span class="hljs-string">'score'</span>] . <span class="hljs-string">', Magnitude: '</span> . $sentiment[<span class="hljs-string">'magnitude'</span>];    }}
</code></pre><h3 id="heading-conclusion">Conclusion</h3>
<p>We’ve only scratched the surface of what the Google Natural Language API has to offer. Once you’ve come to grips with this, I suggest checking out the following additional services available in this API:</p>
<ul>
<li><strong>Entity Analysis</strong>: analyze entities like landmarks and public figures.</li>
<li><strong>Content Classification</strong>: analyze text and return a list of categories that apply to the content.</li>
</ul>
<p>If you have any questions — please feel free to make contact!</p>
<p><em>Originally published at <a target="_blank" href="https://www.chowles.com/sentiment-analysis-using-laravel-and-google-natural-language-api/">www.chowles.com</a> on June 13, 2018.</em></p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
