<?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 Abhinav Sharma on Medium]]></title>
        <description><![CDATA[Stories by Abhinav Sharma on Medium]]></description>
        <link>https://medium.com/@abhinavsharma_64776?source=rss-9e994f9ef9cf------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*NHAGqzewmpe4rsp0Wg-uwQ.jpeg</url>
            <title>Stories by Abhinav Sharma on Medium</title>
            <link>https://medium.com/@abhinavsharma_64776?source=rss-9e994f9ef9cf------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Fri, 22 May 2026 18:48:53 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@abhinavsharma_64776/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[Classification machine learning using Adobe Analytics data]]></title>
            <link>https://medium.com/@abhinavsharma_64776/classification-machine-learning-using-adobe-analytics-data-ff09fe078271?source=rss-9e994f9ef9cf------2</link>
            <guid isPermaLink="false">https://medium.com/p/ff09fe078271</guid>
            <category><![CDATA[adobe-analytics]]></category>
            <category><![CDATA[classification]]></category>
            <category><![CDATA[adobe-target]]></category>
            <category><![CDATA[shap]]></category>
            <category><![CDATA[machine-learning]]></category>
            <dc:creator><![CDATA[Abhinav Sharma]]></dc:creator>
            <pubDate>Thu, 17 Aug 2023 12:09:02 GMT</pubDate>
            <atom:updated>2023-08-17T12:26:50.531Z</atom:updated>
            <content:encoded><![CDATA[<h4><strong>Applying machine learning for advanced analysis on clickstream data.</strong></h4><h4>Problem Statement</h4><blockquote><strong>We take an airline as an example. But this use case is relevant to any e-commerce site where there is a classification problem.</strong></blockquote><p><strong>An airline retail site wants to optimize the booking journeys in real-time for customers based on their travel intent. They offer hotel, cabs, and experiences (ancillary) cross-sell during flight sales and want to increase this cross-sell conversion. If they have user propensities to ancillary purchases, they can optimize the flight summary page or even the confirmation page to include relevant offers around cross-sell.</strong></p><h4><strong>Tool Kit</strong></h4><p><strong>The airline has clickstream tracking via Adobe Analytics and content management via Adobe Target. There is s CRM CDP but is not connected to online tracking via unified ID. This limits our visibility to historical customer booking behavior.<br>There is a robust data layer that captures all values ultimately passed into Adobe Analytics.</strong></p><h4>Solution Approach</h4><p><strong>We will try to solve this problem in 4 steps</strong></p><ol><li>We will build a classification model on the booking details of all customers. We get booking details from the Adobe Analytics data warehouse.</li><li>Ideally, this model output should be directly actionable but since that’s not possible here (lack of centralized customer data warehouse), we will instead analyze feature importance from the model above using SHAP values.</li><li>We will next build a cluster model (unsupervised learning) from the SHAP values to determine feature values critical in purchase propensity.</li><li>These values can then be utilized directly in Adobe Target to build customized experiences for the cohort with higher propensity.</li></ol><blockquote>This solution is relevant to any e-commerce use case where there is online data collection (form, widgets, etc.) leading to customer transactions.</blockquote><h4>Step 1: Classification using XGBoost (or any other classification model)</h4><p>We run a classification model to observe whether the model scores better than the baseline evaluation metric. This ensures that the features are relevant for prediction and that there is a trend hidden in their interactions.</p><p>Any classification model would work but you will generally find that an ensemble model would be most efficient.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/549/1*Q6EG5v22RnnszonhRxFB_g.png" /><figcaption>ensemble model like XGBoost would return permutation-based feature importance</figcaption></figure><h4>Step 2: Feature importance using SHAP values</h4><p>SHAP feature importance is an alternative to permutation feature importance. Permutation feature importance is based on the decrease in model performance when a feature is removed. SHAP is based on the contribution of a feature value to the prediction in different coalitions.</p><p>Given that SHAP values work on impact on prediction rather than model output, hence is best suited to determine the importance of features working in coalition and suits real-life scenarios the best.</p><p>SHAP values, once generated, can be visualized through string of plots, thereby further helping in interpretation.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*un5HwtRyNoSm44d8Ytg5Qw.jpeg" /><figcaption>SHAP values to explain the predicted ancillary purchase of an individual flight search. The baseline — the average predicted probability — is -2.314. This search has a lower predicted probability of -4.06. Purchase-increasing effects such as a travel duration of 5 days are offset by decreasing effects such as only one adult passenger.</figcaption></figure><p>SHAP Summary Plot —</p><p>The summary plot combines feature importance with feature effects. Each point on the summary plot is a Shapley value for a feature and an instance. The position on the y-axis is determined by the feature and on the x-axis by the Shapley value. The color represents the value of the feature from low to high.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/572/1*FUXCFznMwhys4QxWxtxbDQ.png" /><figcaption>SHAP summary plot. A low number of days for travel duration increases the predicted propensity to purchase, and a large number of days decreases the propensity. Your regular reminder: All effects describe the behavior of the model and are not necessarily causal in the real world.</figcaption></figure><h4>Step 3: Clustering SHAP values using kMeans</h4><p>Clustering bookings by their SHAP values leads to isolating groups with high propensity to purchase and we can observe the values of respective features for those groups.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Qs_SM4ZMOFO_dE8aYvqTjQ.jpeg" /><figcaption>Cluster dataset with mean values of all the features for each cluster. The cluster with the highest mean for the target variable represents the cohort with the highest propensity.</figcaption></figure><p>We observe from here that segment 3 has the most propensity to ancillary purchase (a_purchase mean = 0.45). The top 3 important features have the following mean values -</p><ol><li>Travel duration (9.26) ~ 9 days</li><li>Adult passengers (1.71) ~ 2 adults</li><li>Time to travel (122.14) ~ 122 days</li></ol><p>We can also use quantile thresholds to understand the range of values in the segments and based on that recommend rules for Adobe Target activation.</p><h4>Step 4: Adobe Target (or any other audience) activation</h4><p>Observing both quantiles and mean, we can recommend the following thresholds for Adobe Target experience activation (remember this is dummy data so values are not expected to make sense) -</p><ol><li>Bookings/Searches with a travel duration of less than 10 days</li><li>Number of adult passengers more than 2</li><li>time to travel more than 30 days</li></ol><p>This is a very good set of criteria that isolates an audience/ cohort with the best possible chances to purchase ancillary products. Adobe Target can create custom experiences for these audiences while keeping a general experience for the rest of the visits. For example, an extra page highlighting ancillary products or destination-themed content can be tested for this cohort in flight selling flow without risking the usual experience for general users. Based on observation, experiences can be scaled to a wider audience.</p><p>Code Repo in my <a href="https://github.com/abhinav-sharma15/feature_importance/tree/main">Github here.</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ff09fe078271" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[A/B Test MythBusters]]></title>
            <link>https://medium.com/@abhinavsharma_64776/a-b-test-mythbusters-5f9b6de01d69?source=rss-9e994f9ef9cf------2</link>
            <guid isPermaLink="false">https://medium.com/p/5f9b6de01d69</guid>
            <category><![CDATA[ab-testing]]></category>
            <dc:creator><![CDATA[Abhinav Sharma]]></dc:creator>
            <pubDate>Thu, 17 Aug 2023 09:59:00 GMT</pubDate>
            <atom:updated>2023-08-17T09:59:00.508Z</atom:updated>
            <content:encoded><![CDATA[<p>A/b testing is a decision-making support and research methodology which is an integral part of the product design lifecycle. Product managers should use testing outcomes to determine not only the look and feel of their products but their viability as well.</p><p>The following examples explain the importance of a/b testing at different stages of the product lifecycle -</p><p><strong>Introduction </strong>— New features are launched for a controlled set of actual users (eg. 1% of users) and the performance data is compared against the existing cohort to determine if there is any quantifiable improvement. This also gives the opportunity to determine any technical issues or bugs in the product. Most organizations already do this as an enhanced form of beta testing.</p><p><em>Example: Fictious online retailer called AMart has launched a new feature allowing users to save their shopping lists which can then be easily passed on to the trolley.</em></p><p><strong>Growth </strong>— Add-ons or redesigns are religiously put through a/b testing pipelines to get data-led insights (rather than hunches) around their performance.</p><p><em>Example: PMs at AMart need to improve add to trollies from the Shopping list feature. They notice that the ‘Add to Trolley’ button is only provided at the end of the page and perhaps for longer lists, users find it difficult to locate. They want to test having this CTA both at the top and end of the page.</em></p><p><strong>Maturity </strong>— for established products, the focus shifts on retention and hence any re-branding or upgrades again go via a/b testing pipelines to validate efficiency. This is also where a/b testing evolves into targeting and personalization.</p><p><em>Example: Users with shopping lists are perceived to be wanting easy shopping regularly. AMart PMs hypothesize that an auto-generated weekly/ monthly shopping list based on their shopping history would further make their shopping easier. This hypothesis obviously needs validation via testing but also needs further intelligence around targeting specific cohorts.</em></p><p>A/b testing is the most accurate way to quantitatively measure an impact of a change in a product. However, it can only highlight what changed and by how much. Any insights around the ‘why’ of it, will need traditional qualitative research methods like user interviews and surveys, etc.</p><h3>Myth 2: We have sample size calculator; we don’t need a data scientist.</h3><p>In my experience, I have seen statistics as the biggest casualty in the whole a/b testing process. For a successful and productive testing program, a data scientist is a must on board. A good data scientist will be a champion of internal business KPIs. They will know the variance for these KPIs and would understand how seasonality and other external factors (eg. Campaigns) affect them. Hence, they will be in the best position to give the most accurate pre and post-assessment of the tests. This avoids a lot of hit-and-trial costs for the organization.</p><p>A company using agile methodology usually has a feature development team that comprises of product managers, software developers, designers, and data scientists. They all have a role to play in the ab testing process (highlighted in the figure above). Data scientist engages right at the onset giving the right guidance in terms of measurement and feasibility of KPIs. They then set up the test and avoid common mistakes like peeking at false positives during the run period.</p><h3>Myth 3: Statistical significance is the only statistic that is required.</h3><p>I have seen on several occasions where teams treat statistical significance as the ultimate goal of the tests. The whole exercise of sample size calculation is centered around ensuring that the tests have a fair chance of reaching statistical significance. While this is partially true, testers rarely tune other variables in the sample size formula.</p><p>The most important of them is the Minimum detectable effect or MDE. Most often, I have seen test engineers going with default values for MDE or using hunches to go with values like 10%, 5%, etc.</p><blockquote><em>What is minimum detectable effect (MDE)?</em></blockquote><blockquote><em>In traditional hypothesis testing, the MDE is essentially the sensitivity of your test. In other words, it is the smallest relative change in conversion rate you are interested in detecting. For example, if your baseline conversion rate is 20%, and you set an MDE of 10%, your test would detect any changes that move your conversion rate outside the absolute range of 18% to 22% (a 10% relative effect is a 2% absolute change in conversion rate in this example).</em></blockquote><blockquote>excerpt taken from <a href="https://www.optimizely.com/sample-size-calculator/#/?conversion=3&amp;effect=20&amp;significance=95">Optimizely Sample Size Calculator</a>.</blockquote><p>MDE should be more personal than we often treat it to be.</p><p>Assuming a normal distribution of measurements of any metric, we expect most values to lie within one standard deviation of the mean. Hence, we should treat results from any two samples as different only when they are at least beyond one standard deviation (of the mean). I rarely see this insight properly reflect in the sample sizing.</p><p>A good estimate starts with the historical trend of your population metric. Filtering out anomalies, use the trend to get the mean and standard deviation for the metric. The relative difference between mean and S.D. is what you should consider as your minimum detectable effect. It is okay to have value more than S.D. depending on the bandwidth and flexibility of your test conditions. But having a totally disproportionate figure to this difference is unnecessary starching your experiment to unreasonable statistical tests. This ultimately translates to cost in terms of time and resource wastage.</p><h3>Myth 4: There is a standard sample size formula that fits any KPI.</h3><p>The traditional proportion-based sample size estimator churns out the total number of visits/users required for each variation in the test. This is useful if we want to measure KPIs around actions of the users like purchase and clickthrough etc. The ‘action’ in this case is binary in nature and the metric is treated as binomial.</p><p>However, recently, and particularly with the onset of mobile apps, aggregate KPIs are also very in demand. These are continuous metrics that are then aggregated at a time or user level to measure their values. Examples include Daily Active Use (DAU) or Revenue per user (RPV) etc.</p><p>The sample size is estimated by using variations of one or a two-tailed Z-test for both categories of metrics. The major difference is that for continuous variables, the sample size is the number of days rather than the actual volume. This is achieved by replacing probabilities with standard deviation in the formula for continuous metrics.</p><p><a href="https://www.stat.ubc.ca/~rollin/stats/ssize/b2.html">Example of proportion-based sample size calculato</a> r (for binomial metrics)</p><p><a href="https://www.stat.ubc.ca/~rollin/stats/ssize/n2.html">Example of mean-based sample size calculator</a> (for continuous metrics)</p><h3>Myth 5: Lift from an a/b test will remain forever.</h3><p>It is unsafe to assume that the changes you make based on a/b test lift, will last forever. This is especially true for revenue or conversion-related metrics.</p><p>For example, let’s say you observe a statistically significant lift of 10% from variation at the end of the test. You roll out the variation. For how long you should continue to expect a 10% lift from the change?</p><p>This is a complex question to answer and requires some analysis and familiarity with business but it’s wise to count on the fact that the effect of the variation will decay with time and eventually will remain only a proportion of what it was.</p><p>Usually, it is recommended to attach monthly, quarterly, and yearly lift estimates with your test plan. These estimates should incorporate a decay model instead of being linear in nature.</p><p>This is again where data scientist has a role to play. If the revenue per conversion is known for the target test, a data scientist can use a confidence interval around the MDE as a lift estimate to prepare an incremental revenue impact around the test activities.</p><p><em>Originally published at </em><a href="https://www.linkedin.com/pulse/ab-test-mythbusters-abhinav-sharma"><em>https://www.linkedin.com</em></a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5f9b6de01d69" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[My reflections on issues around use of AI (as of 2022)]]></title>
            <link>https://medium.com/@abhinavsharma_64776/my-reflections-on-issues-around-use-of-ai-as-of-2022-32fcccc7d288?source=rss-9e994f9ef9cf------2</link>
            <guid isPermaLink="false">https://medium.com/p/32fcccc7d288</guid>
            <category><![CDATA[ai-skills]]></category>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[machine-learning]]></category>
            <dc:creator><![CDATA[Abhinav Sharma]]></dc:creator>
            <pubDate>Thu, 31 Mar 2022 10:24:59 GMT</pubDate>
            <atom:updated>2022-03-31T10:24:59.936Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*47COo4d2JUlLs3Lw2B1p5g.jpeg" /><figcaption>Image source: Pixabay | No attribution required</figcaption></figure><p>In this short reflective essay, I will talk about issues and concerns around use of AI in various industries. I will start with highlighting some areas of concern and then follow it up with my own reflections and experiences. I will conclude by expressing what I think should be the future course in terms of AI adoptability and use.</p><h3><strong>Can AI make value judgements?</strong></h3><p>We are living in a unique time in history where AI engineers are suddenly at the frontline of tackling complex spiritual questions. Consider this classic philosophical dilemma that is quite relevant in design of a self-driving car —</p><p><em>A car is self-driving with owner sleeping on the back seat. Suddenly two playing kids jump on the road in front of the car. The only way to save the two kids is to swerve to the side and fall of the cliff and kill the owner of the car. What should the car do?</em></p><p>The response would most likely be syntactically coded in its system meaning that whatever we program as the right approach is guaranteed to be implemented. Firstly, it means that it is responsibility of an engineer (maybe supported by a team of philosophers) to get a deterministic answer to such a complex question. Secondly, given the deterministic (and in any case controversial) nature of the solution, it opens the possibility of exploitation and abuse. This is very different from how a human being would respond to such scenarios. Philosophers can debate about the best way to deal with such situations and come up with a solution. But the interesting thing about us humans (including those philosophers) is that when faced with real life scenarios requiring quick decisioning, we often respond erratically and care little about the philosophy that we preach.</p><p>It could be argued that it is such randomness (or perhaps intuitiveness) that keeps this complex world in balance.</p><p>This might be a subjective example, but it effectively highlights the problem and issues we face as we adopt more AI reliant systems in our daily lives. Today, AI is fast replacing human involvement in fields like justice, medicine, and security. Effectively we are replacing probabilistic systems with high precision deterministic systems. As such, its paramount that the systems are built by the experienced and the data that is fed into the system to train itself should be of highest quality.</p><h3><strong>The issue with data</strong></h3><p>Anyone living with United Kingdom would relate to the fact that UK’s National Health Service doesn’t link its healthcare records together as a matter of standard practice. This means that if I visit an NHS hospital for certain issue, they won’t have explicit visibility to any of my previous visits to my GP.</p><p>Artificial intelligence has lot of potential in disease diagnosis and pattern detection. However, if NHS avails a state-of-the-art AI solution for disease detection and prediction, it will mostly be ineffective given nature of the data about patients which is not centralized, collated, and collected properly.</p><p>The point is, that so far, we haven’t been able to build a solid data ecosystem for most of our AI platforms across industries. And hence, we get to hear frequent news about biased or erratic AI projections. These incidences further diminish public’s faith in adopting these technologies. On the flip side, it could be argued that such centralized data collection is unethical and infringes the privacy rights of the patients.</p><h3><strong>Privacy Issues</strong></h3><p>So far, organizations, both large and small, have had little incentive to build privacy protected AI systems. Data breeches are becoming more common in recent years with little fallout for the companies responsible.¹</p><p>It is still not a common practice to hire a dedicated data governance officer within organizations who actively use AI applications that concerns with personal data storage. The psychographic profiling of Facebook users and its influence in 2016 USA presidential elections (Cambridge Analytica scandal) is one of the most popular examples that highlighted the concerns around privacy implications of AI use.</p><h3><strong>‘Mystery’ algorithms</strong></h3><p>Recent developments with deep learning and neural nets have made AI led predictions far more accurate. However, it has also made the system a black box because while it’s possible to interpret traditional ML and AI algorithms, deep learning algorithms are more complex and quite often, cannot be interpreted as to why or what features led to certain predictions. The interpretability issue affects people’s trust on deep learning systems. It is also related to many ethical problems, e.g., algorithmic discrimination.²</p><h3><strong>Personal reflections</strong></h3><p>Last few years have seen focussed initiatives that address some issues with AI. While the public is more sensitive to their privacy and data sharing rights, the organizations are swift to respond to public sentiments by giving more options to their customers. AI is coming of age in this era and the outlook is very promising.</p><p>I work as a data analyst in retail. Being familiar with some of the prominent use cases of AI in retail, I can comfortably say that at least in this industry, AI has so far shown more promise rather than concerns. Artificial intelligence has allowed marketers to process millions of data points together and get insights that can then be applied at demographic or group level. Sales and customer experience management have also benefited immensely from use of AI. With AI, it’s possible to apply heavy computation on large scale connecting several data points together. This is something which is beyond human calibre and was mostly unexplored before advent of AI and machine learning.</p><p>Use cases of AI in retail like hyper-personalization, allocation and replenishment and pricing and markdown etc. have been very popular lately and have also been widely adapted by the industry at every level.</p><p>The issues that can come up is more around ‘how’ rather than ‘what’ of applications of AI in retail. There is a growing concern about privacy of users and whether retailers should process demographic and behavioural data of their customers. Handling of personal identifiable information (PII) is subject to various regional laws (eg GDPR for Europe). These laws ensure citizen right to privacy but are not prevalent across the globe. Additionally, there is a risk that given need to large data ecosystem to train AI platforms, some large corporations start with obvious advantage in this area and could create a space of monopoly in this field. Amazon is a good example to keep an eye on in the following years.</p><h3>Looking ahead</h3><p>Hannah Fry mentions a trick in her fabulous book ‘Hello World’ that can help us spot the junk algorithms —</p><blockquote><em>whenever you see a story about an algorithm, see if you can swap out the buzzwords, like ‘machine learning’, and ‘artificial intelligence’, and swap in the word ‘magic’. Does everything still make grammatical sense? Is any of the meaning lost? If not, I’d be worried that something is wrong. Because — long into the future — we’re not going to ‘solve world hunger with magic’ or ‘use magic to write the perfect screenplay’ any more than we are with AI.³</em></blockquote><p>Acknowledging that algorithms aren’t perfect, any more than the humans are, might just have the effect of diminishing any assumptions of their authority. With that sort of limitations, AI systems should also be part of usual audit process that are applied to financial processes for example. Trained auditors should test these systems against potential risks of biases and publish the results on regular basis. Also, there is still huge potential to develop new skills through the human-machine symbiosis and address the missing middle gap.⁴</p><p>I already experience such skill gap even within the organizations that I have worked so far — there are AI creators (data scientists, machine learning engineers etc.) who create or code technical AI solutions. But they create most of their solutions for other group who are AI users. This group mostly comprises of business managers with little or no knowledge of how the solutions work and are mostly interested in the outcomes. Most often, creators and users don’t talk to each other and don’t even understand each other’s language. We need a link between them who can serve as a bridge between these groups and ensure that both these groups work towards goals that are more aligned to a common success objective. In other words, we need AI translators. This is going to be a most sought-after skill in the coming future.</p><h3>References:</h3><p>1 — <a href="https://www.isaca.org/resources/news-and-trends/isaca-now-blog/2021/beware-theprivacy-violations-in-artificial-intelligence-applications">https://www.isaca.org/resources/news-and-trends/isaca-now-blog/2021/beware-theprivacy-violations-in-artificial-intelligence-applications</a></p><p>2 — A Survey on Neural Network Interpretability — Yu Zhang, Peter Tiňo, Aleš Leonardis, Ke Tang | <a href="https://arxiv.org/abs/2012.14261">https://arxiv.org/abs/2012.14261</a></p><p>3 — Hanna Fry, Hello World ISBN 978–1–784–16306–8</p><p>4 — <a href="https://thedatalab.com/news/human-machine-combatting-myths/">https://thedatalab.com/news/human-machine-combatting-myths/</a> further references Human + Machine by James Wilson &amp; Paul Daugherty</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=32fcccc7d288" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Must know ML techniques for digital analysts: Part 3— Recommendation Engines]]></title>
            <link>https://medium.com/data-science/must-know-ml-techniques-for-digital-analysts-part-3-recommendation-engines-23713ae80b49?source=rss-9e994f9ef9cf------2</link>
            <guid isPermaLink="false">https://medium.com/p/23713ae80b49</guid>
            <category><![CDATA[data-science]]></category>
            <category><![CDATA[recommendation-system]]></category>
            <category><![CDATA[machine-learning]]></category>
            <dc:creator><![CDATA[Abhinav Sharma]]></dc:creator>
            <pubDate>Mon, 28 Sep 2020 14:17:57 GMT</pubDate>
            <atom:updated>2020-09-28T15:02:07.087Z</atom:updated>
            <content:encoded><![CDATA[<h4>Introduction to machine learning techniques that can help you to optimize your digital analytics value chain</h4><p>As a digital analyst for your organization, you are not supposed to write ML code for recommendation engines. However, even ML engineers who write these codes would rely on you in terms of visibility of how these engines are performing on the site. Additionally, the digital analytics team also influences the content placement and A/B testing of content (or different ML algorithms). So, some inherent knowledge of how recommendation engines actually work could be a valuable asset for you.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*7mJSE3L9zXD94qooU7GoQQ.png" /><figcaption>Amazon’s recommendation to me when I was browsing a certain book. Can you guess which one? Image by author</figcaption></figure><h3>Recommendation engines — an introduction</h3><p>The poster child for the advantages of a recommendation engine would companies like Amazon, Netflix, Tinder, etc. Your amazon homepage is the finest example of recommendations in practice. Rolling through the homepage you can find sections like<em> ‘Inspired by your shopping trends’, ‘Related to items you’ve viewed’ </em>etc. all of them being powered by recommendation engines in the background. Recommendation engines are not just limited to presenting similar products on the eCommerce pages. The engines have a more profound use of presenting relevant and personal (<em>right</em>) content to the <em>right</em> customers at <em>right </em>time using the <em>right</em> channel.</p><p>Beyond mapping products that were bought together, the use of recommenders can be extended to -</p><ul><li>Make recommendations based on customer demographics.</li><li>recommend based on a similarity between customers.</li><li>recommend based on product similarity.</li><li>recommend based on historical purchase profile of customers.</li></ul><p>Use cases for recommendation systems are not just limited to eCommerce but widely exist in domains like pharmaceuticals, finance, and Travel.</p><h3>Recommendation engine types</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*SFH1r7Ywou2KH8zJl0Xdfg.png" /><figcaption>image by author</figcaption></figure><p>Each of the techniques shown in the diagram may be used to build a recommender system model. Let’s briefly explore the various recommendation engine categories.</p><p><strong>Content-based filtering</strong>, recommends items by comparing product attributes and customer profile attributes. The attributes of each product are represented as a set of tags or terms — typically the words that occur in a product description document. The customer profile is represented with the same terms and built by analyzing the content of products that have been seen or rated by the customer. Typically, the content-based filtering method provides a list of top N recommendations based on some similarity scores.</p><p><strong>Collaborative filtering</strong> filters information by using the recommendations of other people. Given a database of user ratings for products, where a set of users have rated a set of products, collaborative filtering algorithms can give ratings for products yet to be rated by a particular user. This leverages the neighborhood information of the user to provide such recommendations. The underlying premise of the collaborative filtering algorithm is that if two users agree on ratings for a large set of items, they may tend to agree for other items too.</p><p>Collaborative filtering can be further classified into:</p><ul><li><strong>Memory-based</strong>: In this method, user rating information is used to compute the likeness between users or items. This computed likeness is then used to come up with recommendations. This differentiates from content-based recommendations where item/user metadata is used to calculate similarity scores rather than their feedback (eg. ratings).</li><li><strong>Model-based</strong>: Data mining methods are applied to recognize patterns in the data, and the learned patterns are then used to generate recommendations. We have already covered a popular technique of association mining using the apriori algorithm in <a href="https://towardsdatascience.com/ml-techniques-to-optimise-digital-analytics-part-1-association-analysis-2ab198d56181">Part 1</a>.</li><li>The latent factor approach leverages <strong>matrix factorization</strong> techniques to arrive at recommendations. Recently these methods have proved themselves superior to item-based and user-based recommender systems. This was one of the winning solutions in the famous Netflix recommendation competition.</li></ul><p>Finally, <strong>Hybrid filtering</strong> is the system where we combine more than one type of recommendation system to come up with final recommendations.</p><p>Singular-value decomposition approximation, most popular items, and SlopeOne are some other popular techniques that may be employed to build recommendation systems. Further learning on recommendation engines could be in the direction of exploring and studying these rarely-used techniques and applying them to real-world problems.</p><h3>Example Implementation</h3><p>For standalone implementation, both Python and R have packages that include the most popular recommendation techniques bundled together. <em>Recommenderlab</em> package in R is a one-stop-shop for building recommendation engines and provides awesome functionality to convert datasets into the required format and train/test ensemble of models. The recommender function contains the option to include parameters for different similarity scores that we want to choose.</p><p>As an example for this article, we will take a more organic approach and try to implement a content-based recommendation for a news aggregator website.</p><p>Consider the following use case -</p><p><strong><em>A news aggregator wants to solve the following problem: When a customer browses a particular article, what other articles should we suggest to him? The challenge is we don’t have any information about customer preferences. We are either looking at the customer for the first time or we don’t have any mechanism set up yet to capture customer interaction with our products/items.</em></strong></p><p>We will be pulling up data from a news aggregator dataset from UCI public repository.</p><p>when a user is browsing a particular news article, we need to give him other news articles as recommendations, based on:</p><ul><li>The text content of the title of the article he is currently reading</li><li>The publisher of this document</li><li>The category to which document belongs</li><li>The polarity of the document (something we will calculate based on the text content of the title)</li></ul><p>Polarity identification algorithms use text mining to get the document&#39;s opinion. We will use one such algorithm to get the polarity of our texts.<br>We need multiple similarity measures for this use case:</p><ul><li>Cosine distance/similarity for comparing words in two documents</li><li>For the polarity, a Manhattan distance measure</li><li>For the publisher and category, Jaccard’s distance</li></ul><p>Refer <a href="https://github.com/abhinav-sharma15/CF_Recommendation">GitHub</a> for the complete markdown of this project.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/9e219d3dc73c57abca11850760f29df4/href">https://medium.com/media/9e219d3dc73c57abca11850760f29df4/href</a></iframe><p>Here is the break down of the code -</p><p>The first part of the code (up to line 62) focusses on data wrangling, and then refining the dataset to contain only a fraction of data (for scaling down the project) and further focussing only on the top 100 publishers with the maximum number of articles.</p><h3>Similarity Index</h3><p>We use a bag-of-words representation of all article titles to measure their similarity scores. We use cosine distance as a similarity scoring measure because it is non-invariant to changes in the magnitude of values and will change if there are changes in the article.</p><p>The process involves:</p><ul><li>using tm package in R, creating a document term matrix (dtm) of all the articles.</li><li>use it to measure cosine distance between articles and return a document matrix.</li></ul><pre># cosine distance<br>sim.score &lt;- tcrossprod_simple_triplet_matrix(dtm)/(sqrt( row_sums(dtm^2) %*% t(row_sums(dtm^2)) ))</pre><pre>sim.score[1:10,1:10]</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*7iQOOmifYf79Y4q-xkLe0w.png" /><figcaption>image by author</figcaption></figure><h3>Search</h3><p>In this section, our aim is to filter the top 30 articles based on cosine similarity matches. So for example our current document is article ID 16947 titled “UPDATE 1-Ukraine crisis worries hammer German investor morale” by Reuters, then we pick up the top 30 matching articles based on cosine distance.</p><pre># merge title.df and other.df with match.refined:<br>match.refined &lt;- inner_join(match.refined, title.df,by = &quot;ID&quot;)<br>match.refined &lt;- inner_join(match.refined, others.df,by = &quot;ID&quot;)</pre><pre>head(match.refined)</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*CZob0-eSV7Y2nkRre56Bzw.png" /><figcaption>image by author</figcaption></figure><h3>Polarity Scores</h3><p>We leverage <em>sentimentr</em> package in R to measure sentiments of the top articles that we have collected. A score of -1 indicates that the sentence has a very negative polarity. A score of 1 means that the sentence is very positive. A score of 0 refers to the neutral nature of the sentence.</p><pre># update the match.refined data frame with the polarity scores:<br>match.refined$polarity &lt;- sentiment.score$sentiment<br>head(match.refined)</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*XV-S65NvQgKk51c2Lw67Rw.png" /><figcaption>image by author</figcaption></figure><h3>Jaccard’s distance</h3><p>We also use publisher and category similarity from the current article by measuring it via the Jaccard index. The Jaccard index measures the similarity between two sets and is a ratio of the size of the intersection and the size of the union of the participating sets. Here we have only had two elements, one for publisher and one for the category, so our union is 2. The numerator, by adding the two Boolean variables, we get the intersection. We also calculate the absolute difference (Manhattan distance) in the polarity values between the articles in the search results and our search article. We do a min/max normalization of the difference score,</p><pre># Jaccard&#39;s distance<br>match.refined$jaccard &lt;- (match.refined$is.publisher + match.refined$is.category)/2</pre><pre># Manhattan distance<br>match.refined$polaritydiff &lt;- abs(target.polarity - match.refined$polarity)</pre><pre>range01 &lt;- function(x){(x-min(x))/(max(x)-min(x))}<br>match.refined$polaritydiff &lt;- range01(unlist(match.refined$polaritydiff))<br></pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*7Irpv6Sr_zth8CDPBbmb_A.png" /><figcaption>image by author</figcaption></figure><h3>Fuzzy logic ranking</h3><p>Finally, we use these 3 scores to apply the fuzzy rule to the list and get rankings for our top 30 articles. Based on the interaction between the linguistic variables cosine, Jaccard, and polarity, the ranking linguistic variables are assigned different linguistic values. These interactions are defined as rules. Having defined the linguistic variables, linguistic values, and the membership function, we proceed to write down our fuzzy rules.</p><pre># The get.ranks function is applied in each row of match.refined to get the fuzzy ranking. Finally, we sort the results using this ranking.<br>get.ranks &lt;- function(dataframe){<br>  cosine =  as.numeric(dataframe[&#39;cosine&#39;])<br>  jaccard = as.numeric(dataframe[&#39;jaccard&#39;])<br>  polarity = as.numeric(dataframe[&#39;polaritydiff&#39;])<br>  fi &lt;- fuzzy_inference(ranking.system, list(cosine = cosine,  jaccard = jaccard, polarity=polarity))<br>  return(gset_defuzzify(fi, &quot;centroid&quot;))<br>  <br>}</pre><pre>match.refined$ranking &lt;- apply(match.refined, 1, get.ranks)<br>match.refined &lt;- match.refined[order(-match.refined$ranking),]<br>match.refined</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*sbOhjjgFr3dWKN4srG7RCw.png" /><figcaption>image by author</figcaption></figure><p>This brings us to the end of our design and implementation of a simple fuzzy-induced content-based recommendation system.</p><p><em>There is more to the story —</em></p><p><a href="https://towardsdatascience.com/ml-techniques-to-optimise-digital-analytics-part-1-association-analysis-2ab198d56181"><strong>Part 1 — Association Analysis</strong></a></p><p><a href="https://towardsdatascience.com/must-know-ml-techniques-for-digital-analysts-part-2-customer-lifetime-value-22cd7496beca"><strong>Part 2 — Customer Lifetime Value</strong></a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=23713ae80b49" width="1" height="1" alt=""><hr><p><a href="https://medium.com/data-science/must-know-ml-techniques-for-digital-analysts-part-3-recommendation-engines-23713ae80b49">Must know ML techniques for digital analysts: Part 3— Recommendation Engines</a> was originally published in <a href="https://medium.com/data-science">TDS Archive</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Must know ML techniques for digital analysts: Part 2 — Customer Lifetime Value]]></title>
            <link>https://medium.com/data-science/must-know-ml-techniques-for-digital-analysts-part-2-customer-lifetime-value-22cd7496beca?source=rss-9e994f9ef9cf------2</link>
            <guid isPermaLink="false">https://medium.com/p/22cd7496beca</guid>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[data-science]]></category>
            <dc:creator><![CDATA[Abhinav Sharma]]></dc:creator>
            <pubDate>Wed, 16 Sep 2020 13:09:52 GMT</pubDate>
            <atom:updated>2020-09-16T13:19:52.395Z</atom:updated>
            <content:encoded><![CDATA[<h3>Must know ML techniques for digital analysts: Part 2 — Customer Lifetime Value</h3><h4>Introduction to machine learning techniques that can help you to optimize your digital analytics value chain</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8ArOuiaSE4t7uk0WM5SDyw.png" /><figcaption>image by author</figcaption></figure><p>As pointed out in <a href="https://medium.com/@abhinavsharma_64776/ml-techniques-to-optimise-digital-analytics-part-1-association-analysis-2ab198d56181">Part 1</a> where we covered the concept of Association Analysis, analytics is increasingly becoming more augmented and relational. As a digital analyst, it&#39;s better for us to be aware of the connection between different data sources and be ready to produce much more than just descriptive analytics.</p><p>With this necessity in mind, we will cover another smart digital analytics concept — Customer Lifetime Value.</p><h3>Calculating Lifetime Value</h3><p>Customer lifetime value (CLV) is the discounted sum of future cash flows attributed to the relationship with a customer. CLV estimates the ‘profit’ that an organization will derive from a customer in the future. The CLV can be used to evaluate the amount of money that can reasonably be devoted to customer acquisition. Even without considering the dollar value, CLV modeling still helps in identifying the most important (aka. profitable) customer segments which can then receive different treatment in terms of the acquisition strategy.</p><p>The taxonomy of CLV models depends much on the nature of the business. If the business has a <em>contractual relationship </em>(eg. subscription model) with customers then the most important issue in these situations is retaining customers over time, and survival analysis models are used to study the time until a customer cancels. These models are sometimes also referred to as <em>‘gone for good’ </em>models because the models assume customers who cancel the service will not return.</p><p>A simplistic CLV formula for a typical ‘gone for good’ models -</p><blockquote>The CLV formula multiplies the per-period cash margin, <em>$M</em>, by a long-term multiplier that represents the present value of the customer relationship’s expected length:</blockquote><blockquote>CLV = $M [r / 1 + d-r]</blockquote><blockquote>where <em>r</em> is the per-period retention rate and <em>d</em> is the per-period discount rate.</blockquote><p>The other main class of CLV models is called <em>‘always a share.’</em> These models do not assume that customer inactivity implies the customer will never return. For example, a retail customer who does not buy this month might come back next month.</p><blockquote>It is these types of CLV models that are most relevant for an online retail business setup where users engage with the business at will, such as in e-commerce stores in which users might make purchases at any time.</blockquote><p>In this article, I elaborate on one of the models that can be utilized to predict future CLV based on the customer’s historical transactions with the business. The model that is described in this series is best applied to predict the future value for existing customers who have at least a moderate amount of transaction history.</p><h3>Buy Till you Die Probabilistic models for CLV</h3><p>The BTYD models capture the non-contractual purchasing behavior of customers — or, more simply, models that tell the story of people buying until they die (become inactive as customers).</p><p>There are 2 models widely used -</p><ul><li><strong>Pareto/NBD</strong></li><li><strong>BG/NBD</strong></li></ul><p>The BG/NBD (Beta Geometric Negative Binomial Distribution) model is easier to implement than Pareto/NBD and runs faster (I am intentionally being naive). The two models tend to yield similar results. These models assume probabilistic distribution of rates at which customers make purchases and the rate at which they drop out. The modeling is based on four parameters that describe these assumptions.</p><p>Statistical introduction to the assumptions is important but out of the scope of this article. A high-level idea to keep in mind is that these models assume that the interactions of the customers with your business should be at their own will (in other words, random for your interpretation). If you have any influence (campaigns or promotional offers) in acquiring your customers, then that sort of historical data is not ideal to fit in these models.</p><h3>Example Implementation</h3><p>Let&#39;s consider the following scenario -</p><p><em>A retailer is re-strategizing their CPC ads. They want to understand who their most profitable customers are and what is the demography of this ideal customer. Eventually, they want to better target their CPC ads to get the most profitable customers possible. They have provided you with the last couple of years of transaction data and expect and output in terms of three customer buckets — high, medium, and low value. They expect to feed this customer value identifier back to their data lake and understand more about associated demographies for each bucket.</em></p><p>We apply the model on a public dataset (details in citation). The dataset has transactions for the year 2010–11. We will first be preparing the data to shape it in the expected ‘event log’ format for the model. An event log is basically a log of each customer’s purchase with a record of revenue and timestamp associated with it. We will then be using a probabilistic model to calculate CLV. The data is enough to extract <strong>Recency, Frequency, and Monetary (RFM)</strong> values. The solution here uses an existing BTYD library in R.</p><p>Please refer my <a href="https://github.com/abhinav-sharma15/Customer-Lifetime-Value">GitHub</a> for complete code -</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/0f847b0104e38813f796da617e2dbdd4/href">https://medium.com/media/0f847b0104e38813f796da617e2dbdd4/href</a></iframe><p>Leaving out the upload and data cleaning part (where we convert the dataset into event log format), here is the breakdown of the remaining code —</p><h3>Weekly transaction Analysis</h3><p>Methods elog2cum and elog2inc take an event log as a first argument and count for each time unit the cumulated or incremental number of transactions. If the argument first is set to TRUE, then a customer’s initial transaction will be included, otherwise not.</p><pre>op &lt;- par(mfrow = c(1, 2), mar = c(2.5, 2.5, 2.5, 2.5))<br><em># incremental</em><br>weekly_inc_total &lt;- elog2inc(elog, by = 7, first = TRUE)<br>weekly_inc_repeat &lt;- elog2inc(elog, by = 7, first = FALSE)<br>plot(weekly_inc_total, typ = &quot;l&quot;, frame = FALSE, main = &quot;Incremental&quot;)<br>lines(weekly_inc_repeat, col = &quot;red&quot;)<br><em># commualtive</em><br>weekly_cum_total &lt;- elog2cum(elog, by = 7, first = TRUE)<br>weekly_cum_repeat &lt;- elog2cum(elog, by = 7, first = FALSE)<br>plot(weekly_cum_total, typ = &quot;l&quot;, frame = FALSE, main = &quot;Cumulative&quot;)<br>lines(weekly_cum_repeat, col = &quot;red&quot;)</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*llZ1NoiqZY3o6EPyopefRQ.png" /><figcaption>image by author</figcaption></figure><p>Further, we need to convert the event log into a <strong>customer-by-sufficient-statistic (CBS)</strong> format. The elog2cbs method is an efficient implementation for the conversion of an event log into CBS data.frame, with a row for each customer. This is the required data format for estimating model parameters. Argument T.cal allows one to calculate the summary statistics for a calibration and a holdout period separately.</p><p>Instead of realistic calibration and holdout, I would like to use T.cal to sample only transactions before the holiday shopping for 2011, where there is an incremental spike. This will keep the estimated parameters realistic for future predictions.</p><pre>calibration_cbs = elog2cbs(elog, units = &quot;week&quot;, T.cal = &quot;2011-10-01&quot;)<br>head(calibration_cbs)</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*G4p9wj2XcsTHdOHAliV1pg.png" /><figcaption>image by author</figcaption></figure><p>The returned field cust is the unique customer identifier, x the number of repeat transactions (i.e., frequency), t.x the time of the last recorded transaction (i.e., recency), litt the sum over logarithmic intertransaction times (required for estimating regularity), first the date of the first transaction, and T.cal the duration between the first transaction and the end of the calibration period. The time unit for expressing t.x, T.cal and litt are determined via the argument units, which is passed forward to method difftime, and defaults to weeks. Only those customers are contained, who have had at least one event during the calibration period.</p><ul><li>cust: Customer id (unique key).</li><li>x: Number of recurring events in calibration period.</li><li>t.x: Time between first and last event in calibration period.</li><li>litt: Sum of logarithmic intertransaction timings during calibration period.</li><li>sales: Sum of sales in calibration period, incl. initial transaction.</li><li>first: Date of first transaction in calibration period.</li><li>T.cal: Time between first event and end of calibration period.</li><li>T.star: Length of holdout period.</li><li>x.star: Number of events within holdout period.</li><li>sales.star: Sum of sales within holdout period.</li></ul><p>Estimating the parameter values of the BG/NBD process.</p><pre><em># estimate parameters for various models</em><br>params.bgnbd &lt;- BTYD::bgnbd.EstimateParameters(calibration_cbs) <em># BG/NBD</em><br>row &lt;- <strong>function</strong>(params, LL) {<br>names(params) &lt;- c(&quot;k&quot;, &quot;r&quot;, &quot;alpha&quot;, &quot;a&quot;, &quot;b&quot;)<br>c(round(params, 3), LL = round(LL))<br>}<br>rbind(`BG/NBD` = row(c(1, params.bgnbd),<br>BTYD::bgnbd.cbs.LL(params.bgnbd, calibration_cbs)))</pre><pre>##        k     r alpha     a     b     LL<br>## BG/NBD 1 0.775 7.661 0.035 0.598 -29637</pre><h3>Predicting on holdout period</h3><pre><em># predicting on holdout</em><br>calibration_cbs$xstar.bgnbd &lt;- bgnbd.ConditionalExpectedTransactions(<br>params = params.bgnbd, T.star = 9,<br>x = calibration_cbs$x, t.x = calibration_cbs$t.x,<br>T.cal = calibration_cbs$T.cal)<br><em># compare predictions with actuals at aggregated level</em><br>rbind(`Actuals` = c(`Holdout` = sum(calibration_cbs$x.star)),<br>`BG/NBD` = c(`Holdout` = round(sum(calibration_cbs$xstar.bgnbd))))</pre><pre>##         Holdout<br>## Actuals    4308<br>## BG/NBD     2995</pre><p>Comparing the predictions at an aggregate level, we see that the BG/NBD ‘under predicts’ for the dataset. That is attributed to the high jump in transactions during the holdout period (Nov and Dec 2011). The aggregate level dynamics can be visualized with the help of bgcnbd.PlotTrackingInc</p><pre>nil &lt;- bgnbd.PlotTrackingInc(params.bgnbd,<br>T.cal = calibration_cbs$T.cal,<br>T.tot = max(calibration_cbs$T.cal + calibration_cbs$T.star),<br>actual.inc.tracking = elog2inc(elog))</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*T1m2H3C2oYV3aNRT.png" /><figcaption>image by author</figcaption></figure><p>In case testing the model, we can use the holdout period to calculate MAE</p><pre><em># mean absolute error (MAE)</em><br>mae &lt;- <strong>function</strong>(act, est) {<br>stopifnot(length(act)==length(est))<br>sum(abs(act-est)) / sum(act)<br>}<br>mae.bgnbd &lt;- mae(calibration_cbs$x.star, calibration_cbs$xstar.bgnbd)<br>rbind(<br>`BG/NBD` = c(`MAE` = round(mae.bgnbd, 3)))</pre><pre>##          MAE<br>## BG/NBD 0.769</pre><h3>Parameters for gamma spend</h3><p>Now we need to develop a model for the average transaction value for a customer. We will use a two-layered hierarchical model. The average transaction value will be Gamma distributed with shape parameter <em>p</em>. The scale parameter of this Gamma distribution is also Gamma distributed, with shape and scale parameters <em>q</em> and $$, respectively. Estimating these parameters requires the data to be in a slightly different format than the cbs format we used for the BG/NBD model. Instead, we simply need the average transaction value and the total number of transactions for each customer. This is easily obtained using dplyr notation on the elog object.</p><pre>spend_df = elog %&gt;%<br>    group_by(cust) %&gt;%<br>    summarise(average_spend = mean(sales),<br>              total_transactions = n())</pre><pre>## `summarise()` ungrouping output (override with `.groups` argument)</pre><pre>spend_df$average_spend &lt;- as.integer(spend_df$average_spend)<br>spend_df &lt;- filter(spend_df, spend_df$average_spend&gt;0)<br>  <br>  head(spend_df)</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*7XKfDjk7owstWRVNdCOv6w.png" /><figcaption>image by author</figcaption></figure><p>Now let’s plug this formatted data into the spend.EstimateParameters() function from the BTYD package to get the parameter values for our Gamma-Gamma spend model.</p><pre>gg_params = spend.EstimateParameters(spend_df$average_spend, <br>                                       spend_df$total_transactions)<br>  gg_params</pre><pre>## [1]   2.619805   3.346577 313.666656</pre><h3>Applying the model to the entire cohort</h3><p>With all the parameters needed to understand the transaction and average revenue behavior, we can now apply this model to our entire cohort of customers. To do so, we will need to create a cbs data frame for our entire data set (i.e., no calibration period). We can make use of the elog2cbs() function again, but omit the calibration_date argument. We can then calculate expected transactions and average transaction value for the next 12 weeks for each customer.</p><pre>customer_cbs = elog2cbs(elog, units = &quot;week&quot;)<br>customer_expected_trans &lt;- data.frame(cust = customer_cbs$cust,<br>                                      expected_transactions = <br>                                        bgnbd.ConditionalExpectedTransactions(params = params.bgnbd,<br>                                                                              T.star = 12,<br>                                                                              x = customer_cbs[,&#39;x&#39;],<br>                                                                              t.x = customer_cbs[,&#39;t.x&#39;],<br>                                                                              T.cal  = customer_cbs[,&#39;T.cal&#39;]))<br>customer_spend = elog %&gt;%<br>  group_by(cust) %&gt;%<br>  summarise(average_spend = mean(sales),<br>            total_transactions = n())</pre><pre>## `summarise()` ungrouping output (override with `.groups` argument)</pre><pre>customer_spend &lt;- filter(customer_spend, customer_spend$average_spend&gt;0)<br>customer_expected_spend = data.frame(cust = customer_spend$cust,<br>                                     average_expected_spend = <br>                                        spend.expected.value(gg_params,<br>                                                             m.x = customer_spend$average_spend,<br>                                                             x = customer_spend$total_transactions))</pre><p>Combining these two data frames together gives us the next three month’s worth of customer value for each person in our data set. We can further bucket them into high, medium, and low categories.</p><pre>merged_customer_data = customer_expected_trans %&gt;%<br>  full_join(customer_expected_spend) %&gt;%<br>  mutate(clv = expected_transactions * average_expected_spend,<br>         clv_bin = case_when(clv &gt;= quantile(clv, .9, na.rm = TRUE) ~ &quot;high&quot;,<br>                             clv &gt;= quantile(clv, .5, na.rm = TRUE) ~ &quot;medium&quot;,<br>                             TRUE ~ &quot;low&quot;))</pre><pre>merged_customer_data %&gt;%<br>  group_by(clv_bin) %&gt;%<br>  summarise(n = n())</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ZuAxvtQCTEiIEbEAOnPz2w.png" /><figcaption>image by author</figcaption></figure><p>Combining historical spend and forecast together and saving it as an output csv —</p><pre>customer_clv &lt;- left_join(spend_df, merged_customer_data, by =&quot;cust&quot;)<br>head(customer_clv)<br>write.csv(customer_clv, &quot;clv_output.csv&quot;)</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*0YwsPJBJvaZK--JohAvmMw.png" /><figcaption>image by author</figcaption></figure><h3>Plot of CLV Clusters</h3><pre><br>customer_clv  %&gt;% <br>    ggplot(aes(x = total_transactions,<br>               y = average_spend,<br>               col = as.factor(clv_bin),<br>               shape = clv_bin))+<br>    geom_point(size = 4,alpha = 0.5)</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*tq3-Ff0H1oXD_y2w.png" /><figcaption>image by author</figcaption></figure><p>The output csv can now be fed back to and merged with the customer database. The clv bucket metric will then be available for breaking down in terms of other demographic or behavioral information.</p><h3>Citation</h3><p>Daqing Chen, Sai Liang Sain, and Kun Guo, Data mining for the online retail industry: A case study of RFM model-based customer segmentation using data mining, Journal of Database Marketing and Customer Strategy Management, Vol. 19, №3, pp. 197â€“208, 2012 (Published online before print: 27 August 2012. doi: 10.1057/dbm.2012.17).</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=22cd7496beca" width="1" height="1" alt=""><hr><p><a href="https://medium.com/data-science/must-know-ml-techniques-for-digital-analysts-part-2-customer-lifetime-value-22cd7496beca">Must know ML techniques for digital analysts: Part 2 — Customer Lifetime Value</a> was originally published in <a href="https://medium.com/data-science">TDS Archive</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Must know ML techniques for digital analysts — Part 1: Association Analysis]]></title>
            <link>https://medium.com/data-science/ml-techniques-to-optimise-digital-analytics-part-1-association-analysis-2ab198d56181?source=rss-9e994f9ef9cf------2</link>
            <guid isPermaLink="false">https://medium.com/p/2ab198d56181</guid>
            <category><![CDATA[association]]></category>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[digital-analytics]]></category>
            <category><![CDATA[web-analytics]]></category>
            <dc:creator><![CDATA[Abhinav Sharma]]></dc:creator>
            <pubDate>Tue, 08 Sep 2020 10:39:45 GMT</pubDate>
            <atom:updated>2020-09-15T20:25:37.987Z</atom:updated>
            <content:encoded><![CDATA[<h3>Must know ML techniques for digital analysts — Part 1: Association Analysis</h3><h4>Introduction to machine learning techniques that can help you to optimize your digital analytics value chain</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*2skuyk1JOdmayYrAGvsZlA.png" /><figcaption>Data Science processes across the digital analytics value chain. Image by author</figcaption></figure><p>Business users are increasingly becoming self-service on basic digital analysis and reporting. If you are a digital analyst, it will be a smart move to start to expand/shift towards data science now and be equipped to offer more than basic analysis and dash-boarding.</p><p>This was my motivation to learn, apply, and eventually share knowledge around these data science techniques that have been part of incremental data analysis long before “data science” was a buzz word.</p><p>My approach would be to explain the concept and the use cases it can cover. I will highlight the prerequisites and follow it up with a decent example. My example implementations will be programmed in R.</p><p>In this part 1, I talk about <strong>Association Analysis</strong> more popularly referred to as <strong>Market Basket Analysis</strong>. This analysis is relevant for retail and other setups, where a user can add to and eventually purchase multiple products, from a shopping cart. The objective is to better understand what sort of products or items go together well and use that information for better cross-selling, merchandising, or targeted offers.</p><h3>Associations: Finding Items That Go Together</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*rmrPxA-YxzOCmxBZJu1Kqg.jpeg" /><figcaption>photo by <a href="https://unsplash.com/@davidveksler">David Veksler</a> on <a href="https://unsplash.com/">Unsplash</a></figcaption></figure><p>Association analysis is a statistical technique that helps you identify top association rules between your products.</p><blockquote>What is an association rule? An example from a grocery transaction would be that the association rule is a recommendation of the form {peanut butter, jelly} =&gt; { bread }. It says that, based on the transactions, it’s expected that bread will most likely be present in a transaction that contains peanut butter and jelly. It’s a recommendation to the retailer that there is enough evidence in the database to say that customers who buy peanut butter and jelly will most likely buy bread.</blockquote><p>Association Analysis is simply a search through the data for combinations of items whose statistics are <em>interesting.</em> It helps us establish rules dictating something like <em>“If A occurs then B is likely to occur as well.”</em></p><p>But, what are these interesting stats that we have to look for and how should we set their values/thresholds?</p><h3><strong>Association parameters (interesting statistics!)</strong></h3><p>First, we need to consider complexity control: there are likely to be a tremendous number of co-occurrences, many of which might simply be due to chance, rather than to a generalizable pattern. A simple way to control complexity is to place a constraint that such rules must apply to some minimum percentage of the data — let’s say that we require rules to apply to at least 0.01% of all transactions. This is called the <strong>support</strong> of the association.</p><p>We also have the notion of “likely” in the association. If a customer buys the jelly then she is likely to buy the bread. Again, we may want to require a certain minimum degree of likelihood for the associations we find. The probability that B occurs when A; it is p(B|A), which in association mining is called the <strong>confidence</strong> of the rule (not to confuse it with statistical confidence). So we might say we require the confidence to be above some threshold, such as 5% (so that 5% or more of the time, a buyer of A also buys B).</p><p>Just Support and Confidence as a parameter might be misleading for items that are too common/ popular in the basket. It is more likely that popular items are part of the same basket just because they are popular rather than anything else. We need some measure of “surprise” for association analysis. Lift and Leverage are two parameters providing that. The<strong> lift </strong>of the co-occurrence of A and B is the probability that we actually see the two together, compared to the probability that we would see the two together if they were unrelated to (independent of) each other. As with other uses of the lift we’ve seen, a lift greater than one is the factor by which seeing A “boosts” the likelihood of seeing B as well. An alternative is to look at the difference between these quantities rather than their ratio. This measure is called <strong>leverage</strong>.</p><p>So, for any items A and B in a transaction -</p><p>Support=p(A⋂B)</p><p>Confidence=p(A|B) or p(A⋂B)/p(A)</p><p>Lift(A,B)=p(A⋂B)/p(A)p(B)</p><p>Leverage(A,B)=p(A⋂B)−p(A)p(B)</p><blockquote><strong>As a Market basket analyst, your job is to search for rules with a lift that are greater than 1 backed with high confidence values and often, high support.</strong></blockquote><h3>Other Applications</h3><p>Since we’re using the market basket as an analogy at this point, we should consider broadening our thinking of what might be an item. Why can’t we put just about anything we might be interested in finding associations with into our “basket”? For example, we might put a user’s location into the basket, and then we could see associations between purchase behavior and locations. For actual market basket data, these sometimes are called virtual items, to distinguish from the actual items that people put into their basket in the store. Association analysis finds and tells us statistically significant observations like <em>“If A occurs then B is likely to occur as well.”</em> Now, we can replace anything for A and B provided they happened together (can be basketed).</p><p>With the above logic, we have several other applications of association analysis beyond cross-sell opportunities in online e-commerce. It can help us answer questions like:</p><ul><li>What seasonal or brand factors contribute towards product mix in the basket? The product mix that the association analysis highlights could vary for different industries. For example, it could be the origin and destination cities for travel operators.</li><li>Is the mix of products different for customers who purchase on their mobile device? What products are they more or less likely to purchase?</li></ul><h3>Apriori algorithm</h3><p>There are several algorithmic implementations for association rule mining. Key among them is the apriori algorithm by Rakesh Agrawal and Ramakrishnan Srikanth, introduced in their paper, <em>Fast Algorithms for Mining Association Rules.</em></p><blockquote>The Apriori algorithm is a commonly-applied technique in computational statistics that identifies itemsets that occur with a support greater than a pre-defined value (frequency) and calculates the confidence of all possible rules based on those itemsets.</blockquote><p>The Apriori algorithm is implemented in the <em>arules</em> package, which can be installed and run in R.</p><h3>Transactions</h3><p>The algorithm takes as input, transactional data. Transactions are purchases made by a customer on a single visit to a retail store. Typically, transaction data can include the products purchased, quantity purchased, the price, discount, if applied, and a timestamp. A single transaction can include multiple products. It may register information about the user who made the transaction in some cases, where the customer allows the retailer to store his information by joining a rewards program. For mining, the transaction data is first transformed into a binary purchase incidence matrix with columns corresponding to the different items and rows corresponding to transactions. The matrix entries represent the presence (1) or absence (0) of an item in a particular transaction.</p><h3>Example Implementation</h3><p>Association mining is based on probability measures hence generating reliable insights from analysis typically requires large volumes of transactional data. Large data sets are difficult to process without highly-scalable storage and compute resources. Usually, you will be doing this exercise sourcing data from your data lake using cloud-based architecture however the inherent principles will remain the same and your objective will be to get data in a transactional format to apply this rule. R has packages to connect to most of the systems and you can even use SQL for data wrangling.</p><p>Let&#39;s consider the following scenario -</p><p><em>A retailer is planning a marketing campaign on a large scale to promote sales. One aspect of his campaign is the cross-selling strategy. Cross-selling is the practice of selling additional products to customers. In order to do that, he wants to know what items/products tend to go together. Equipped with this information, he can now design his cross-selling strategy. He expects us to provide him with a recommendation of top N product associations so that he can pick and choose among them for inclusion in his campaign.</em></p><p>We will implement a project where we will apply association rule mining to a retail dataset with the final objective of recommending cross-sell items. This project is based on a dataset released by Instacart in 2017. They released over 3 million anonymized orders for the machine learning community to try hands-on. I will be using a subset training dataset for association rule mining (assuming our cross-sell use case). We will have to do some initial data wrangling to get the desired transaction format. Please refer citation below for dataset related information.</p><p>Refer <a href="https://github.com/abhinav-sharma15/market-basket-analysis-instacart">github</a> for the complete code of this project.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/9d9ab74d95da6267cb01d33102cef4a2/href">https://medium.com/media/9d9ab74d95da6267cb01d33102cef4a2/href</a></iframe><p>Here is the break down of the code -</p><p>loading the required libraries</p><pre><strong>library</strong>(dplyr)<br><strong>library</strong>(arules)<br><strong>library</strong>(arulesViz)</pre><h3>Data wrangling</h3><p>We are provided with 2 files. An orders csv with around 131k orders with order ID and product ID observations and a product file with product ID and product name mapping. First, we will create a transaction dataset containing order ID and associated product name.</p><pre><em># Orders csv</em><br>file1.path = &quot;./order_products__train.csv&quot;<br>orders = read.csv(file1.path)<br>head(orders)</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*hu0niXqoDGRDd5sl9_Jd9w.png" /><figcaption>image by author</figcaption></figure><pre><em># Products csv</em><br>file2.path = &quot;./products.csv&quot;<br>products = read.csv(file2.path)<br>head(products)</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*QG1UfNYCqNaIx3R90F-zSw.png" /><figcaption>image by author</figcaption></figure><p>Combining both of them and forming a single transaction dataset -</p><pre><em># Combining both of them and forming a single transaction dataset -</em><br>data = left_join(orders, products, by = &quot;product_id&quot;) %&gt;% select(order_id, product_name)<br>head(data,50)</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ZwLHQx1wzAwXM78dfHr0IQ.png" /><figcaption>image by author</figcaption></figure><p>Let’s quickly explore our data. We can count the number of unique transactions and the number of unique products:</p><pre><em># We can count the number of unique transactions and the number of unique products</em><br>data %&gt;%<br> group_by(&#39;order_id&#39;) %&gt;%<br> summarize(order.count = n_distinct(order_id))</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*eKrdTSbdubpMhHJBo2_4_w.png" /><figcaption>image by author</figcaption></figure><pre>data %&gt;%<br> group_by(&#39;product_name&#39;) %&gt;%<br> summarize(product.count = n_distinct(product_name))</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*J3XyvkaNY-CKoCOjhAgsOA.png" /><figcaption>image by author</figcaption></figure><p>We have 131209 transactions and 39123 individual products. There is no information about the number of products purchased in a transaction. We have used the dplyr library to perform these aggregate calculations, which is a library used to perform efficient data wrangling on data frames.</p><p>writing it back to csv</p><pre><em># writing it back to csv</em><br>write.table(data,file =  &quot;./data.csv&quot;, row.names = FALSE, sep = &quot;;&quot;, quote = FALSE)</pre><h3>Association Rule Mining</h3><p>We begin with reading our transactions stored in the data frame and create an arules data structure called transactions.</p><pre><em># create an arules data structure called transactions</em><br>data.path = &quot;./data.csv&quot;<br>transactions.obj &lt;- read.transactions(file = data.path, format = &quot;single&quot;,<br> sep = &quot;;&quot;,<br> header = TRUE,<br> cols = c(&quot;order_id&quot;, &quot;product_name&quot;),<br> rm.duplicates = FALSE,<br> quote = &quot;&quot;, skip = 0,<br> encoding = &quot;unknown&quot;)</pre><p>Looking at the parameters of read.transactions, the function used to create the transactions object. For the first parameter, file, we pass our file where we have the transactions from the retailer. The second parameter, format, can take any of two values, single or basket, depending on how the input data is organized. In our case, we have a tabular format with two columns–one column representing the unique identifier for our transaction and the other column for a unique identifier representing the product present in our transaction. This format is named single by arules. Refer to the arules documentation for a detailed description of all the parameters.</p><p>On inspecting the newly created transactions object transaction.obj:</p><pre><em># inspecting the newly created transactions object transaction.obj</em><br>transactions.obj</pre><pre>## transactions in sparse format with<br>##  131209 transactions (rows) and<br>##  39121 items (columns)</pre><p>We can see that there are 131209 transactions and 39121 products. They match the previous count values from the dplyr output.</p><p>We can explore the most frequent items, that is, the items that are present in most of the transactions and vice versa — the least frequent items and the items present in many fewer transactions?</p><p>The itemFrequency function in the arules package comes to our rescue. This function takes a transaction object as input and produces the frequency count (the number of transactions containing this product) of the individual products:</p><pre>data.frame(head(sort(itemFrequency(transactions.obj, type = &quot;absolute&quot;), decreasing = TRUE), 10)) <em># Most frequent</em></pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Ulvk5-7NmI0LznqoMCwbhw.png" /><figcaption>image by author</figcaption></figure><pre>data.frame(head(sort(itemFrequency(transactions.obj, type = &quot;absolute&quot;), decreasing = FALSE), 10)) <em># Least frequent</em></pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*iDF5uXfgB9vkk7IvhBgy5g.png" /><figcaption>image by author</figcaption></figure><p>In the preceding code, we print the most and the least frequent items in our database using the itemFrequency function. The itemFrequency function produces all the items with their corresponding frequency and the number of transactions in which they appear. We wrap the sort function over itemFrequency to sort this output; the sorting order is decided by the decreasing parameter. When set to TRUE, it sorts the items in descending order based on their transaction frequency. We finally wrap the sort function using the head function to get the top 10 most/least frequent items.</p><p>The Banana product is the most frequently occurring across 18726 transactions. The itemFrequency method can also return the percentage of transactions rather than an absolute number if we set the type parameter to relative instead of absolute.</p><p><em>The purpose of this project is to focus on the method rather than the output. If you will refer to the dataset source — the dataset includes orders from many different retailers and is a heavily biased subset of Instacart’s production data, and so is not a representative sample of their products, users, or their purchasing behavior.</em></p><p>Another convenient way to inspect the frequency distribution of the items is to plot them visually as a histogram. The arules package provides the itemFrequencyPlot function to visualize the item frequency:</p><pre><em># itemFrequencyPlot function to visualize the item frequency</em><br>itemFrequencyPlot(transactions.obj,topN = 25)</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ABVuM8tY-eCoNNjns5By6A.png" /><figcaption>image by author</figcaption></figure><blockquote>The item frequency plot should give us some idea about the threshold that we should maintain for support. Usually, we should select a support threshold where the long tail starts.</blockquote><p>Now that we have successfully created the transaction object, let’s proceed to apply the apriori algorithm to this transaction object.</p><p>The apriori algorithm works in two phases. Finding frequent itemsets is the first phase of the association rule mining algorithm. A group of product IDs is called an itemset. The algorithm makes multiple passes into the database; in the first pass, it finds out the transaction frequency of all the individual items. These are itemsets of order 1. We will introduce the first interest measure, Support, here.</p><p>Now, in the first pass, the algorithm calculates the transaction frequency for each product. At this stage, we have order 1 itemsets. We will discard all those itemsets that fall below our support threshold. The assumption here is that items with a high transaction frequency are more interesting than the ones with a very low frequency. Items with very low support are not going to make for interesting rules further down the pipeline. Using the most frequent items, we can construct the itemsets as having two products and find their transaction frequency, that is, the number of transactions in which both the items are present. Once again, we discard all the two product itemsets (itemsets of order 2) that are below the given support threshold. We continue this way until we have exhausted them.</p><pre><em># Interest Measures</em><br> support &lt;- 0.005<br><em># Frequent item sets</em><br> parameters = list(<br> support = support,<br> minlen = 2, <em># Minimal number of items per item set</em><br> maxlen = 10, <em># Maximal number of items per item set</em><br> target = &quot;frequent itemsets&quot;)<br> freq.items &lt;- apriori(transactions.obj, parameter = parameters)</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*72WRPBHbG23ZCA7-yeBTmQ.png" /><figcaption>image by author</figcaption></figure><p>The apriori method is used in arules to get the most frequent items. This method takes two parameters, the transaction.obj and the second parameter, which is a named list. We create a named list called parameters. Inside the named list, we have an entry for our support threshold. We have set our support threshold to 0.005, namely, one percent of the transaction. We settled at this value by looking at the histogram we plotted earlier. By setting the value of the target parameter to frequent itemsets, we specify that we expect the method to return the final frequent itemsets. Minlen and maxlen set lower and upper cut off on how many items we expect in our itemsets. By setting our minlen to 2, we say we don’t want itemsets of order 1. While explaining the apriori in phase 1, we said that the algorithm can do many passes into the database, and each subsequent pass creates itemsets that are of order 1, greater than the previous pass. We also said apriori ends when no higher-order itemsets can be found. We don’t want our method to run till the end, hence by using maxlen, we say that if we reach itemsets of order 10, we stop. The apriori function returns an object of type itemsets.</p><p>It’s good practice to examine the created object, itemset in this case. A closer look at the itemset object should shed light on how we ended up using its properties to create our data frame of itemsets:</p><pre>str(freq.items)</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*_92ptaH1EYyDdny-JEVnJw.png" /><figcaption>image by author</figcaption></figure><p>By calling the function label and passing the freq.items object, we retrieve the item names:</p><pre><em># Let us examine our freq item sites</em><br> freq.items.df &lt;- data.frame(item_set = labels(freq.items)<br> , support = freq.items@quality)<br>head(freq.items.df,10)</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*v2QkTznIKMjThQ7p4j0O6g.png" /><figcaption>image by author</figcaption></figure><p>Let’s move on to phase two, where we will induce rules from these itemsets. It’s time to introduce our second interest measure, confidence. Let’s take an itemset from the list given to us from phase one of the algorithm, {Banana, Blueberries}.</p><p>We have two possible rules here:</p><p>Banana =&gt; Blueberries: The presence of Banana in a transaction strongly suggests that Blueberries will also be there in the same transaction. Blueberries =&gt; Banana: The presence of Blueberries in a transaction strongly suggests that Banana will also be there in the same transaction. How often are these two rules found to be true in our database? The confidence score, our next interest measure, will help us measure this:</p><pre>confidence &lt;- 0.2 <em># Interest Measure</em><br> <br> parameters = list(<br> support = support,<br> confidence = confidence,<br> minlen = 2, <em># Minimal number of items per item set</em><br> maxlen = 10, <em># Maximal number of items per item set</em><br> target = &quot;rules&quot;<br> )<br>rules &lt;- apriori(transactions.obj, parameter = parameters)</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*P1xGQRhRH-a59nZ5JZA9iw.png" /><figcaption>image by author</figcaption></figure><p>Once again, we use the apriori method; however, we set the target parameter in our parameters named list to rules. Additionally, we also provide a confidence threshold. After calling the method apriori using the returned object rules, we finally build our data frame, rules.df, to explore/view our rules conveniently. Let’s look at our output data frame, rules.df. For the given confidence threshold, we can see the set of rules thrown out by the algorithm:</p><pre><em># output data frame, rules.df</em><br>rules.df &lt;- data.frame(rules = labels(rules), rules@quality)<br>head(rules.df)</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*fcBY6RViQOjOsi5rDYKktA.png" /><figcaption>image by author</figcaption></figure><p>Lift is also reflected as another interest measure in the dataframe.</p><p>Alright, we have successfully implemented our association rule mining algorithm; we went under the hood to understand how the algorithm works in two phases to generate rules. We have examined three interest measures: support, confidence, and lift. Finally, we know that the lift can be leveraged to make cross-selling recommendations to our retail customers.</p><p>Given the rule A =&gt; B, we explained that lift calculates how many times A and B occur together more often than expected. There are other ways of testing this independence, like a chi-square test or a Fisher’s test. The arules package provides the is.significant method to do a Fisher or a chi-square test of independence. The parameter method can either take the value of fisher or chisq depending on the test we wish to perform.</p><pre><em># is.significant method to do a Fisher test of independence</em><br>is.significant(rules, transactions.obj, method = &quot;fisher&quot;)</pre><pre>##  [1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE<br>## [15] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE<br>## [29] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE<br>## [43] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE</pre><p>We have written a function called find.rules. This function returns the list of top N rules given the transaction and support/confidence thresholds. We are interested in the top 10 rules. We are going to use leverage values for our recommendation.</p><pre><em># top N rules</em><br>find.rules &lt;- <strong>function</strong>(transactions,topN = 10){<br> <br> other.im &lt;- interestMeasure(rules, transactions = transactions)<br> <br> rules.df &lt;- cbind(rules.df, other.im[,c(&#39;conviction&#39;,&#39;leverage&#39;)])<br> <br> <br> <em># Keep the best rule based on the interest measure</em><br> best.rules.df &lt;- head(rules.df[order(-rules.df$leverage),],topN)<br> <br> <strong>return</strong>(best.rules.df)<br> }</pre><pre>cross.sell.rules &lt;- find.rules(transactions.obj)<br>cross.sell.rules$rules &lt;- as.character(cross.sell.rules$rules)<br>cross.sell.rules</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*nHSeibh-okc7Ks8nwUiIRQ.png" /><figcaption>image by author</figcaption></figure><p>The first four entries have a lift value of 2 to 4, indicating that the products are not independent. These rules have support of around 2 percent and the system has 30 percent confidence for these rules. But wait, what about leverage? These items have a leverage of about 1 percentage points. Whatever is driving the co-occurrence results in a one-percentage-point increase in the probability of buying both together over what we would expect simply because they are popular items. Is that sufficient for cross-selling decisions? Maybe yes or no... that’s a business dependent decision.</p><p>For the sake of this example, we recommend that the retailer uses these top products in his cross-selling campaign as, given the lift value, there is a high probability of the customer picking up a {Bag of Organic Bananas} if he picks up an {Organic Hass Avocado}.</p><p>We have also included one other interest measure — conviction.</p><blockquote>Convicton: Conviction is a measure to ascertain the direction of the rule. Unlike lift, conviction is sensitive to the rule direction. Conviction (A =&gt; B) is not the same as conviction (B =&gt; A). Conviction, with the sense of its direction, gives us a hint that targeting the customers of Organic Hass Avocado to cross-sell will yield more sales of Bag of Organic Bananas rather than the other way round.</blockquote><h3>visualize the rules</h3><p>The plot.graph function is used to visualize the rules that we have shortlisted based on their leverage values. It internally uses a package called igraph to create a graph representation of the rules:</p><pre><strong>library</strong>(igraph)</pre><pre><em># visualize the rules</em><br>plot.graph &lt;- <strong>function</strong>(cross.sell.rules){<br> edges &lt;- unlist(lapply(cross.sell.rules[&#39;rules&#39;], strsplit, split=&#39;=&gt;&#39;))<br> <br> g &lt;- graph(edges = edges)<br> plot(g)<br>}<br>plot.graph(cross.sell.rules)</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*F_dql9qfHmMnantAFFLTaA.png" /><figcaption>image by author</figcaption></figure><h3>Weighted Transactions</h3><p>In the pure vanilla use, arules package uses the frequency of the items in the itemset to measure support. We can replace this by explicitly providing weights for different transactions which can then replace support measures. Doing this can allow us to hardcode certain products in our association rules even though they may not be frequent (by assigning more weight to transactions that contain them).</p><p>In the arules package, the weclat method allows us to use weighted transactions to generate frequent itemsets based on these weights. We introduce the weights through the itemsetinfo data frame in the str(transactions.obj) transactions object.</p><p>If explicit weights are not available, we can use an algorithm called Hyperlink-induced topic search (HITS) to generate one for us. The basic idea of HITS algorithm is to assign weights such that a transaction with a lot of items is considered more important than a transaction with a single item.</p><p>The arules package provides the method (HITS). So for example here, we can use hits to generate weights and then use weclat method to do weighted association ruling…</p><pre><em># The arules package provides the method (HITS)</em><br>weights.vector &lt;- hits( transactions.obj, type = &quot;relative&quot;)<br>weights.df &lt;- data.frame(transactionID = labels(weights.vector), weight = weights.vector)</pre><pre>head(weights.df)</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*IhM21m1M7PLDTec1coboIA.png" /><figcaption>image by author</figcaption></figure><h3>Citation</h3><ul><li>The Instacart Online Grocery Shopping Dataset 2017”, Accessed from <a href="https://www.instacart.com/datasets/grocery-shopping-2017">https://www.instacart.com/datasets/grocery-shopping-2017</a> on 3/09/2020</li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=2ab198d56181" width="1" height="1" alt=""><hr><p><a href="https://medium.com/data-science/ml-techniques-to-optimise-digital-analytics-part-1-association-analysis-2ab198d56181">Must know ML techniques for digital analysts — Part 1: Association Analysis</a> was originally published in <a href="https://medium.com/data-science">TDS Archive</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>