<?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" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Venkat Chadalavada on Medium]]></title>
        <description><![CDATA[Stories by Venkat Chadalavada on Medium]]></description>
        <link>https://medium.com/@venkat.chadalavada?source=rss-9ec97de55fb7------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*o4NTNhcn2x67SX40eAXTvQ@2x.jpeg</url>
            <title>Stories by Venkat Chadalavada on Medium</title>
            <link>https://medium.com/@venkat.chadalavada?source=rss-9ec97de55fb7------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 15 Nov 2026 09:13:23 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@venkat.chadalavada/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[Lyrics generator using LSTM]]></title>
            <link>https://medium.com/@venkat.chadalavada/lyrics-generator-using-lstm-e174bfc6c2f?source=rss-9ec97de55fb7------2</link>
            <guid isPermaLink="false">https://medium.com/p/e174bfc6c2f</guid>
            <category><![CDATA[lstm]]></category>
            <category><![CDATA[neural-networks]]></category>
            <category><![CDATA[data-science]]></category>
            <category><![CDATA[nlp]]></category>
            <category><![CDATA[machine-learning]]></category>
            <dc:creator><![CDATA[Venkat Chadalavada]]></dc:creator>
            <pubDate>Sat, 29 Feb 2020 12:17:06 GMT</pubDate>
            <atom:updated>2020-02-29T12:17:06.181Z</atom:updated>
            <content:encoded><![CDATA[<p>Introduction</p><ol><li>Motivation</li></ol><p>Natural language processing is among the most attractive and difficult field in machine learning. Different from computer vision and other machine learning tasks, NLP does not convey meaning through any physical manifestation. By the virtue of deep learning, NLP achieved tremendous progress in keyword search, machine translation, semantic analysis and etc. In this project, I would like to make a lyrics generator by using both character level and word level RNN(recurrent neural network).</p><p>The dataset is from kaggle with 3.8 million song lyrics from various artist.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*73MDUFfuaGZf3NEI1mkM2A.jpeg" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*KWgAFrMVL38KeUod8HgCEw.jpeg" /></figure><p>But I will only use lyrics from Eminem and Michael Jackson. Because they have around 400 songs, it is easier to extract regular patterns from them.</p><h3>2. Exploratory data analysis</h3><p>Unlike other machine learning tasks, there is not much visualization we can do with NLP. And data cleaning will be based on the model that we want to explore. For character-based model, it is necessay to keep punctuations as they are part of the characters. However, for word-based model, punctuations are supposed to be removed. To briefly explore the dataset, we will count most frequently used words for different artists (bag of words or unigram). Consequently, very crude sentiment score can be obtained from it.</p><h4>Bag-of-words</h4><p>Remove stop words and punctuations from lyrics</p><pre>from sklearn.feature_extraction.text import CountVectorizer</pre><pre>vectorizer = CountVectorizer(stop_words=&#39;english&#39;)<br>X = vectorizer.fit_transform([eminem_lyrics])</pre><p>Sentiment score base on bag-of-words</p><pre>from nltk.sentiment.vader import SentimentIntensityAnalyzer</pre><pre>def sentiment(eminem_lyrics):<br>    sentiment = SentimentIntensityAnalyzer()<br>    score = sentiment.polarity_scores(eminem_lyrics)<br>    return score</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/720/1*SlH6L4TzhpNbhUhm8T5iLw.jpeg" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/720/1*i6jMeXay6nYdlmT40SgUGw.jpeg" /><figcaption>Eminem sentiment score: -1.0 Michael Jackson sentiment score: 1.0</figcaption></figure><p>Based on bag of words, one can do naïve Bayes to predict the genre of songs, but we will not cover it here. Let us go deeper to deep learning.</p><h3>Character-level recurrent neural network(RNN)</h3><p>Why recurrent? Different from vanilla neural network, RNN (see below, pic from wikipedia) is able to process sequences of inputs (such as words and sentences) by utilizing the internel state (memory state). Hence, it is regarded as a very promising candidate to solve NLP tasks.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*G_9CU58TkrRwNwX3.png" /></figure><p>Inspired by the <a href="https://gist.github.com/karpathy/d4dee566867f8291f086">minimal character-level Vanilla RNN model</a> from Andrej Karpathy, we decided to build a more complicated RNN model to generate lyrics. Below is the summary of my model: 2 LSTM layers and 1 dense layer.</p><pre>Layer (type)                 Output Shape              Param #   <br>=================================================================<br>lstm_1 (LSTM)                (None, 10, 200)           230400    <br>_________________________________________________________________<br>dropout_1 (Dropout)          (None, 10, 200)           0         <br>_________________________________________________________________<br>lstm_2 (LSTM)                (None, 200)               320800    <br>_________________________________________________________________<br>dropout_2 (Dropout)          (None, 200)               0         <br>_________________________________________________________________<br>dense_1 (Dense)              (None, 87)                17487     <br>=================================================================<br>Total params: 568,687<br>Trainable params: 568,687<br>Non-trainable params: 0<br>_________________________________________________________________</pre><p>After 600 epochs, the model achieved 64% accuracy for validation set.</p><pre>Epoch 600/600 - loss: 0.7529 - acc: 0.7858 - val_loss: 1.6630 - val_acc: 0.6402</pre><h3>1. How to prepare the data and train the model?</h3><ul><li>One-hot encode all characters ( a-z, 0-9 and punctuations !&quot;#$%&amp;()*+,-./:;&lt;=&gt;?@[\\]^_`{|}~\t\n )</li></ul><pre>from keras.utils import to_categorical #[1,2,3] -&gt; [[1,0,0], [0,1,0], [0,0,1]] one-hot_X = to_categorical(X, num_classes=vocab_size)</pre><ul><li>Make a sliding window that collects 10 characters as input. Model only generates one character.</li></ul><pre>input: &#39;hello, world&#39; -&gt; output: &#39;n&#39;, true output: &#39;p&#39;</pre><ul><li>Calculate cross entropy and backpropagate the neural network to update 568,687 parameters.</li><li>Slide the window to the right by one character. Extract new input and iterate above process until cost function reaches the minimum.</li></ul><h3>2. How to generate lyrics? Teacher forcing</h3><ul><li>Make seed lyrics. Feed it to the neural network to generate one character after the seed lyrics, ‘b’.</li><li>input: &#39;I want to &#39; -&gt; output &#39;b&#39;</li><li>Append new character to the seed lyrics and remove the very first character.</li><li>new input : &#39; want to b&#39;</li><li>Feed the new seed lyrics into the neural network and iterate the above process as many as you want.</li><li>&#39;I want to &#39; -&gt; &#39; want to b&#39; -&gt; &#39;want to be&#39; -&gt; .... -&gt; &#39;ing of pop&#39;</li><li>In the end, you might get something like ‘I want to be king of pop’</li></ul><p>This process is known as teacher forcing: training neural network that uses model output from a prior time step as an input.</p><p>3. Eminem’s lyrics generator</p><p>After one epoch, generated lyrics:</p><pre>input: &#39;not afraid&#39;    output: &#39;the me the me the me the me the me the me the me the me the&#39;</pre><p>Not smart, it repeats the same words over and over.</p><p>After 600 epochs, generated lyrics:</p><pre>20 characters<br>input: &#39;slim shady&#39;    output: &#39;(what you was a mom&#39;</pre><pre>40 characters<br>input: &quot;i&#39;m rap go&quot;    output: &quot;ing, you should see her, she won&#39;t even&quot;</pre><pre>60 characters<br>input: &#39;the way i&#39;    output: &quot;lounding off, they can try to take your heart and I don&#39;t kn&quot;</pre><pre>80 characters<br>input: &#39;lose myself&#39;    output: &#39; in the music, the moment You own it, you better never let it go You only get o&#39;</pre><pre>100 characters<br>input: &#39;not afraid&#39; output: &#39;) To take a stand) Maybe a dontte the back of the way that I know what the fuck I say to the motherf&#39;</pre><p>It is amazing as the generator can spell the word correctly and it is not hard to tell that they have eminem style.</p><h3>Word-level RNN</h3><h3>1. Word embedding and word2vec</h3><p>Instead of letting the model learning how to spell words. One can upgrade the model from character-level to word-level. Correspondingly, this endows model the ability to learning semantics from the corpus. Since the number of unique words is much larger than that of characters, it is necessay to introduce a new representation: word embedding. This is basically the only difference from character-based model. However, there is much more wisdom than just dimension reduction. The notion was first referred by <a href="https://arxiv.org/pdf/1310.4546.pdf">Misolov, et al.,2013</a>. Word embedding rotates word vector from one-hot representation to word2vec representation.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*5eA7uQG2lJ-no46cQBEKIw.png" /><figcaption>word2vec</figcaption></figure><pre>_________________________________________________________________<br>Layer (type)                 Output Shape              Param #<br>=================================================================<br>embedding_1 (Embedding)      (None, 10, 100)           600500<br>_________________________________________________________________<br>lstm_1 (LSTM)                (None, 10, 300)           481200<br>_________________________________________________________________<br>dropout_1 (Dropout)          (None, 10, 300)           0<br>_________________________________________________________________<br>lstm_2 (LSTM)                (None, 300)               721200<br>_________________________________________________________________<br>dropout_2 (Dropout)          (None, 300)               0<br>_________________________________________________________________<br>dense_1 (Dense)              (None, 300)               90300<br>_________________________________________________________________<br>dense_2 (Dense)              (None, 6005)              1807505<br>=================================================================<br>Total params: 3,700,705<br>Trainable params: 3,700,705<br>Non-trainable params: 0<br>_________________________________________________________________</pre><p>Training is much harder than character-base model. Only 32% accuracy is obtained from this model.</p><pre>Epoch 300/300 - loss: 2.1268 - acc: 0.7121 - val_loss: 8.1230 - val_acc: 0.3291</pre><h3>2. Michael Jackson&#39;s lyrics generator based on word-level RNN</h3><p>After 300 epochs:</p><ul><li>Generate 20-word: here to change the world hee were afraid that away when we change my hand verse ill can never change my heart in pieces lost my heart on the carousel to</li><li>Generate 40-word: a circus girl who left my heart in pieces lost my heart on the carousel to a circus girl who left my heart in pieces lost my heart on the carousel to a circus girl who left my heart in just a little bit baby thats all i need thats all</li><li>Generate 60-word: night need you dont understand you need what about hard let me change you comes your truth out and to guess down together together then be her day every thing out the carpet were gonna see this one understand by much then ever so to see you there are long so game if let me get away verse verse cant gonna tell you right just show your face in broad daylight</li><li>Generate 80-word: im create your crescendo how they dance well theres a reason what its a door when here all never door brother its yes we yeah yeah when you start to say if you truth its whole past and they start that can do tell me girl ive wont you have it tell me no little when the door now im cries chorus bridge cause its door made your game chorus ive never stop up and tell me no true oh her dreams left behind everything for the movie scene nothing more</li><li>Generate 100-word: little start i go a i am away im dreams of this life girl girl tell me fall im together so much i feel you all i say that you say into into i lost my heart i can and you game on me baby ill see i can be far away today i love you from your truth cause youre across the bitch baby does it feel it needs me from a door start that not here there was ghost of moon aint a you better he made the you she win your dreams off the madness i never</li></ul><p>It generates something with correct grammar at some parts but it is hard to understand the meaning.</p><h3>3. How to improve word-level model?</h3><h4>a. Using pretrained word embedding</h4><p>Word-level RNN is essentially concatenation of two neural networks. If we train two parts separately, we should achieve better accuracy. However, after using a <a href="https://nlp.stanford.edu/projects/glove/">pretrained word embedding</a>, the accuracy of validation set decreases to 20%. Such a counterintuitive result!</p><pre>Epoch 50/50 - loss: 4.7769 - acc: 0.3353 - val_loss: 6.1902 - val_acc: 0.2160</pre><pre>from keras.layers import Embedding<br>model = Sequential()<br>model.add(Embedding(num_of_tokens, latent_dim, input_length=seq_length, weights=[pretrained_embedding], train = False))</pre><pre>_________________________________________________________________<br>Layer (type)                 Output Shape              Param #<br>=================================================================<br>embedding_1 (Embedding)      (None, 10, 100)           600500<br>_________________________________________________________________<br>lstm_1 (LSTM)                (None, 10, 250)           351000<br>_________________________________________________________________<br>dropout_1 (Dropout)          (None, 10, 250)           0<br>_________________________________________________________________<br>lstm_2 (LSTM)                (None, 250)               501000<br>_________________________________________________________________<br>dropout_2 (Dropout)          (None, 250)               0<br>_________________________________________________________________<br>dense_1 (Dense)              (None, 6005)              1507255<br>=================================================================<br>Total params: 2,959,755<br>Trainable params: 2,359,255<br>Non-trainable params: 600,500<br>_________________________________________________________________</pre><p>There are 600,500 non-trainable parameters which are from pretrained word embedding. Using non-trainable embedding seems not working well. Maybe it would be better to train the word embedding particularlly for the dataset by using CBOW or skip-gram.</p><h4>b. Word-level Seq2Seq model</h4><p>Seq2Seq model was widely used in <a href="https://papers.nips.cc/paper/5346-sequence-to-sequence-learning-with-neural-networks.pdf">neural tranlation machine</a>. But there is nothing wrong to apply it to lyrics generator. The basic idea is to process input in the encoder end and generate a memory state (a vector) that represents the whole input message. Decoder take the memory state and SOS token to generate one token. Generated token becomes the next input for decoder to predict the next token. The process iterates many cycles until EOS is generated or max length of output is reached. Accordingly, unlike many-to-one model, seq2seq model has advantage of generating more than one token.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*7YoXEgBWDsiGdcyJ.png" /></figure><p>However, the performance does not change by much. But from recently research, inplementing <a href="https://papers.nips.cc/paper/7181-attention-is-all-you-need.pdf">attention mechanism</a> could significantly improve the performance. Attention mechanism not only resolves long-term dependency problem of vanilla Seq2Seq languange model but also speeds up training process as it dicarded RNN which disfavors parallel computation.</p><h3>Concluding remarks</h3><p>Takeaways for tuning hyperparameters:</p><pre>1. It is easy to overfit the model. It is necessay to add Dropout layer after each LSTM layer.<br>2. Sometimes GRU is better than LSTM and computationally cheaper.<br>3. Initialization and luck are very important. Try to restart kernel if model is stuck at local minimum.<br>4. Try [importance sampling](https://arxiv.org/pdf/1803.00942.pdf) which randomly takes samples from distrution instead of feeding datapoints in order</pre><ul><li>Character-based models perform better than word-base. Even though word embedding is a very innovative method in NLP, word vectors by itself hardly convey semantics efficiently.</li><li>Future work:</li><li>1.Try negative sampling to boost the training and improve the metrics (better than softmax).</li><li>2. Implement attention mechanism to seq2seq model.</li></ul><h3>Reference</h3><ol><li><a href="https://arxiv.org/pdf/1405.4053.pdf">Distributed Representations of Sentences and Documents</a></li><li><a href="https://arxiv.org/pdf/1310.4546.pdf">Distributed Representations of Words and Phrases and their Compositionality</a></li><li><a href="https://arxiv.org/pdf/1409.0473.pdf">Neural machine translation by jointly learning to align and translate</a></li><li><a href="https://papers.nips.cc/paper/7181-attention-is-all-you-need.pdf">Attention Is All You Need</a></li><li><a href="https://arxiv.org/pdf/1803.00942.pdf">Importance Sampling</a></li><li><a href="https://papers.nips.cc/paper/5346-sequence-to-sequence-learning-with-neural-networks.pdf">Sequence to Sequence Learning with Neural Networks</a></li></ol><h3><strong>Acknowledgement</strong></h3><ul><li>Dataset is from <a href="https://www.kaggle.com/gyani95/380000-lyrics-from-metrolyrics">Kaggle</a>.</li><li>Thanks for the tutorial <a href="https://github.com/philferriere/dlwin">GPU-accelerated Deep Learning on Windows 10</a>.</li></ul><p><strong>Final Words</strong></p><p>If any errors are found, please email me at venkat.chadalavada@gmail.com</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e174bfc6c2f" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Predicting Sales Opportunities]]></title>
            <link>https://medium.com/@venkat.chadalavada/predicting-sales-opportunities-504bee13d9ac?source=rss-9ec97de55fb7------2</link>
            <guid isPermaLink="false">https://medium.com/p/504bee13d9ac</guid>
            <category><![CDATA[data-science]]></category>
            <category><![CDATA[machine-learning]]></category>
            <dc:creator><![CDATA[Venkat Chadalavada]]></dc:creator>
            <pubDate>Fri, 21 Feb 2020 14:52:05 GMT</pubDate>
            <atom:updated>2020-02-21T14:52:05.650Z</atom:updated>
            <content:encoded><![CDATA[<p>Capstone Project</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/591/1*B958YBdVcW-WrRzNtTjSWQ.jpeg" /></figure><h3>Introduction</h3><p>Sales is one of the essential components of any business. It is the act of selling goods or services to an interested party, in exchange for money. It is the primary process for a business to generate revenue, which explains why it is so vital for any organisation. Without sales, a business will not have the resources necessary to grow or even survive.</p><p>Due to its importance, this project will examine the sales process of an organisation and seek to achieve the following goals:-</p><p>Goal 1 — Predict the value of sales opportunity (‘Amount’ column) using regression models</p><p>Goal 2 — Predict the outcome of sales opportunity (‘Result’ column) using classification models</p><h3>Table of Contents</h3><p>Part 1 Pre-Processing<br> 1.1 — Data Overview<br> 1.2 — Data Cleaning<br> 1.3 — Exploratory Data Analysis<br> 1.4 — Feature Engineering<br> Part 2 Predict Opportunity Amount<br> 2.1 — Feature Selection<br> 2.2 — Prepare training/testing data<br> 2.3 — Model Generation<br> 2.4 — Model Results Evaluation<br> 2.5 — Model Selection<br> Part 3 Predict Opportunity Outcome<br> 3.1 — Prepare training/testing data<br> 3.2 — Data Imbalance<br> 3.3 — Model Generation<br> 3.4 — Model Results Evaluation<br> 3.5 — Model Selection<br> Conclusion</p><p>Part 1 Pre-Processing</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/777/1*KSad6kwraz_BJfaXp7lS0Q.png" /></figure><h3>1.1 — Data Overview</h3><p>In this project, we will be looking at the sales database for an automotive supplies wholesaler. This is a sample dataset provided by <a href="https://www.ibm.com/communities/analytics/watson-analytics-blog/sales-win-loss-sample-dataset/">IBM Watson Analytics</a>. The goal of the sales process is to identify and communicate with potential leads, and explore opportunities to convert them into customers. For this project, the database contains records of every sales opportunity with information about the client, product, and process status which focuses on 3 key stages:-</p><ol><li>Identified/Qualifying</li><li>Qualified/Validating</li><li>Validated/Gaining Agreement</li></ol><p>This dataset consists of 78,025 rows and 19 columns (9 numerical, 10 categorical). The columns include the following:-</p><ol><li>Amount — Estimated total revenue of opportunities in USD. (Goal 1)</li><li>Result — Outcome of opportunity. (Goal 2)</li><li>Id — A uniquely generated number assigned to the opportunity.</li><li>Supplies — Category for each supplies group.</li><li>Supplies_Sub — Sub group of each supplies group.</li><li>Region — Name of the region.</li><li>Market — The opportunities’ route to market.</li><li>Client_Revenue — Client size based on annual revenue.</li><li>Client_Employee — Client size by number of employees.</li><li>Client_Past — Revenue identified from this client in the past two years.</li><li>Competitor — An indicator if a competitor has been identified.</li><li>Size — Categorical grouping of the opportunity amount.</li><li>Elapsed_Days — The number of days between the change in sales stages. Each change resets the counter.</li><li>Stage_Change — The number of times an opportunity changes sales stage. Includes backward and forward changes.</li><li>Total_Days — Total days spent in Sales Stages from Identified/Validating to Gained Agreement/Closing.</li><li>Total_Siebel — Total days spent in Siebel Stages from Identified/Validating to Qualified/Gaining Agreement.</li><li>Ratio_Identify — Ratio of total days spent in the Identified/Validating stage over total days in sales process.</li><li>Ratio_Validate — Ratio of total days spent in the Validated/Qualifying stage over total days in sales process.</li><li>Ratio_Qualify — Ratio of total days spent in Qualified/Gaining Agreement stage over total days in sales process.</li></ol><h3>1.2 — Data Cleaning</h3><p>Before proceeding, it is necessary to conduct checks to evaluate the integrity of the dataset. Incorrect and incomplete data will affect the results of our models, so these issues will need to be identified and addressed first.</p><p>Missing values is a common problem faced in data science. Fortunately, our dataset is complete without any missing values.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/280/1*GqRmGswXt4rKRe7ElLTyKw.png" /></figure><p>Next, a check will be conducted on the 3 ratio columns (Ratio_Identify, Ratio_Validate, Ratio_Qualify) to ensure that the total value does not exceed 1. A new column Total_Ratio will be created that sums up the values of these 3 columns.</p><p>The results of the new Total_Ratio column shows that there are 471 records with a total ratio that exceeds the total of 1. Upon closer inspection, the exceeded amount for each of these records is very minor and it is safe to assume that this is possibly due to the rounding in the 3 ratio columns and thus these records will remain as is.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*hml0hJGb97cwwwNYThTYNg.png" /></figure><p>However, there is a single record that has an extreme value of 1.007547. This record will therefore be removed.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*P4zU5H0DsSlkxkwMVhGBTA.png" /></figure><p>The string values for the categorical columns will also be cleaned up to ensure a consistent format.</p><p>cars[‘Client_Employee’].replace([‘1K or less’, ‘More than 25K’, ‘5K to 15K’, ‘1K to 5K’, ‘15K to 25K’], [‘Below_1K’, ‘Above_25K’, ‘5K_to_15K’, ‘1K_to_5K’, ‘15K_to_25K’], inplace=True)</p><h3>1.3 — Exploratory Data Analysis</h3><p>With the data cleaned, we can now carry out EDA and perform an in-depth analysis of the data.</p><p>Lets start by examining the correlation between the numerical columns through the construction of a heatmap.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/775/1*5hdVs2sqVa2rVj_Hk48Hpg.png" /></figure><p>The heatmap above immediately higlights an almost perfect correlation between the Total_Days and Total_Siebel columns. This will have a negative impact on our models, therefore the Total_Siebal column will be dropped. The other numerical columns have a low to moderate correlation value, which are acceptable and no additional measures will be required.</p><p>Next, we will analyse the distribution of our features by plotting various graphs.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*QtGblyzRGgPCASL5qL4nlQ.png" /></figure><p>We will use histograms to represent data in the numerical columns. Majority of the graphs show a positively skewed distribution, with very few data points located on the right side. The 3 ratio columns represent data points that are located at both extreme ends of the scale and a minimal number in the middle.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*SSqqIfpT9cu6o7DEv_st4Q.png" /></figure><p>With regards to the categorical columns, bar graphs illustrate the distribution across the different classes. We can see a decent spread across all classes for the Supplies_Sub, Region and Size columns. However, the other features have a strong class imbalance distribution, with a single dominant class. Even our target feature Result has an imbalance where the majority class is about three times larger than the minority class. Class imbalance can have a negative impact on machine learning algorithms, and may result in predictive models that are biased and inaccurate.</p><h3>1.4 — Feature Engineering</h3><p>The next stage of pre-processing requires some changes to be made to the current features. The first step involves converting the values in our target column Result into binary values.</p><pre>cars[&#39;Result&#39;] = cars[&#39;Result&#39;].map(lambda x: 0 if x == &#39;Loss&#39; else 1)</pre><p>The classes in the Client_Past columns are also changed. The data is grouped into 2 classes to identify if the opportunity is from a new client or existing client, rather than separating into 5 classes.</p><pre>cars[&#39;Client_Past&#39;] = cars[&#39;Client_Past&#39;].map(lambda x: 0 if x == &#39;0 (No business)&#39; else 1)</pre><p>Comparing the Supplies and Supplies_Sub columns, we can see that Supplies_Sub actually is more detailed and provides a clearer picture as compared to Supplies. Therefore, the Supplies column will be dropped.</p><p>With regards to the categorical columns, bar graphs illustrate the distribution across the different classes. We can see a decent spread across all classes for the Supplies_Sub, Region and Size columns. However, the other features have a strong class imbalance distribution, with a single dominant class. Even our target feature Result has an imbalance where the majority class is about three times larger than the minority class. Class imbalance can have a negative impact on machine learning algorithms, and may result in predictive models that are biased and inaccurate.</p><h3>1.4 — Feature Engineering</h3><p>The next stage of pre-processing requires some changes to be made to the current features. The first step involves converting the values in our target column Result into binary values.</p><pre>cars[&#39;Result&#39;] = cars[&#39;Result&#39;].map(lambda x: 0 if x == &#39;Loss&#39; else 1)</pre><p>The classes in the Client_Past columns are also changed. The data is grouped into 2 classes to identify if the opportunity is from a new client or existing client, rather than separating into 5 classes.</p><pre>cars[&#39;Client_Past&#39;] = cars[&#39;Client_Past&#39;].map(lambda x: 0 if x == &#39;0 (No business)&#39; else 1)</pre><p>Comparing the Supplies and Supplies_Sub columns, we can see that Supplies_Sub actually is more detailed and provides a clearer picture as compared to Supplies. Therefore, the Supplies column will be dropped.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/513/1*drj_3wGcmkg70PZaAUA3hQ.png" /></figure><p>The Total_Siebel column was previously shown to be highly correlated to the Total_Days column, so that too will be removed.</p><p>Due to the number of categorical features in our dataset, we will create 38 new dummy variables to replace the original categorical columns. This new set of dummy variables is then concatenated with the original dataset to create a new dataset to be used our predictions.</p><pre>cat_dummy = pd.get_dummies(cars2[cat_columns], drop_first=True)<br>cars2.drop(cat_columns, axis=1, inplace=True)<br>cars2 = pd.concat([cars2, cat_dummy], axis=1)</pre><p>With pre-processing completed, we are now ready to commence building our predictive models.</p><h3>Part 2 Predict Opportunity Amount</h3><p>All businesses are interested in knowing how much revenue they can make for each transaction, therefore the ability to predict the value of a sales opportunity would be very insightful. In this section, the objective will be to predict the values in the Amount column and through the use of Regression algorithms. But first, we will need to take additional steps to prepare our data for model generation.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/468/1*VMNd7ZsgoS3YgdmnVYXxYg.png" /></figure><h3>2.1 — Feature Selection</h3><p>We will begin by performing feature selection by using the .summary() command from statsmodels python package to analyse the p-values of each feature. Any features with a p-value or 0.05 and higher will be deemed insignificant and thus dropped.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/629/1*6aNnHgjyRZcMbYVoJqZSFA.png" /></figure><p>These are the features that were dropped.</p><pre>cars2.drop([&#39;Ratio_Identify&#39;, &#39;Supplies_Sub_Electronics&#39;, &#39;Supplies_Sub_Garage_Car_Care&#39;, &#39;Market_Other&#39;,<br>            &#39;Client_Revenue_500K_to_1M&#39;, &#39;Client_Revenue_250K_to_500K&#39;, &#39;Supplies_Sub_Towing_Hitches&#39;,<br>            &#39;Client_Revenue_Above_1M&#39;, &#39;Client_Revenue_Below_100K&#39;, &#39;Client_Employee_1K_to_5K&#39;,<br>            &#39;Client_Employee_5K_to_15K&#39;, &#39;Client_Employee_Below_1K&#39;, &#39;Client_Employee_Above_25K&#39;,<br>            &#39;Supplies_Sub_Tires_Wheels&#39;, &#39;Region_Midwest&#39;, &#39;Elapsed_Days&#39;, &#39;Supplies_Sub_Replacement&#39;,<br>            &#39;Supplies_Sub_Motorcycle_Parts&#39;, &#39;Ratio_Validate&#39;, &#39;Total_Days&#39;], axis=1, inplace=True)</pre><p>Using this method, 20 out of 44 features were removed. The selected features are shown below.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/607/0*x6CwPIoYzpoWK_zC" /></figure><h3>2.2 — Prepare training/testing data</h3><p>To prepare our data, we will use the holdout method to split our dataset. We will use training set that comprises of 70% of the data to train our models, and a testing set of 30% to assess their predictions. 5-fold cross validation will also be applied to the training set for all models.</p><pre>X_train, X_test, y_train, y_test = train_test_split(X, y, train_size=0.7, random_state=100)</pre><h3>2.3 — Model Generation</h3><p>Model construction can begin by using the new prepared datasets.</p><p>5 different regression algorithms will used to create the models:</p><ol><li>Linear Regression</li><li>Lasso Regression</li><li>Ridge Regression</li><li>SGD Regression</li><li>Random Forest Regression</li></ol><p>The diagram below is an example of the code used to build the Lasso Regression model.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/747/0*J2glCKvtS5WN1qNy" /></figure><p>The results for each of the 5 models will be collected and evaluated, before selecting the model that best predicts the opportunity amount.</p><h3>2.4 — Model Results Evaluation</h3><p>With the models completed, we can now compile all the results into a new pandas dataframe, making it easier to compare the results. Graphical representations will also be generated to help visualise the output.</p><p>Model performance will be judged based on 2 key criterias:-</p><ol><li>R² score (training, cross validation, testing)</li><li>Root Mean Squared Error score (RMSE)</li></ol><p>We will also take a look at the feature rankings for the models.</p><p>When conducting evaluation, we are looking for a model with a high R² score and low RMSE score. The R² score would indicate the goodness of fit of a set of predictions on the actual values, RMSE indicates the magnitude of error between the predicted and actual value in terms of the output value.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/372/0*9vW0nVS8ga3YQX2Q" /></figure><p>Looking at the compiled results, we see that Linear, Lasso and Ridge Regression achieved the highest R² scores, and the results were identical. Even their RMSE scores were almost exact. On the other hand, the Random Forest Regression model performed the worst with the lowest R² score and highest RMSE score.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*ew5qqEl8zomFjA77" /></figure><p>In terms of feature ranking, all 5 models share the same features that occupy the top 4 ranks, which are Size_above_60K, Size_50K_to_60K, Size_40K_to_50K and Size_30K_to_40K. After that, feature rankings begin to differentiate between models. These top 4 features also have very similar coefficient values, with the exception of the Random Forest Regression model which uses a different weights scale. The coefficient values show us how large of an impact a particular feature has on the overall opportunity amount.</p><h3>2.5 — Model Selection</h3><p>As mentioned earlier, the ideal model is judged according to their R² and RMSE scores. As Linear Regression, Lasso Regression and Ridge Regression had the highest R² testing score and their values are identical, we will then compare the RMSE score between these 3 models. Based on our evaluation of the results above, we can conclude that the Ridge Regression model is the best choice with the lowest RMSE score of 39646.3218.</p><h3>Part 3 Predict Opportunity Outcome</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*TJe__O6pOG1TBJVR" /></figure><p>In part 3 of this project, we will now create classification models to predict the sales opportunity outcome (Result column). The ability to predict the outcome enables a business to identify influencing factors and also better utilize their resources.</p><p>Previously in our pre-processing stage, we converted the values in the Result column into binary numbers. The value 1 represents the opportunities that were won, while the value 0 signifies the opportunities that were lost. Hence, our goal will be to accurately predict the highest number of 1s.</p><h3>3.1 — Prepare training/testing data</h3><p>For this prediction, we will also be using the holdout method to create the training and testing datasets, and incorporating 5-fold cross-validation into the models.</p><p>The next step incorporates the SelectFromModel function from sklearn to perform feature selection, and apply the RandomForestClassifier inside the function as an estimator to identify the feature importance.</p><pre>from sklearn.feature_selection import SelectFromModel<br>from sklearn.ensemble import RandomForestClassifier<br>select = SelectFromModel(RandomForestClassifier())<br>select.fit(Xs_train, y_train)<br>Xs_train = select.transform(Xs_train)<br>Xs_test = select.transform(Xs_test)<br>feature_support = pd.DataFrame({&#39;feature&#39;: X_train.columns, &#39;support&#39;: select.get_support()})<br>feature_support.sort_values(&#39;support&#39;, inplace=True, ascending=False)<br>feature_support.head(10)</pre><p>The results show that out of the 44 features in our dataset, only 9 were selected. This means that these 9 features had the biggest influence in prediction the opportunity outcome.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/208/0*-sQtOrMiBfccJfQg" /></figure><h3>3.2 — Data Imbalance</h3><p>As previously shown in our distribution plots under the EDA section, there is an imbalance in our target column whereby the majority class 0 has a total count of more than 3 times when compared to the minority class 1. To solve the problem of class imbalance, we will utilize 2 different techniques from the python package imblearn to resample the data in our training set.</p><p>RandomOverSampler — randomly oversample the minority class (1) with replacement.</p><pre>from imblearn.over_sampling import RandomOverSampler<br>ros = RandomOverSampler(random_state=100)<br>Xs_train_ros, y_train_ros = ros.fit_sample(Xs_train, y_train)</pre><p>RandomUnderSampler — randomly undersample the majority class (0) with replacement.</p><pre>from imblearn.under_sampling import RandomUnderSampler<br>rus = RandomUnderSampler(random_state=100)<br>Xs_train_rus, y_train_rus = rus.fit_sample(Xs_train, y_train)</pre><p>Oversampling will increase the number of minority class from 12401 to 42215, while undersampling will reduce the number of majority class from 42215 to 12401. The end result after resampling is 3 different training sets (default, oversample, undersample).</p><h3>3.3 — Model Generation</h3><p>Now that we have our training and testing datasets, we can begin to generate our models.</p><p>3 different classification algorithms will used to create the models:</p><ol><li>Logistic Regression</li><li>Random Forest</li><li>K-Nearest Neighbors</li></ol><p>3 versions of each algorithm will also be created, with each version tackling a different dataset (default, oversample, undersample). In the end, we will have 9 models to compare. The results for each of the 9 models will be collected and evaluated, before selecting the model that best predicts the opportunity result.</p><h3>3.4 — Model Results Evaluation</h3><p>With the models completed, we can now compile all the results into a new pandas dataframe, making it easier to compare the results. Graphical representations will also be generated to help visualise the output.</p><p>An example of the output results for the Logistic Regression (default) model is shown below.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/526/0*Z5P5znUasJubSd35" /></figure><p>Model performance will be judged based on 3 key criterias:-</p><ol><li>Confusion matrix results (TN, FP, FN, TP)</li><li>Accuracy scores (training, cross validation, testing, AUC ROC)</li><li>Precision and recall scores of the minority class</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*Ea9zXHjPzhyRXtiL" /></figure><p>From the precision and recall graphs above, we can see an inverse correlation between them. Models that had a high precision result like Random Forest (default) and KNN (default) did not perform well in recall, while models with high recall results like KNN (undersample) and Random Forest (undersample) had a lower precision result.</p><p>Another interesting point to note is that default models achieved higher precision scores while models with undersampling had higher recall scores.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*NfiSTNDAoOAnmIhO" /></figure><p>In terms of accuracy scores, our models will need to achieve an accuracy score that is higher than the baseline of 0.77408. From the results, all 9 models were able to exceed the baseline. The Logistic Regression models in general had the lowest scores, while the Random Forest models had the best.</p><p>When comparing the 4 accuracy graphs,the random forest (oversample) model was consistently able to achieve one of the highest scores across all 4.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*-SjcGFaGtZV-njAZ" /></figure><p>Looking at the confusion matrix results, the KNN (undersample) and Random Forest (Undersample) models had the highest number of correct predictions for the minority class (TP), while the Random Forest (default) and Logistic Regression (default) models had the most number of majority class predictions (TN).</p><p>In terms of wrong predictions, Logistic Regression (oversample and undersample) has the most Type I errors (FP) and Logistic Regression (default) the highest number of Type II errors (FN). This means that Logistic Regression models are unable to accurately classify the minority class and would be unsuitable algorithm to achieve our goal.</p><p>When comparing the Random Forest and KNN models, the undersampling models had the most False Positive (FP) errors and the lowest False Negative (FN) rates . On the other hand, while default and oversampling models may have a lower FP rate, their FN rate is higher.</p><h3>3.5 — Model Selection</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/728/0*aYkml7YbFJFjEsCX" /></figure><p>Since our goal is to predict the highest number of win opportunities, a model with high recall is desired. Being able to identify these accurately will mean more revenue for the business. Based on this, the K-Nearest Neighbors (undersample) model was able to achieve the highest recall score of 0.83, the highest True Positive (TP) rate of 4349, and lowest False Negative (FN) rate of 877. While its Type II error (FP) is one of the highest out of all the models, it is more acceptable to wrongly predict a loss opportunity than an inaccurate prediction of a won opportunity. Therefore, this model would be most suitable to achieve our goal of predicting the opportunity outcome.</p><h3>Conclusion</h3><p>After constructing our predictive models and analysing the results, we can conclude that the goals that were originally set have been achieved. The Ridge Regression model is suitable to predict the value of sales opportunities, and the K-Nearest Neighbors (undersample) model can be used to predict the outcome. Overall, this project demonstrates the usefulness of machine learning in creating business insights.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=504bee13d9ac" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>