<?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:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Rohan's Bytes: ML Case-Study 🔐]]></title><description><![CDATA[🎉 WORLD'S MOST COMPREHENSIVE RESOURCE FOR MACHINE LEARNING CASE-STUDY BASED INTERVIEW QUESTIONS - Collected from many real-life FANG ML Engineers.]]></description><link>https://www.rohan-paul.com/s/ml-case-study</link><image><url>https://substackcdn.com/image/fetch/$s_!q7Ea!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F20030c9b-4180-453e-9ef3-f42abd8f9de5_1200x1200.png</url><title>Rohan&apos;s Bytes: ML Case-Study 🔐</title><link>https://www.rohan-paul.com/s/ml-case-study</link></image><generator>Substack</generator><lastBuildDate>Sat, 02 May 2026 16:17:49 GMT</lastBuildDate><atom:link href="https://www.rohan-paul.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Rohan Paul]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[rohanpaul@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[rohanpaul@substack.com]]></itunes:email><itunes:name><![CDATA[Rohan Paul]]></itunes:name></itunes:owner><itunes:author><![CDATA[Rohan Paul]]></itunes:author><googleplay:owner><![CDATA[rohanpaul@substack.com]]></googleplay:owner><googleplay:email><![CDATA[rohanpaul@substack.com]]></googleplay:email><googleplay:author><![CDATA[Rohan Paul]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[ML Case-study Interview Question: Scaling Real-Time Recommendations for Millions with Distributed Machine Learning]]></title><description><![CDATA[Browse all the ML Case-Studies here.]]></description><link>https://www.rohan-paul.com/p/ml-case-study-interview-question-346</link><guid isPermaLink="false">https://www.rohan-paul.com/p/ml-case-study-interview-question-346</guid><dc:creator><![CDATA[Rohan Paul]]></dc:creator><pubDate>Tue, 22 Apr 2025 10:01:28 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!yYxz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6066bd4e-9e7c-458d-acec-83d9d9a1f40a_1024x597.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!yYxz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6066bd4e-9e7c-458d-acec-83d9d9a1f40a_1024x597.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!yYxz!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6066bd4e-9e7c-458d-acec-83d9d9a1f40a_1024x597.png 424w, https://substackcdn.com/image/fetch/$s_!yYxz!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6066bd4e-9e7c-458d-acec-83d9d9a1f40a_1024x597.png 848w, https://substackcdn.com/image/fetch/$s_!yYxz!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6066bd4e-9e7c-458d-acec-83d9d9a1f40a_1024x597.png 1272w, https://substackcdn.com/image/fetch/$s_!yYxz!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6066bd4e-9e7c-458d-acec-83d9d9a1f40a_1024x597.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!yYxz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6066bd4e-9e7c-458d-acec-83d9d9a1f40a_1024x597.png" width="1024" height="597" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6066bd4e-9e7c-458d-acec-83d9d9a1f40a_1024x597.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:597,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1038673,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.rohan-paul.com/i/161871518?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6066bd4e-9e7c-458d-acec-83d9d9a1f40a_1024x597.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!yYxz!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6066bd4e-9e7c-458d-acec-83d9d9a1f40a_1024x597.png 424w, https://substackcdn.com/image/fetch/$s_!yYxz!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6066bd4e-9e7c-458d-acec-83d9d9a1f40a_1024x597.png 848w, https://substackcdn.com/image/fetch/$s_!yYxz!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6066bd4e-9e7c-458d-acec-83d9d9a1f40a_1024x597.png 1272w, https://substackcdn.com/image/fetch/$s_!yYxz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6066bd4e-9e7c-458d-acec-83d9d9a1f40a_1024x597.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Browse all the <strong><a href="https://www.rohan-paul.com/s/ml-case-study/archive?sort=new">ML Case-Studies here</a></strong>.</p><h1><strong>Case-Study question</strong></h1><h2><strong>A fast-growing enterprise faces scaling issues with a recommendation system that personalizes content for millions of users. The existing solution processes user activity data from multiple sources, including streaming interactions and offline logs, but struggles with latency and data quality. The Chief Data Officer wants a scalable Machine Learning system to handle real-time predictions and offline model updates with minimal downtime. Propose a full technical strategy to address data ingestion, model training, model serving, metrics, and iterative improvement.</strong></h2><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://x.com/rohanpaul_ai&quot;,&quot;text&quot;:&quot;Connect with me on X (Twitter)&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://x.com/rohanpaul_ai"><span>Connect with me on X (Twitter)</span></a></p><h4><strong>Proposed Detailed Solution</strong></h4><p>Data ingestion uses streaming frameworks like Apache Kafka for real-time processing and a parallel data pipeline for offline batch logs. A distributed file system ingests offline data for large-scale processing. Metadata is managed in a centralized repository to maintain schema consistency. An ETL process standardizes numerical features, categorical features, and timestamps for subsequent modeling steps. A data lake approach keeps raw and processed data in separate storage zones for efficient discovery and cleaning. A consistent data schema is enforced at all ingestion points to reduce corruption.</p><p>Feature engineering includes session-based aggregations, time-decay factors that emphasize recent behavior, and user-specific context vectors captured from historical interactions. Scalable transformations run on Spark clusters to handle huge volumes. An orchestrated pipeline retrains models with updated features daily or hourly. Intermediate outputs are cached in a distributed key-value store for faster retrieval.</p><p>Model selection begins with a collaborative filtering approach to leverage user-user or item-item similarity. A second layer uses a neural network to incorporate richer contextual signals. Embedding vectors map users and items into a dense space for similarity computations. The training process runs on a GPU cluster to manage large-scale mini-batch gradient updates. Each epoch processes sampled user-item pairs to reduce overfitting. Hyperparameter tuning uses historical offline data and a holdout set. Early stopping monitors validation loss to avoid excessive overfitting.</p><h4><strong>Real-Time Model Serving</strong></h4><p>A low-latency serving layer deploys the trained model behind a RESTful endpoint. A load balancer routes incoming traffic to multiple instances. The system caches frequently requested data for repeated queries. A micro-batching approach merges small requests to reduce overhead. When a model update is ready, a rolling deployment strategy updates one instance at a time to ensure zero downtime. A shadow deployment tests new versions in parallel to confirm performance before full rollout.</p><h4><strong>Monitoring and Metrics</strong></h4><p>Metrics focus on click-through rate, dwell time, and user retention. A streaming analytics engine collects these signals in real time. Aggregated metrics feed a dashboard for detection of performance regression. Model drift is monitored by checking distribution shifts in user-item patterns over time. These checks initiate retraining if the drift crosses a threshold. Confidence intervals for key metrics guide safe deployments.</p><h4><strong>Scalability and Ongoing Iterations</strong></h4><p>Sharding strategies split the user base by region, reducing memory footprints per model instance. Horizontal scaling provisions extra compute when traffic spikes. New feature ideas are tested in controlled A/B experiments. Retraining intervals may be daily or weekly, depending on cost and variance considerations. Parallel offline experiments benchmark different network architectures. A feedback loop from monitoring refines the system design.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.rohan-paul.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">I write everyday for my readers on actionable AI. Subscribe and instantly get a 1300+ page Python book.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2><strong>How would you handle cold-start users with minimal historical data?</strong></h2><p>A mixed strategy uses demographic or geo-based defaults plus behavior-based clustering. A fallback model assigns baseline predictions for new users, gradually switching to personalized recommendations once enough session data accumulates. Demographic grouping can be done by age range or region to approximate preferences. After a few clicks, the system transitions to partial personalization by training an embedding layer on short sequences. If a user is entirely new with no clicks, a trending items approach or population-wide popularity ranking ensures a basic fallback.</p><h2><strong>How do you handle real-time feature updates?</strong></h2><p>A streaming pipeline ingests user clicks, page views, and dwell-time signals. Updates are published to Apache Kafka, which triggers feature transformations. A near-real-time store refreshes user embeddings or aggregates. A streaming library merges new events with existing feature vectors. The model serving layer retrieves the most recent vector at inference time. If the system requires immediate partial updates to the model, an incremental learning component can apply small gradient updates. If updates are aggregated for a future batch retraining, an event timestamp ensures synchronization with the correct training windows.</p><h2><strong>How would you ensure data quality at scale?</strong></h2><p>Frequent validation checks compare incoming data against expected ranges for numeric features and valid categories for categorical features. A schema registry enforces strict field definitions. If anomalies appear, an alert system notifies data engineers. A data profiling job looks for missing or corrupt fields and removes problematic records if necessary. A versioning system tracks changes in data schema. A quarantine approach isolates suspicious partitions for further review before merging them into the main dataset.</p><h2><strong>How do you select an appropriate model architecture?</strong></h2><p>Model choice depends on balancing time-sensitive features and historical context. A two-tower model architecture uses separate embedding layers for user features and item features. Each tower produces latent representations, and a dot product or attention mechanism computes similarity. This architecture scales well because user and item embeddings can be precomputed and updated independently. A deeper neural network approach might capture more complex interactions, but it adds training cost. Testing smaller prototypes on a subset helps find a sweet spot between complexity and performance.</p><h2><strong>How do you validate the model offline before real-time deployment?</strong></h2><p>An offline validation set with historical user actions is split chronologically to simulate real-world data flow. A standard evaluation metric like mean average precision (MAP) or normalized discounted cumulative gain (NDCG) measures recommendation quality. If the dataset is large, random sampling retains a representative portion. A performance threshold is set based on business goals. If offline performance meets the threshold, an A/B test starts to compare the new model with the old version. A short test with a percentage of live traffic confirms real-time metrics before a wider release.</p><h2><strong>How would you handle scaling for tens of millions of users?</strong></h2><p>A distributed GPU cluster or parameter server architecture trains embeddings in parallel. A memory-based cache or in-memory store holds frequently accessed user vectors. Sharding by user segment or region balances loads across multiple servers. An autoscaler watches system CPU and GPU utilization, adding more nodes during peak usage. Offline data processing runs on a big data platform with sufficient memory and compute resources to avoid bottlenecks. For real-time inference, a load balancer routes requests to the closest regional data center to reduce latency.</p><h2><strong>How do you implement continuous improvement?</strong></h2><p>An automated pipeline triggers daily or weekly retraining with fresh data. A drift detection mechanism looks at user behavioral changes and triggers earlier retraining when shifts are large. A modular architecture swaps new feature transformations or model layers with minimal refactoring. A structured experiment-tracking system records each model&#8217;s parameters and metrics, ensuring reproducibility. The system monitors user feedback loops, diagnosing deteriorations caused by seasonality or emergent patterns. Recalibration steps then refine learning rates, sample weighting, or architecture changes to maintain optimal performance.</p><p></p><p></p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.rohan-paul.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">I write everyday for my readers on actionable AI. Subscribe and instantly get a 1300+ page Python book.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[ML Case-study Interview Question: ML-Powered Contact Accuracy Score: Unifying Email and Company Verification]]></title><description><![CDATA[Browse all the ML Case-Studies here.]]></description><link>https://www.rohan-paul.com/p/ml-case-study-interview-question-3d5</link><guid isPermaLink="false">https://www.rohan-paul.com/p/ml-case-study-interview-question-3d5</guid><dc:creator><![CDATA[Rohan Paul]]></dc:creator><pubDate>Tue, 22 Apr 2025 09:59:28 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!bkik!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c41ab8c-f28f-45cc-a635-cd04dfbb5f96_1024x574.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!bkik!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c41ab8c-f28f-45cc-a635-cd04dfbb5f96_1024x574.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!bkik!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c41ab8c-f28f-45cc-a635-cd04dfbb5f96_1024x574.png 424w, https://substackcdn.com/image/fetch/$s_!bkik!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c41ab8c-f28f-45cc-a635-cd04dfbb5f96_1024x574.png 848w, https://substackcdn.com/image/fetch/$s_!bkik!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c41ab8c-f28f-45cc-a635-cd04dfbb5f96_1024x574.png 1272w, https://substackcdn.com/image/fetch/$s_!bkik!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c41ab8c-f28f-45cc-a635-cd04dfbb5f96_1024x574.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!bkik!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c41ab8c-f28f-45cc-a635-cd04dfbb5f96_1024x574.png" width="1024" height="574" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1c41ab8c-f28f-45cc-a635-cd04dfbb5f96_1024x574.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:574,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1007054,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.rohan-paul.com/i/161871331?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c41ab8c-f28f-45cc-a635-cd04dfbb5f96_1024x574.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!bkik!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c41ab8c-f28f-45cc-a635-cd04dfbb5f96_1024x574.png 424w, https://substackcdn.com/image/fetch/$s_!bkik!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c41ab8c-f28f-45cc-a635-cd04dfbb5f96_1024x574.png 848w, https://substackcdn.com/image/fetch/$s_!bkik!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c41ab8c-f28f-45cc-a635-cd04dfbb5f96_1024x574.png 1272w, https://substackcdn.com/image/fetch/$s_!bkik!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c41ab8c-f28f-45cc-a635-cd04dfbb5f96_1024x574.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Browse all the <strong><a href="https://www.rohan-paul.com/s/ml-case-study/archive?sort=new">ML Case-Studies here</a></strong>.</p><h1><strong>Case-Study question</strong></h1><h2><strong>A large data intelligence platform merged two different systems that each provided a single metric indicating data accuracy. One system used last updated date, and the other used a human-verified vs machine-generated label. These single metrics were sometimes misleading or expensive to maintain. The company chose to unify them by creating a machine learning-based contact accuracy score focusing on email address and company name accuracy. How would you design a solution to generate an accuracy score for each contact, ensuring scalability, strong predictive power, and continuous improvement?</strong></h2><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://x.com/rohanpaul_ai&quot;,&quot;text&quot;:&quot;Connect with me on X (Twitter)&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://x.com/rohanpaul_ai"><span>Connect with me on X (Twitter)</span></a></p><h4><strong>Provide a step-by-step plan. Describe how you would handle ground truth data creation, feature extraction, model selection, model deployment, and ongoing maintenance.</strong></h4><div><hr></div><h2><strong>Detailed Solution</strong></h2><h4><strong>Overview</strong></h4><p>This combines multiple signals (recent updates, data sources, verification status, etc.) into a single score for each contact. The main target is whether the email address is valid and whether the contact is associated with the correct company. A random subset of records is labeled as good or bad. A model then predicts the likelihood a new record is correct based on relevant features.</p><h4><strong>Ground Truth Construction</strong></h4><p>Randomly sample a subset of contacts. Manually check if each email address is valid (bounce tests) and confirm the person&#8217;s current company. Label as good if both company and email are valid, or if only the company is valid and email is missing. Label as bad if the company is invalid or the email is invalid. This becomes the training set.</p><h4><strong>Exploratory Data Analysis</strong></h4><p>Explore each field to see how it correlates with good vs bad. Use statistical tests or data visualization to see which features best separate good from bad. Investigate how last updated date, human verification indicator, and other fields (like phone presence or multiple data sources) correlate with correctness.</p><h4><strong>Feature Selection</strong></h4><p>Focus on fields with the highest predictive power:</p><ul><li><p>Age of the record or last updated timestamp</p></li><li><p>Whether the email was machine-generated or user-supplied</p></li><li><p>Availability of a phone number</p></li><li><p>Number of distinct data sources feeding the record</p></li><li><p>Age of any signatures or references</p></li></ul><h4><strong>Model Choice</strong></h4><p>A practical approach is <strong>logistic regression</strong>. It models the probability that a record is good or bad. A general form is shown below.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!s-Xg!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b9d0b7c-8f4f-4870-86bf-447eac10c349_910x114.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!s-Xg!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b9d0b7c-8f4f-4870-86bf-447eac10c349_910x114.png 424w, https://substackcdn.com/image/fetch/$s_!s-Xg!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b9d0b7c-8f4f-4870-86bf-447eac10c349_910x114.png 848w, https://substackcdn.com/image/fetch/$s_!s-Xg!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b9d0b7c-8f4f-4870-86bf-447eac10c349_910x114.png 1272w, https://substackcdn.com/image/fetch/$s_!s-Xg!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b9d0b7c-8f4f-4870-86bf-447eac10c349_910x114.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!s-Xg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b9d0b7c-8f4f-4870-86bf-447eac10c349_910x114.png" width="910" height="114" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7b9d0b7c-8f4f-4870-86bf-447eac10c349_910x114.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:114,&quot;width&quot;:910,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:15712,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.rohan-paul.com/i/161871331?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b9d0b7c-8f4f-4870-86bf-447eac10c349_910x114.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!s-Xg!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b9d0b7c-8f4f-4870-86bf-447eac10c349_910x114.png 424w, https://substackcdn.com/image/fetch/$s_!s-Xg!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b9d0b7c-8f4f-4870-86bf-447eac10c349_910x114.png 848w, https://substackcdn.com/image/fetch/$s_!s-Xg!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b9d0b7c-8f4f-4870-86bf-447eac10c349_910x114.png 1272w, https://substackcdn.com/image/fetch/$s_!s-Xg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b9d0b7c-8f4f-4870-86bf-447eac10c349_910x114.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Here, p is the probability a record is good. x_1..x_n are features such as last updated date, user verification, phone number presence, etc. beta_0..beta_n are learned parameters.</p><p>After training on the labeled subset, apply the model to all contacts. Output is a probability in the range [0,1]. Map that to a final 70-99 range if poor contacts are already removed or cleaned from the system.</p><h4><strong>Sample Python Code</strong></h4><pre><code><code>import pandas as pd
from sklearn.linear_model import LogisticRegression

# df contains rows of contact data with relevant features
# 'label' is 1 for good, 0 for bad
X = df[['last_updated_days','verified_flag','phone_exists','multiple_sources','signature_age']]
y = df['label']

model = LogisticRegression()
model.fit(X, y)

# Score for new data
df['score_raw'] = model.predict_proba(X)[:,1]
df['contact_accuracy_score'] = 70 + 29 * df['score_raw']
</code></code></pre><p>Explain in a simple paragraph format: The code loads the features, fits a logistic regression model, and then predicts the probability a contact is good. It maps the probability to a 70-99 range for the final contact accuracy score. For any contact updates, re-run these steps or an incremental retraining process.</p><h4><strong>Validation</strong></h4><p>To confirm the score is meaningful, randomly sample records, calculate their score, and manually re-verify email and company correctness. Score distributions should correlate with actual correctness rates. Adjust thresholds or modeling parameters if the predictions deviate from observed outcomes.</p><h4><strong>Maintenance</strong></h4><p>Continuously sample new records or changed records for manual verification. Retrain periodically using the newly labeled records. Expand or refine features (like phone type or recency of job transitions) to capture more signal. Consider advanced models if logistic regression underperforms.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.rohan-paul.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">I write everyday for my readers on actionable AI. Subscribe and instantly get a 1300+ page Python book.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2><strong>How would you address these Follow-Up Questions?</strong></h2><h2><strong>1) How do you handle data that changes rapidly?</strong></h2><p>Monitor frequently updated fields and run incremental retraining. For each incremental batch, gather ground truth labels, update features like last update timestamp, and retrain or fine-tune the model. Apply automated checks (e.g., bounce tests) to high-value records first.</p><h2><strong>2) Why focus on email and company accuracy?</strong></h2><p>Email and company name are business-critical fields for marketing, sales, and engagement. Invalid emails cause bounces and penalties with mailing services. Incorrect company associations waste resources and lead to lost opportunities.</p><h2><strong>3) What if you want a separate score for phone numbers?</strong></h2><p>Repeat the same approach. Define a ground truth for phone correctness. Retrain a similar logistic regression or more advanced model using phone-specific labels. Combine scores or produce multiple accuracy scores (e.g., EmailAccuracyScore and PhoneAccuracyScore).</p><h2><strong>4) How do you choose between logistic regression and more complex algorithms?</strong></h2><p>Compare performance metrics (e.g., area under ROC curve) for multiple approaches such as random forest, gradient boosting, or neural networks. Logistic regression is simple and transparent, making it easier to explain. If a complex model demonstrates significantly higher accuracy, weigh that benefit against interpretability, training cost, and data scale.</p><h2><strong>5) How do you address label imbalance if most records are good?</strong></h2><p>Use stratified sampling to preserve class proportions in training data. If good vs bad is highly imbalanced, apply techniques like oversampling bad records or undersampling good records. Experiment with class-weight parameters in the model training function. Evaluate performance carefully on a balanced validation set.</p><h2><strong>6) How do you keep your data pipeline efficient?</strong></h2><p>Automate data ingestion, cleaning, feature engineering, and model scoring. Cache intermediate outputs to reduce repetitive computations. Use distributed computing frameworks if the dataset is large. Log data changes to trigger partial scoring rather than recomputing everything.</p><h2><strong>7) What if human verification becomes too expensive?</strong></h2><p>Prioritize high-risk or high-impact subsets for manual checks. Reduce labeling frequency for stable data. Explore more advanced machine learning approaches. Integrate feedback loops from email bounce logs or user responses to refine labels. Focus on ROI: manual checks might be justified for certain high-value segments.</p><h2><strong>8) Why set a minimum score at 70?</strong></h2><p>Poor-quality or outdated records are removed before scoring, so even the lowest-scoring records still meet a minimal quality threshold. This scoring strategy is a product decision. If new requirements arise, shift the baseline to different minimum values (like 50) or allow negative scores.</p><h2><strong>9) How do you ensure generalization to new data?</strong></h2><p>Include diverse samples during model training. If your user base expands internationally, incorporate those countries in training data. Periodically retrain using new contact profiles, watch for drift (e.g., changing email patterns), and confirm the model&#8217;s assumptions still hold.</p><h2><strong>10) What improvements would you consider in the future?</strong></h2><p>Incorporate more features (e.g., role-based emails, auto-detected seniority). Assign different weights to fresh vs older data. Build ensemble models that average multiple algorithms&#8217; outputs. Segment the model by industries or regions if you observe different data patterns.</p><p></p><p></p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.rohan-paul.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">I write everyday for my readers on actionable AI. Subscribe and instantly get a 1300+ page Python book.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[ML Case-study Interview Question: Dual Contrastive Embeddings for Balanced Two-Sided Marketplace Recommendations.]]></title><description><![CDATA[Browse all the ML Case-Studies here.]]></description><link>https://www.rohan-paul.com/p/ml-case-study-interview-question-879</link><guid isPermaLink="false">https://www.rohan-paul.com/p/ml-case-study-interview-question-879</guid><dc:creator><![CDATA[Rohan Paul]]></dc:creator><pubDate>Tue, 22 Apr 2025 09:55:58 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!qesa!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf7953cb-eb6c-413d-a077-47b6ad802922_1024x573.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!qesa!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf7953cb-eb6c-413d-a077-47b6ad802922_1024x573.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!qesa!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf7953cb-eb6c-413d-a077-47b6ad802922_1024x573.png 424w, https://substackcdn.com/image/fetch/$s_!qesa!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf7953cb-eb6c-413d-a077-47b6ad802922_1024x573.png 848w, https://substackcdn.com/image/fetch/$s_!qesa!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf7953cb-eb6c-413d-a077-47b6ad802922_1024x573.png 1272w, https://substackcdn.com/image/fetch/$s_!qesa!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf7953cb-eb6c-413d-a077-47b6ad802922_1024x573.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!qesa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf7953cb-eb6c-413d-a077-47b6ad802922_1024x573.png" width="1024" height="573" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bf7953cb-eb6c-413d-a077-47b6ad802922_1024x573.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:573,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:896970,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.rohan-paul.com/i/161871162?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf7953cb-eb6c-413d-a077-47b6ad802922_1024x573.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!qesa!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf7953cb-eb6c-413d-a077-47b6ad802922_1024x573.png 424w, https://substackcdn.com/image/fetch/$s_!qesa!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf7953cb-eb6c-413d-a077-47b6ad802922_1024x573.png 848w, https://substackcdn.com/image/fetch/$s_!qesa!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf7953cb-eb6c-413d-a077-47b6ad802922_1024x573.png 1272w, https://substackcdn.com/image/fetch/$s_!qesa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf7953cb-eb6c-413d-a077-47b6ad802922_1024x573.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Browse all the <strong><a href="https://www.rohan-paul.com/s/ml-case-study/archive?sort=new">ML Case-Studies here</a></strong>.</p><h1><strong>Case-Study question</strong></h1><h2><strong>A large-scale online platform hosts a two-sided marketplace with millions of active job-seekers and millions of active job postings. The goal is to create a recommendation engine that connects both sides efficiently. The platform observes diverse data from employers (thumbs up/down), job-seeker activities (applications, searches), and textual attributes (job descriptions, resumes, titles, skills, etc.). The data exhibits extreme long-tail distributions, constant entity churn, and noisy free-text with domain-specific jargon. Propose a robust machine learning system that produces relevant, balanced recommendations for both sides. Show how you would design and train your approach to handle zero-shot predictions for unseen entities, incorporate feedback signals from both sides, and keep inference scalable. Provide your reasoning, architecture choices, and any supporting technical details. Explain how you would ensure that the system optimizes for both job-seeker relevance and employer satisfaction.</strong></h2><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://x.com/rohanpaul_ai&quot;,&quot;text&quot;:&quot;Connect with me on X (Twitter)&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://x.com/rohanpaul_ai"><span>Connect with me on X (Twitter)</span></a></p><h4><strong>Detailed Solution</strong></h4><h4><strong>Problem Framing</strong></h4><p>Training a model to recommend jobs to job-seekers requires representing both sides of the marketplace. The data is sparse, non-stationary, and includes free-text with non-standard formats. Embedding representations help tackle these issues by converting textual and structured attributes into dense vectors. Embeddings also allow scalar dot products at inference for scalability, rather than heavier per-request models.</p><h4><strong>Encoder Strategy</strong></h4><p>Pre-trained encoders capture same-entity semantic similarities. One encoder models job-to-job similarity. Another encoder models resume-to-resume similarity. These encoders use large corpora of implicit user interactions and explicit employer thumbs-up/down signals.</p><p>The job encoder learns representations of job postings. Co-applied jobs are treated as positive pairs, while random pairs are negatives. The resume encoder learns representations of candidate resumes. Two resumes that receive a thumbs-up on the same job are considered similar, while a thumbs-up vs thumbs-down pair is dissimilar. Triplet loss is effective here, particularly because many job postings contain far more negative feedback samples than positive ones.</p><h4><strong>Combined Architecture for Cross-Entity Inference</strong></h4><p>A downstream model learns to align job-seeker embeddings with job embeddings. The job-seeker side uses:</p><ul><li><p>The pre-trained resume embedding.</p></li><li><p>A time-based encoder for recent activities, such as search queries or job interactions, each mapped through the same job encoder or a separate query encoder.</p></li><li><p>A feed-forward layer merges the static resume encoding with the dynamic interaction-based encoding.</p></li></ul><p>This merged job-seeker representation is dot-producted with the pre-trained job embedding to generate a match score.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!t_KB!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cc7bc90-0240-4177-adc7-6b8e3f74d2b8_280x77.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!t_KB!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cc7bc90-0240-4177-adc7-6b8e3f74d2b8_280x77.png 424w, https://substackcdn.com/image/fetch/$s_!t_KB!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cc7bc90-0240-4177-adc7-6b8e3f74d2b8_280x77.png 848w, https://substackcdn.com/image/fetch/$s_!t_KB!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cc7bc90-0240-4177-adc7-6b8e3f74d2b8_280x77.png 1272w, https://substackcdn.com/image/fetch/$s_!t_KB!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cc7bc90-0240-4177-adc7-6b8e3f74d2b8_280x77.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!t_KB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cc7bc90-0240-4177-adc7-6b8e3f74d2b8_280x77.png" width="280" height="77" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5cc7bc90-0240-4177-adc7-6b8e3f74d2b8_280x77.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:77,&quot;width&quot;:280,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:4369,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.rohan-paul.com/i/161871162?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cc7bc90-0240-4177-adc7-6b8e3f74d2b8_280x77.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!t_KB!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cc7bc90-0240-4177-adc7-6b8e3f74d2b8_280x77.png 424w, https://substackcdn.com/image/fetch/$s_!t_KB!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cc7bc90-0240-4177-adc7-6b8e3f74d2b8_280x77.png 848w, https://substackcdn.com/image/fetch/$s_!t_KB!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cc7bc90-0240-4177-adc7-6b8e3f74d2b8_280x77.png 1272w, https://substackcdn.com/image/fetch/$s_!t_KB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cc7bc90-0240-4177-adc7-6b8e3f74d2b8_280x77.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>In text:</p><ul><li><p>L_s is a contrastive term sampling jobs for each job-seeker to ensure relevant matches.</p></li><li><p>L_v is a contrasting term sampling job-seekers for each job to balance employer objectives.</p></li></ul><p>Symmetrizing loss terms avoids bias toward only one side. Sampling negative pairs from the entire corpus captures better coverage, reduces repetitive or in-batch bias, and helps the model learn zero-shot generalizations.</p><h4><strong>Practical Example</strong></h4><p>Below is a simplified Python snippet showing how a training step for the job-seeker side might be organized. Explanations follow.</p><pre><code><code>import torch
import torch.nn as nn
import torch.nn.functional as F

class JobEncoder(nn.Module):
    def __init__(self, vocab_size, embed_dim):
        super(JobEncoder, self).__init__()
        self.embedding = nn.Embedding(vocab_size, embed_dim)
        self.linear = nn.Linear(embed_dim, embed_dim)

    def forward(self, job_tokens):
        x = self.embedding(job_tokens).mean(dim=1)
        x = self.linear(x)
        x = F.normalize(x, p=2, dim=1)
        return x

class SeekerEncoder(nn.Module):
    def __init__(self, resume_embed_dim, activity_embed_dim, hidden_dim):
        super(SeekerEncoder, self).__init__()
        self.resume_linear = nn.Linear(resume_embed_dim, hidden_dim)
        self.activity_linear = nn.Linear(activity_embed_dim, hidden_dim)
        self.final_linear = nn.Linear(hidden_dim, hidden_dim)

    def forward(self, resume_embed, activity_embed):
        r = self.resume_linear(resume_embed)
        a = self.activity_linear(activity_embed)
        merged = r + a
        merged = self.final_linear(merged)
        merged = F.normalize(merged, p=2, dim=1)
        return merged

# forward pass with dual-contrastive loss
def dual_contrastive_loss(seeker_embs, job_embs):
    # L_s: fix seeker_embs, differentiate over job_embs
    logits_s = torch.matmul(seeker_embs, job_embs.t())
    labels_s = torch.arange(len(seeker_embs)).to(seeker_embs.device)
    loss_s = F.cross_entropy(logits_s, labels_s)

    # L_v: fix job_embs, differentiate over seeker_embs
    logits_v = torch.matmul(job_embs, seeker_embs.t())
    labels_v = torch.arange(len(job_embs)).to(job_embs.device)
    loss_v = F.cross_entropy(logits_v, labels_v)

    return loss_s + loss_v
</code></code></pre><p>This structure shows separate encoders (conceptually referencing your pre-trained job encoder and combined job-seeker encoder) and a dual contrastive loss. The cross-entropy usage approximates a softmax-based contrastive term, with rows and columns reversed for each side.</p><h4><strong>Zero-Shot Adaptability</strong></h4><p>Representations come from generic text or attribute embeddings, not from a closed set of IDs. New job titles or new resumes can be mapped without retraining the entire network. Pre-trained text-processing layers handle domain-specific slang or creative job titles. Training updates can incorporate fresh patterns.</p><h4><strong>Large-Scale Inference</strong></h4><p>Dot products between normalized embeddings scale well. Approximate nearest-neighbor indices can accelerate job retrieval for each job-seeker. Similar methods can retrieve candidate sets for an employer. The system can keep up with huge real-time traffic.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.rohan-paul.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">I write everyday for my readers on actionable AI. Subscribe and instantly get a 1300+ page Python book.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2><strong>Follow-up Questions</strong></h2><h2><strong>How would you handle the long-tail job titles when training the job encoder?</strong></h2><p>Training data is skewed. Many titles have few samples. Oversampling and a shared embedding vocabulary for text tokens help. Data augmentation from synonyms or domain expansions helps. Subword tokenization frameworks (for instance, Byte Pair Encoding) mitigate rare-word issues. Embedding-based approaches handle new combinations of rare tokens. Pre-trained language models offer robust representations for unusual job titles. Frequent re-training or fine-tuning ensures rare classes get updated representation.</p><h2><strong>Why does focal loss help for job-pair encoding, and how would you modify it?</strong></h2><p>Focal loss focuses on hard misclassified pairs by reweighting easy examples. This prevents the model from becoming overconfident with abundant easy positives. Including a tunable gamma parameter adjusts how quickly weighting decays on well-classified examples. To implement it, multiply the standard cross-entropy term by (1 - p_t)^gamma, where p_t is the probability assigned to the correct class. The model then allocates more emphasis on challenging examples.</p><h2><strong>How do you ensure balanced optimization for the platform&#8217;s goals, not just one side&#8217;s preferences?</strong></h2><p>Symmetry in the loss function addresses each side&#8217;s objective. The job-seeker loss predicts which jobs a candidate prefers. The job-loss predicts which candidates a job might attract. Weighted sums can adjust emphasis if business goals require. One can also incorporate secondary terms that reflect global constraints, such as coverage or fairness across different categories of users.</p><h2><strong>How would you maintain real-time updates for the candidate&#8217;s recent activities and job statuses?</strong></h2><p>A streaming or micro-batch approach can be used. Resume embeddings remain static, but activity-based states update on fresh interactions. A queue or event-driven pipeline continually ingests new signals. A feature store can hold these incremental features. The job-seeker embedding then recalculates at short intervals or on-demand. For jobs, indexing pipelines can recalculate job embeddings upon significant changes in their data or after new descriptors arrive.</p><h2><strong>How would you deploy this system in practice at large scale?</strong></h2><p>A dedicated service hosts both job and candidate encoders. Embeddings are precomputed and cached. At request time, a fast approximate nearest-neighbor search retrieves top matches. Jobs or candidates can be periodically re-embedded with new data. A streaming pipeline handles partial model updates, especially for embedding layers. Automated A/B testing monitors metrics such as click-through rates, apply rates, and satisfaction. Monitoring ensures that system drift or data distribution shifts trigger re-training.</p><h2><strong>How would you extend it with Graph Neural Networks?</strong></h2><p>A GNN can incorporate multiple entity types in a single embedding space. Entities become nodes, and interactions become edges. Additional signals (rating edges, search edges, application edges) can be learned simultaneously. This captures higher-order relationships among job-seekers, jobs, and attributes. Convolution-like passes aggregate neighbor information. The final embedding can be used for the same similarity-based recommendation. This unifies everything in a single architecture rather than separate encoders.</p><h2><strong>How do you handle textual queries in searches that do not map to known jobs?</strong></h2><p>A separate text-based encoder for search terms can be trained. Tokenize the query, represent each token, and aggregate them, possibly via attention. Weighted self-attention helps highlight crucial terms. A pre-trained model for search tokens improves context understanding. This search embedding can be aligned with the job embedding space. In zero-shot scenarios, unusual queries still produce meaningful embeddings. The search-based signal integrates with the final job-seeker vector to reflect their real-time interests.</p><p></p><p></p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.rohan-paul.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">I write everyday for my readers on actionable AI. Subscribe and instantly get a 1300+ page Python book.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[ML Case-study Interview Question: Building a Scalable Video Moderation Pipeline with Deep Learning and Human Review]]></title><description><![CDATA[Browse all the ML Case-Studies here.]]></description><link>https://www.rohan-paul.com/p/ml-case-study-interview-question-d76</link><guid isPermaLink="false">https://www.rohan-paul.com/p/ml-case-study-interview-question-d76</guid><dc:creator><![CDATA[Rohan Paul]]></dc:creator><pubDate>Tue, 22 Apr 2025 09:53:33 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!BqpP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc175d31d-5b1a-4b1a-b162-13a0527eb978_1024x572.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!BqpP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc175d31d-5b1a-4b1a-b162-13a0527eb978_1024x572.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!BqpP!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc175d31d-5b1a-4b1a-b162-13a0527eb978_1024x572.png 424w, https://substackcdn.com/image/fetch/$s_!BqpP!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc175d31d-5b1a-4b1a-b162-13a0527eb978_1024x572.png 848w, https://substackcdn.com/image/fetch/$s_!BqpP!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc175d31d-5b1a-4b1a-b162-13a0527eb978_1024x572.png 1272w, https://substackcdn.com/image/fetch/$s_!BqpP!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc175d31d-5b1a-4b1a-b162-13a0527eb978_1024x572.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!BqpP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc175d31d-5b1a-4b1a-b162-13a0527eb978_1024x572.png" width="1024" height="572" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c175d31d-5b1a-4b1a-b162-13a0527eb978_1024x572.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:572,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1036576,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.rohan-paul.com/i/161870950?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc175d31d-5b1a-4b1a-b162-13a0527eb978_1024x572.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!BqpP!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc175d31d-5b1a-4b1a-b162-13a0527eb978_1024x572.png 424w, https://substackcdn.com/image/fetch/$s_!BqpP!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc175d31d-5b1a-4b1a-b162-13a0527eb978_1024x572.png 848w, https://substackcdn.com/image/fetch/$s_!BqpP!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc175d31d-5b1a-4b1a-b162-13a0527eb978_1024x572.png 1272w, https://substackcdn.com/image/fetch/$s_!BqpP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc175d31d-5b1a-4b1a-b162-13a0527eb978_1024x572.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Browse all the <strong><a href="https://www.rohan-paul.com/s/ml-case-study/archive?sort=new">ML Case-Studies here</a></strong>.</p><h1><strong>Case-Study question</strong></h1><h2><strong>You are assigned to build a video moderation pipeline to identify and block inappropriate content. A surge in user-uploaded videos has made it vital to detect harmful content, such as nudity, sexual activity, violence, and extremist imagery. Your goal is to design a high-recall system that minimizes the number of false positives. You must incorporate a manual review workflow to counterbalance the occasional misclassifications and avoid frustrating legitimate users. How would you architect this end-to-end system, handle video-frame processing at scale, and fine-tune thresholds to ensure high precision and recall?</strong></h2><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://x.com/rohanpaul_ai&quot;,&quot;text&quot;:&quot;Connect with me on X (Twitter)&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://x.com/rohanpaul_ai"><span>Connect with me on X (Twitter)</span></a></p><h4><strong>Your tasks:</strong></h4><p>Propose an architecture that includes an automated deep-learning model and a human moderation loop. Describe how you would reduce inference time for large videos, manage repeated offenders, and combine frame-level classification outputs into a single decision score. Demonstrate how you would evaluate performance and optimize it in a real-world scenario with heavy traffic and strict latency requirements.</p><h2><strong>Detailed solution</strong></h2><h4><strong>Overall Architecture</strong></h4><p>Start the ingestion pipeline when a user uploads a video. Immediately apply a matching service that blocks known harmful submissions based on a similarity lookup against a database of previously removed content. Forward videos that pass this check to a multi-label classifier built on deep learning. If the model&#8217;s confidence score exceeds a threshold, hide the video and prompt a human review. If the human reviewer confirms a violation, reject the video. If it is flagged incorrectly, restore it.</p><h4><strong>Deep Learning Model</strong></h4><p>Train a convolutional neural network or transformer-based architecture that is already proven effective for image moderation. Adapt this model to handle video frames. Reuse the same underlying weights, then fine-tune on frame-level data representing inappropriate content classes such as nudity or violent imagery. Output multi-label probabilities indicating whether a frame violates any category. Evaluate each label independently.</p><h4><strong>Frame Sampling Strategy</strong></h4><p>Extract frames at regular intervals. Use a balanced approach to avoid missing crucial frames. Each sampled frame goes through the model for classification. Aggregate the results with a function that yields a single final score. One simple approach uses the maximum predicted score across sampled frames:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!lY8m!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22c73dc2-99e4-4f5b-bcad-d9bf3c1d3f48_721x153.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!lY8m!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22c73dc2-99e4-4f5b-bcad-d9bf3c1d3f48_721x153.png 424w, https://substackcdn.com/image/fetch/$s_!lY8m!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22c73dc2-99e4-4f5b-bcad-d9bf3c1d3f48_721x153.png 848w, https://substackcdn.com/image/fetch/$s_!lY8m!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22c73dc2-99e4-4f5b-bcad-d9bf3c1d3f48_721x153.png 1272w, https://substackcdn.com/image/fetch/$s_!lY8m!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22c73dc2-99e4-4f5b-bcad-d9bf3c1d3f48_721x153.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!lY8m!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22c73dc2-99e4-4f5b-bcad-d9bf3c1d3f48_721x153.png" width="721" height="153" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/22c73dc2-99e4-4f5b-bcad-d9bf3c1d3f48_721x153.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:153,&quot;width&quot;:721,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:15199,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.rohan-paul.com/i/161870950?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22c73dc2-99e4-4f5b-bcad-d9bf3c1d3f48_721x153.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!lY8m!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22c73dc2-99e4-4f5b-bcad-d9bf3c1d3f48_721x153.png 424w, https://substackcdn.com/image/fetch/$s_!lY8m!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22c73dc2-99e4-4f5b-bcad-d9bf3c1d3f48_721x153.png 848w, https://substackcdn.com/image/fetch/$s_!lY8m!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22c73dc2-99e4-4f5b-bcad-d9bf3c1d3f48_721x153.png 1272w, https://substackcdn.com/image/fetch/$s_!lY8m!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22c73dc2-99e4-4f5b-bcad-d9bf3c1d3f48_721x153.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Here, S_k is the classifier&#8217;s probability of a violation for the k-th sampled frame, and m is the total number of sampled frames. If S_final exceeds the threshold, label the video for human review.</p><p>Each label&#8217;s threshold is chosen after analyzing validation metrics. A high threshold reduces false positives but may miss some violations. A lower threshold reduces missed detections but risks flagging legitimate content. Calibrate thresholds using validation data that balances the cost of a false positive with the severity of a missed violation.</p><h4><strong>Human Moderation</strong></h4><p>Human reviewers examine the flagged videos to overturn false positives and confirm legitimate violations. Keep these reviewers from having to handle vast volumes of harmless content. This improves overall performance, user experience, and keeps employees focused on real violations. Adjust model thresholds over time to reduce the burden on the moderation team.</p><h4><strong>Reducing Inference Time</strong></h4><p>Limit the frames sent to the model. This ensures near real-time classification. Pre-block uploads from suspicious users by tracking abnormal account patterns. This reduces the total number of samples that must be fully processed.</p><h4><strong>Performance Evaluation</strong></h4><p>Measure recall by counting how many true violations are identified. Measure precision by counting how many flagged videos are truly inappropriate. Evaluate false positives to preserve user trust and maintain engagement. Use a confusion matrix analysis on a validation set to decide final thresholds. Confirm the model&#8217;s performance with regular A/B tests in production.</p><h4><strong>Example Code Snippet</strong></h4><pre><code><code>import cv2
import numpy as np
import torch

def sample_frames(video_path, frame_rate=1):
    cap = cv2.VideoCapture(video_path)
    frames = []
    frame_count = 0
    success = True
    while success:
        success, frame = cap.read()
        if not success:
            break
        if frame_count % frame_rate == 0:
            frames.append(frame)
        frame_count += 1
    cap.release()
    return frames

def predict_inappropriate(frames, model, threshold):
    scores = []
    for frame in frames:
        # Preprocess frame into model input
        input_tensor = preprocess_frame(frame)
        with torch.no_grad():
            logits = model(input_tensor)
            prob = torch.sigmoid(logits)  # For multi-label
        # Suppose we care about any violation category
        violation_score = prob.max().item()
        scores.append(violation_score)
    final_score = max(scores)
    return final_score &gt; threshold
</code></code></pre><p>This code samples frames from a video at regular intervals, applies a pre-trained model, and uses the maximum predicted score across frames. If the maximum exceeds the threshold, the video is flagged.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.rohan-paul.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">I write everyday for my readers on actionable AI. Subscribe and instantly get a 1300+ page Python book.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2><strong>Follow-Up Questions</strong></h2><h2><strong>1) How would you handle an evolving definition of &#8220;inappropriate&#8221; content?</strong></h2><p>Train the model on the existing known categories. Include a label for newly discovered unwanted content as soon as patterns emerge. Collect real examples for each novel category. Continuously retrain or fine-tune the model. Maintain a human-in-the-loop pipeline for cases the model has not seen before. This ensures fast adaptation.</p><h2><strong>2) How do you handle tradeoffs between a single multi-label model and multiple binary classifiers per label?</strong></h2><p>A single multi-label model reduces infrastructure overhead. It also trains each label together, allowing shared feature representations. Multiple specialized binary classifiers can be fine-tuned more granularly for each label, which might boost performance for niche categories. If you have enough data and you need maximum precision for a label, consider separate models for that label. If bandwidth is a constraint, a single multi-label model is more efficient.</p><h2><strong>3) How do you manage repeated upload attempts by malicious users?</strong></h2><p>Track user metadata, IP addresses, and device signatures. Block or throttle uploads from suspicious sources. Store similarity hashes of removed content in a fast key-value store. Compare new submissions against these hashes. Instantly discard any near-duplicate content to spare resources.</p><h2><strong>4) How would you evaluate threshold settings and decide the best tradeoff between recall and false positives?</strong></h2><p>Compute metrics across a labeled validation set. Start with recall = TP / (TP + FN) and precision = TP / (TP + FP). Move the threshold in small increments. Measure how it impacts overall recall and false positives. If missing harmful content is unacceptable, shift thresholds to keep recall high. Combine offline evaluation with a small online A/B test, carefully monitoring user satisfaction and flagged rates.</p><h2><strong>5) How would you improve real-time processing performance for large volumes of videos?</strong></h2><p>Distribute the pipeline across multiple GPU instances. Use a streaming approach that processes frames as they come in. Cache intermediate CNN feature maps so repeated computations are minimized. Convert the model to an optimized format such as TensorRT for faster inference. Pre-filter known suspicious users so their uploads get instantly flagged for further checks.</p><h2><strong>6) How would you handle domain-specific edge cases that are not generalizable by your training data?</strong></h2><p>Curate a high-quality dataset covering edge cases. Gather feedback from users and moderators. Add domain-specific features or textual metadata when it helps. Hybrid approaches might combine visual cues with text in the video&#8217;s audio transcript. Fine-tune the neural network using new examples from these niche categories.</p><h2><strong>7) How do you handle content that requires context beyond a single frame, like borderline sexual imagery that depends on subtle cues over time?</strong></h2><p>Process consecutive frames in short intervals. Use an architecture that captures temporal patterns, such as 3D convolutions or transformer models with attention over time. Aggregate features from a sequence of frames to form a context-aware classification. If the user&#8217;s account has relevant behavioral signals, feed them into the model for more context.</p><h2><strong>8) How would you ensure that your model does not unfairly flag content related to particular races, religious symbols, or artistic expressions?</strong></h2><p>Ensure diverse and representative training data. Collaborate with subject matter experts to label data in a way that accounts for cultural and artistic contexts. Evaluate fairness metrics across protected classes. Regularly audit flagged content for bias. If bias is detected, adjust data and model training to mitigate it. Combine algorithmic checks with human oversight.</p><h2><strong>9) How do you incorporate user feedback on flagged videos to refine the model?</strong></h2><p>Collect cases where users contest a removal. Route that content through a re-labelling process. Include the newly labeled data in model re-training. Periodically analyze contested videos. If many are flagged incorrectly, adjust thresholds or label definitions. Maintain a pipeline that seamlessly updates the production model with refined data.</p><h2><strong>10) How do you manage edge cases where the system incorrectly flags crucial business demonstration videos?</strong></h2><p>Allow a priority-based review queue. If a flagged video is from an established or highly trusted user, move it ahead in the human moderation queue. Collect re-labeled data from these priority cases. This ensures minimal disruption to important users while still maintaining platform safety. Adjust thresholds for certain user types, but keep monitoring for abuse.</p><p></p><p></p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.rohan-paul.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">I write everyday for my readers on actionable AI. Subscribe and instantly get a 1300+ page Python book.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[ML Case-study Interview Question: XGBoost Ranking for Hybrid Recommendations: Combining Content & Collaborative Signals at Scale]]></title><description><![CDATA[Browse all the ML Case-Studies here.]]></description><link>https://www.rohan-paul.com/p/ml-case-study-interview-question-272</link><guid isPermaLink="false">https://www.rohan-paul.com/p/ml-case-study-interview-question-272</guid><dc:creator><![CDATA[Rohan Paul]]></dc:creator><pubDate>Tue, 22 Apr 2025 09:50:04 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Fa1k!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a844154-ce58-435e-8be4-449089b3a231_1024x676.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Fa1k!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a844154-ce58-435e-8be4-449089b3a231_1024x676.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Fa1k!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a844154-ce58-435e-8be4-449089b3a231_1024x676.png 424w, https://substackcdn.com/image/fetch/$s_!Fa1k!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a844154-ce58-435e-8be4-449089b3a231_1024x676.png 848w, https://substackcdn.com/image/fetch/$s_!Fa1k!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a844154-ce58-435e-8be4-449089b3a231_1024x676.png 1272w, https://substackcdn.com/image/fetch/$s_!Fa1k!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a844154-ce58-435e-8be4-449089b3a231_1024x676.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Fa1k!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a844154-ce58-435e-8be4-449089b3a231_1024x676.png" width="1024" height="676" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5a844154-ce58-435e-8be4-449089b3a231_1024x676.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:676,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1172797,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.rohan-paul.com/i/161870749?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a844154-ce58-435e-8be4-449089b3a231_1024x676.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Fa1k!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a844154-ce58-435e-8be4-449089b3a231_1024x676.png 424w, https://substackcdn.com/image/fetch/$s_!Fa1k!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a844154-ce58-435e-8be4-449089b3a231_1024x676.png 848w, https://substackcdn.com/image/fetch/$s_!Fa1k!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a844154-ce58-435e-8be4-449089b3a231_1024x676.png 1272w, https://substackcdn.com/image/fetch/$s_!Fa1k!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a844154-ce58-435e-8be4-449089b3a231_1024x676.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Browse all the <strong><a href="https://www.rohan-paul.com/s/ml-case-study/archive?sort=new">ML Case-Studies here</a></strong>.</p><h1><strong>Case-Study question</strong></h1><h2><strong>You have a massive user-item interaction platform that surfaces business recommendations to tens of millions of users. Past approaches used a matrix factorization model that computed user vectors and business vectors, then performed a dot-product to generate top-k recommendations. Many users with sparse activity were excluded because they had too few interactions. The system also could not incorporate content-based features (like text embeddings, business ratings, or user segments). Propose a new recommendation pipeline that handles both head and tail users. Describe how you would (1) combine collaborative filtering signals with richer content-based features, (2) define a training objective that ranks relevant businesses higher than less relevant ones, (3) handle the need for negative sampling, and (4) scale the system to millions of users. Explain every design choice and detail each step in your solution.</strong></h2><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://x.com/rohanpaul_ai&quot;,&quot;text&quot;:&quot;Connect with me on X (Twitter)&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://x.com/rohanpaul_ai"><span>Connect with me on X (Twitter)</span></a></p><h4><strong>Proposed Solution</strong></h4><p>Matrix factorization alone provides user embeddings and business embeddings but fails on users with few interactions. Enriching signals with content-based features (business categories, review text embeddings, user metadata) addresses the cold-start problem. Training a <strong>supervised</strong> model on top of these signals combines the best of both worlds.</p><p>Using an XGBoost ranker is an efficient solution. XGBoost handles multiple features, offers tree-based explainability, and scales well. Defining the objective as a ranking metric ensures the model learns to prioritize businesses that users will engage with. Normalized Discounted Cumulative Gain (NDCG) is a suitable metric for this because it prioritizes relevant items near the top of recommendations.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!kO7T!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7aa5e00-70ba-4c0e-9d4d-fb663d94f1c0_858x215.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!kO7T!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7aa5e00-70ba-4c0e-9d4d-fb663d94f1c0_858x215.png 424w, https://substackcdn.com/image/fetch/$s_!kO7T!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7aa5e00-70ba-4c0e-9d4d-fb663d94f1c0_858x215.png 848w, https://substackcdn.com/image/fetch/$s_!kO7T!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7aa5e00-70ba-4c0e-9d4d-fb663d94f1c0_858x215.png 1272w, https://substackcdn.com/image/fetch/$s_!kO7T!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7aa5e00-70ba-4c0e-9d4d-fb663d94f1c0_858x215.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!kO7T!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7aa5e00-70ba-4c0e-9d4d-fb663d94f1c0_858x215.png" width="858" height="215" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a7aa5e00-70ba-4c0e-9d4d-fb663d94f1c0_858x215.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:215,&quot;width&quot;:858,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:26429,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.rohan-paul.com/i/161870749?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7aa5e00-70ba-4c0e-9d4d-fb663d94f1c0_858x215.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!kO7T!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7aa5e00-70ba-4c0e-9d4d-fb663d94f1c0_858x215.png 424w, https://substackcdn.com/image/fetch/$s_!kO7T!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7aa5e00-70ba-4c0e-9d4d-fb663d94f1c0_858x215.png 848w, https://substackcdn.com/image/fetch/$s_!kO7T!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7aa5e00-70ba-4c0e-9d4d-fb663d94f1c0_858x215.png 1272w, https://substackcdn.com/image/fetch/$s_!kO7T!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7aa5e00-70ba-4c0e-9d4d-fb663d94f1c0_858x215.png 1456w" sizes="100vw"></picture><div></div></div></a></figure></div><p>Here Z_k is a normalizing constant so that the ideal ranking has NDCG@k = 1.0. rel_i is the relevance score for the business at rank i. The rank index is i. The term 2^{rel_i} - 1 ensures higher relevance gains more weight, while log_2(i+1) discounts items at lower ranks.</p><p>Defining groups for LambdaMART training requires grouping by user and location so pairwise comparisons are performed on relevant sets of items. Content-based features include text-based similarity computed by encoding business reviews with a universal sentence encoder, aggregating them at the business level, and further aggregating user embeddings from the businesses they have interacted with. A cosine similarity between these representations gives a vital signal, especially for users with fewer interactions.</p><p>Controlling negative sampling is crucial. Generating implicit negatives by considering businesses a user never interacted with can introduce bias from how items were presented in the past. A recall step that filters businesses by popularity or user location reduces sampling noise and ensures training data remains representative of real-world serving conditions.</p><p>Scaling predictions demands a second recall stage at inference time. Narrowing the candidate pool by restricting distance or category constraints reduces the number of user-business pairs, making feature computation and XGBoost scoring more tractable.</p><h4><strong>Explanation of Each Technology and Approach</strong></h4><p>XGBoost ranker learns a function that maps each user-business pair to a relevance score. The rank:ndcg objective ensures that pairs with higher actual engagement probabilities appear higher in the ordering. This approach efficiently leverages both collaborative and content-based signals.</p><p>Matrix factorization outputs remain valuable. Including dot-product scores from user and business embeddings (trained previously on large interaction data) serves as a robust collaborative signal. Content signals such as text similarities fill in knowledge for sparse users. The combination handles both users with substantial histories and those new or sporadic.</p><p>Aggregating embeddings from text reviews captures semantic nuances about businesses. Summarizing what businesses offer, and matching these summaries to user interests, bridges the cold-start gap. This representation also helps for users who only rated a few businesses but wrote or consumed text-based content.</p><p>Negative sampling can distort training if done blindly. Restricting negatives to a recall step, such as retrieving top candidates from matrix factorization or popularity, ensures the training process sees realistic user-business pairs. This approach aligns well with how recommendations are eventually surfaced.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.rohan-paul.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">I write everyday for my readers on actionable AI. Subscribe and instantly get a 1300+ page Python book.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h4><strong>Follow-Up Questions and Detailed Answers</strong></h4><h2><strong>How do you ensure that the cold-start user segment still gets meaningful recommendations without sacrificing the performance of head users?</strong></h2><p>Tail users lack sufficient interaction data. Relying on content-based features like user demographics (if available), business category preferences, or text-based similarities helps bridge this gap. The model sees a limited collaborative signal for tail users but a strong content signal if the text embeddings match user traits. The learning algorithm balances the weighting of each feature by maximizing the rank-based objective. Tree-based splits in XGBoost typically shift more weight toward content signals when interaction data is scarce. This does not hurt head users because they retain strong collaborative signals. The model automatically discriminates which features reduce ranking loss for each user.</p><h2><strong>How do you define relevance levels for the ranking objective when interactions vary in strength?</strong></h2><p>Relevance levels match engagement intent. Views might be a lower-intent action, while bookmarks or orders are stronger. A standard approach is to assign integer gains like 1 for views, 2 for bookmarks, 3 for highly active behaviors, and so forth. NDCG uses these to weigh items. The model sees higher gains for interactions that reflect stronger user interest and learns to rank these items toward the top.</p><h2><strong>How do you debug or interpret the model if it relies on many features?</strong></h2><p>Tree-based methods allow feature importance extraction. XGBoost logs importance by total gain or split count. Partial dependence plots show how changing one feature alters the predicted relevance while holding others constant. Examining the distribution of predicted scores for various user segments clarifies whether the model is overfitting or ignoring key signals. If partial dependence indicates the model under-weights collaborative signals, it may need more negative samples from the dot-product top-k. If text-based signals dominate for all users, the hyperparameters or negative sampling strategy might need tuning.</p><h2><strong>How do you handle biases introduced by negative sampling in a large-scale setting?</strong></h2><p>Bias often appears if the sampled negatives do not match how a user interacts in production. Random negatives might ignore the fact that certain users are rarely exposed to specific businesses. Restricting negatives to a realistic recall set (such as location-based candidates or top-K popular items) ensures the training set aligns with how the system surfaces items. Re-sampling multiple times can help. Another approach is weighting negative instances so the class ratio approximates real-world engagement. XGBoost can handle these sample weights. A consistent recall strategy at inference time ensures alignment with training distribution.</p><h2><strong>How do you scale the inference pipeline to millions of users and businesses?</strong></h2><p>The first recall pass prunes candidate businesses using location or popularity filters. Only a small subset of businesses remain for each user. Feature computation occurs next. A broadcasting approach or distributed key-based joins can unify user and business features on Spark. Batched XGBoost scoring on these pairs ranks them, and the top-k items are retained. This method prevents a blowup from scoring all possible user-business pairs, which would be infeasible at large scales.</p><h2><strong>How do you verify that the hybrid model indeed uses both content and collaborative signals correctly?</strong></h2><p>Comparison of partial dependence plots for key collaborative features (dot-product score) versus content features (text-based similarity) shows how predictions vary. Higher sensitivity for the matrix factorization score indicates the model emphasizes collaborative signals, especially for head users. Stronger sensitivity for the text-based feature indicates content signals matter for users with limited history. Observing both high importance ensures the model balances them for maximum overall performance. Offline metrics like NDCG on test data and online metrics from A/B tests confirm improvements. Checking real recommendations with QA testers or product managers helps verify business alignment.</p><h2><strong>How do you keep the system maintainable if you add more complex models in the future?</strong></h2><p>Modular data pipelines isolate feature extraction, negative sampling, and model training. Changing or extending the model is simpler if each part is well-defined. Well-structured data ingestion pipelines let you add new features without rewriting the system. The recall layer remains the same, so only the scoring function changes if you switch to neural networks or hybrid architectures. Detailed documentation of each component ensures future iterations can happen with minimal disruption.</p><h2><strong>How would you adapt this approach if you wanted to optimize a different business metric, like user retention or average order value?</strong></h2><p>Training signals must reflect your business metric. If maximizing average order value, assign higher relevance scores to transactions with higher value. Construct your label period to capture interactions that strongly correlate with longer-term retention or monetary value. The ranking approach remains, but the label definitions shift. The pipeline for recall, negative sampling, and XGBoost training still applies. You might adjust hyperparameters or the tree depth if you suspect new features or different label distributions demand a different complexity level.</p><h2><strong>What if some content-based features are sparse or have high cardinality, like a large set of possible categories?</strong></h2><p>XGBoost handles sparse features by learning split thresholds that skip empty or rare categories. Combining categories in a text-based embedding can reduce dimensionality. You can store multiple categories or text descriptors in a single learned embedding. The essential idea is to preserve relevant semantic information without creating thousands of one-hot columns. Regularization parameters in XGBoost help manage overfitting from large feature spaces.</p><h2><strong>What key mistakes might cause an overestimation of improvement when comparing hybrid approaches to matrix factorization?</strong></h2><p>Mismatched training and test sets can inflate performance. Leakage occurs if the label period overlaps the feature period. This might lead to artificially high NDCG. Failing to use a location-based grouping for the rank objective can mask overfitting to single-city patterns. Another pitfall is ignoring a valid baseline like business popularity for tail users, where matrix factorization alone does not apply. Proper A/B experimentation ensures offline gains translate to real user engagement.</p><h2><strong>How do you ensure the text-based embedding features do not explode your storage or run-time resources?</strong></h2><p>Aggregating the embeddings at the business level and then at the user level compresses the textual information into a reasonable dimension (for example, 512 or 256). Storing these representations in a key-value store allows fast lookups at inference time. Distributed systems that broadcast smaller embedding tables avoid transferring massive arrays of raw review text. Offline precomputation of embeddings ensures scoring only requires a vector lookup rather than re-encoding text on the fly.</p><h2><strong>Why does the model sometimes fail to learn from the collaborative score if you only sample negatives from the dot-product top-K?</strong></h2><p>All negative examples would appear to have an artificially high collaborative score, making the model see that higher collaborative scores can sometimes mean negatives. This leads to a negative correlation between that score and the label. Diversifying the negative sampling to include random or popularity-based negatives ensures the model encounters pairs with a lower collaborative score. Balancing these sets helps the model recognize that high collaborative scores often indicate relevance.</p><h2><strong>How do you decide the weighting or trade-off between location relevance and personalization?</strong></h2><p>Observing partial dependence for location features indicates how strongly distance constraints or local popularity matter. If your product is strictly local, the model might rely on location-based features by design. Tuning XGBoost hyperparameters and data sampling methods can emphasize local signals. Adjusting the group definition so that city-level or region-level grouping is included ensures ranking within a realistic candidate set. Cross-validation on separate geographic splits verifies whether you are overfitting to certain regions.</p><h2><strong>How do you interpret improvements in MAP or NDCG for a business-oriented stakeholder?</strong></h2><p>Explaining that MAP quantifies how early in the ranked list the relevant items appear clarifies that users discover what they want faster. NDCG measures the overall ranking quality with heavier weight on top positions. Doubling MAP means relevant items now appear near the top much more often, so a user is more likely to see interesting businesses early. This can improve engagement metrics, revenue from associated transactions, or user satisfaction. Providing real examples of recommendations that improved helps non-technical stakeholders appreciate the significance of the ranking metrics.</p><h2><strong>What if you want to run different ranking objectives for different user groups?</strong></h2><p>Segmenting user groups can help. For new users, optimizing higher-level engagement might matter more than deeper actions. For power users, you might want to optimize advanced interactions. Training separate models or multi-task learning can unify these objectives. The pipeline for feature extraction remains the same. The difference is in how you define group IDs and relevance. You can maintain one global model with a feature indicating user segment, or train distinct models and blend them.</p><h2><strong>How do you handle the risk of data leakage or label contamination?</strong></h2><p>Splitting data by time prevents features from seeing the outcome. For instance, if you compute features up to time T and labels from time T to T+delta, you avoid direct overlap. Ensuring any new interactions after time T do not feed back into your feature generation pipeline is critical. If the system re-samples negatives with knowledge of the future, the training set might become biased. Carefully partitioning data and checking differences between training, validation, and test sets is essential.</p><h2><strong>How do you measure the success of your final system in production?</strong></h2><p>Monitoring changes in click-through rates, conversion rates, or user retention after launching the new hybrid system. A typical approach uses A/B testing: a control group sees matrix-factorization-based recommendations, while a treatment group sees hybrid-based results. Measuring improvements in user actions, session length, or revenue determines how well the new system performs. Stable improvements in these metrics indicate that offline gains translated well in a real environment.</p><p></p><p></p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.rohan-paul.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">I write everyday for my readers on actionable AI. Subscribe and instantly get a 1300+ page Python book.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[ML Case-study Interview Question: Universal & Zero-Shot Models for Unified Semantic Embeddings of Reviews, Photos & Businesses.]]></title><description><![CDATA[Browse all the ML Case-Studies here.]]></description><link>https://www.rohan-paul.com/p/ml-case-study-interview-question-6c7</link><guid isPermaLink="false">https://www.rohan-paul.com/p/ml-case-study-interview-question-6c7</guid><dc:creator><![CDATA[Rohan Paul]]></dc:creator><pubDate>Tue, 22 Apr 2025 09:46:39 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Iy-0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F69b6438c-650e-4630-9fdb-3815690ea5cc_1024x572.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Iy-0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F69b6438c-650e-4630-9fdb-3815690ea5cc_1024x572.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Iy-0!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F69b6438c-650e-4630-9fdb-3815690ea5cc_1024x572.png 424w, https://substackcdn.com/image/fetch/$s_!Iy-0!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F69b6438c-650e-4630-9fdb-3815690ea5cc_1024x572.png 848w, https://substackcdn.com/image/fetch/$s_!Iy-0!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F69b6438c-650e-4630-9fdb-3815690ea5cc_1024x572.png 1272w, https://substackcdn.com/image/fetch/$s_!Iy-0!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F69b6438c-650e-4630-9fdb-3815690ea5cc_1024x572.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Iy-0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F69b6438c-650e-4630-9fdb-3815690ea5cc_1024x572.png" width="1024" height="572" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/69b6438c-650e-4630-9fdb-3815690ea5cc_1024x572.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:572,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:984063,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.rohan-paul.com/i/161870419?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F69b6438c-650e-4630-9fdb-3815690ea5cc_1024x572.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Iy-0!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F69b6438c-650e-4630-9fdb-3815690ea5cc_1024x572.png 424w, https://substackcdn.com/image/fetch/$s_!Iy-0!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F69b6438c-650e-4630-9fdb-3815690ea5cc_1024x572.png 848w, https://substackcdn.com/image/fetch/$s_!Iy-0!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F69b6438c-650e-4630-9fdb-3815690ea5cc_1024x572.png 1272w, https://substackcdn.com/image/fetch/$s_!Iy-0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F69b6438c-650e-4630-9fdb-3815690ea5cc_1024x572.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Browse all the <strong><a href="https://www.rohan-paul.com/s/ml-case-study/archive?sort=new">ML Case-Studies here</a></strong>.</p><h1><strong>Case-Study question</strong></h1><h2><strong>A prominent online platform handles millions of user-generated reviews, photos, and detailed business metadata. The team wants to build a unified embedding platform for all this content. They need representations that capture semantic information from text and images to support tasks such as classification, search, recommendation, tagging, ranking, and cold-start predictions. They experimented with a universal text encoder to generate embeddings for large volumes of reviews, explored domain-specific fine-tuning, and tried a zero-shot image model to classify and cluster photos. They also created business embeddings by averaging multiple review vectors. The platform&#8217;s goal is to store hundreds of millions of embeddings efficiently, leverage them in existing pipelines, and explore new deep learning solutions. How would you design, optimize, and evaluate such an embedding-based system at scale?</strong></h2><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://x.com/rohanpaul_ai&quot;,&quot;text&quot;:&quot;Connect with me on X (Twitter)&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://x.com/rohanpaul_ai"><span>Connect with me on X (Twitter)</span></a></p><h4><strong>Proposed Solution</strong></h4><p>A universal text encoder generates vector representations for varying text inputs. The off-the-shelf approach takes each text snippet, processes it, and outputs a fixed-dimensional embedding that captures semantic context. A deep averaging network (DAN) is often used, as it averages word and bigram embeddings, then feeds them into a feedforward network.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!-yyl!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd36fd4b0-29c0-4cbf-871a-7e1b1ea396e6_740x189.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!-yyl!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd36fd4b0-29c0-4cbf-871a-7e1b1ea396e6_740x189.png 424w, https://substackcdn.com/image/fetch/$s_!-yyl!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd36fd4b0-29c0-4cbf-871a-7e1b1ea396e6_740x189.png 848w, https://substackcdn.com/image/fetch/$s_!-yyl!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd36fd4b0-29c0-4cbf-871a-7e1b1ea396e6_740x189.png 1272w, https://substackcdn.com/image/fetch/$s_!-yyl!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd36fd4b0-29c0-4cbf-871a-7e1b1ea396e6_740x189.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!-yyl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd36fd4b0-29c0-4cbf-871a-7e1b1ea396e6_740x189.png" width="740" height="189" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d36fd4b0-29c0-4cbf-871a-7e1b1ea396e6_740x189.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:189,&quot;width&quot;:740,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:19673,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.rohan-paul.com/i/161870419?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd36fd4b0-29c0-4cbf-871a-7e1b1ea396e6_740x189.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!-yyl!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd36fd4b0-29c0-4cbf-871a-7e1b1ea396e6_740x189.png 424w, https://substackcdn.com/image/fetch/$s_!-yyl!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd36fd4b0-29c0-4cbf-871a-7e1b1ea396e6_740x189.png 848w, https://substackcdn.com/image/fetch/$s_!-yyl!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd36fd4b0-29c0-4cbf-871a-7e1b1ea396e6_740x189.png 1272w, https://substackcdn.com/image/fetch/$s_!-yyl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd36fd4b0-29c0-4cbf-871a-7e1b1ea396e6_740x189.png 1456w" sizes="100vw"></picture><div></div></div></a></figure></div><p>Here, w_{i} are the word embeddings and b_{j} are the bigram embeddings. The final vector is passed through layers that learn a richer semantic representation.</p><p>Fine-tuning domain-specific text embeddings can give gains when the domain diverges from typical pre-training data. The platform tested tasks like review rating prediction, search category prediction, sentence order prediction, and business matching to create domain-supervised signals. They discovered that the generic pre-trained model was sufficient, possibly because the domain overlapped with the pre-training distribution. They still kept the door open for further fine-tuning with more varied data.</p><p>A zero-shot image model like CLIP encodes each image into a semantic vector by contrasting the image against multiple text descriptions. This approach captures high-level concepts and can generalize to unseen tags. CLIP&#8217;s vulnerability to text artifacts (like random text in an image) or partial misclassification (such as focusing on the foreground object rather than the entire scene) can be mitigated by label engineering and thresholding. Combining these embeddings with domain-specific classifiers can improve recall and precision.</p><p>Creating a single business embedding can be done by averaging its top reviews&#8217; vectors.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!P4cQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9d9efa9-e77d-4933-a569-163521a51795_658x262.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!P4cQ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9d9efa9-e77d-4933-a569-163521a51795_658x262.png 424w, https://substackcdn.com/image/fetch/$s_!P4cQ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9d9efa9-e77d-4933-a569-163521a51795_658x262.png 848w, https://substackcdn.com/image/fetch/$s_!P4cQ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9d9efa9-e77d-4933-a569-163521a51795_658x262.png 1272w, https://substackcdn.com/image/fetch/$s_!P4cQ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9d9efa9-e77d-4933-a569-163521a51795_658x262.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!P4cQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9d9efa9-e77d-4933-a569-163521a51795_658x262.png" width="658" height="262" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d9d9efa9-e77d-4933-a569-163521a51795_658x262.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:262,&quot;width&quot;:658,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:16869,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.rohan-paul.com/i/161870419?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9d9efa9-e77d-4933-a569-163521a51795_658x262.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!P4cQ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9d9efa9-e77d-4933-a569-163521a51795_658x262.png 424w, https://substackcdn.com/image/fetch/$s_!P4cQ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9d9efa9-e77d-4933-a569-163521a51795_658x262.png 848w, https://substackcdn.com/image/fetch/$s_!P4cQ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9d9efa9-e77d-4933-a569-163521a51795_658x262.png 1272w, https://substackcdn.com/image/fetch/$s_!P4cQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9d9efa9-e77d-4933-a569-163521a51795_658x262.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Each e_{review_i} is the text embedding for one review. The system might later add photo embeddings and metadata. The resulting vector can feed into nearest-neighbor lookups for similarity-based recommendations (for instance, &#8220;Users who like this business also like that one&#8221;).</p><p>Embedding storage at scale requires a robust vector database or a distributed storage solution. The system must handle bulk insertion, efficient retrieval, and real-time updates. Model re-training or fine-tuning triggers re-embeddings. An internal service layer can facilitate easy consumption of these embeddings by various teams.</p><h4><strong>Implementation Details</strong></h4><p>Modeling code typically uses libraries like TensorFlow or PyTorch. Below is a simplified Python snippet outlining how to load a universal sentence encoder (USE) and produce embeddings:</p><pre><code><code>import tensorflow_hub as hub
import numpy as np

use_model = hub.load("https://tfhub.dev/google/universal-sentence-encoder/4")

sample_reviews = [
    "The pizza was great, loved the crust.",
    "Had to wait too long for dry cleaning.",
    "Staff was friendly at the pet groomer."
]

review_embeddings = use_model(sample_reviews)

# Each embedding is accessible as a row in 'review_embeddings'.
similarity_matrix = np.inner(review_embeddings, review_embeddings)
print(similarity_matrix)
</code></code></pre><p>This snippet shows how to transform a list of text samples into embeddings and then compute the inner product as a similarity measure.</p><h4><strong>Architecture Considerations</strong></h4><h5><strong>Text Representation</strong></h5><p>The universal encoder architecture uses a transformer or a deep averaging network to compress variable-length text into fixed-length embeddings. The team can maintain an inference pipeline that processes streaming data in real-time or in batches.</p><h5><strong>Business Embeddings</strong></h5><p>Averaging the top N recent reviews is a simple yet effective approach, but it might need weighting strategies (for example, weighting reviews by recency or relevance) to emphasize more representative reviews.</p><h5><strong>Photo Embeddings</strong></h5><p>Zero-shot CLIP embeddings support new categories and tags without retraining. The model&#8217;s performance improves when carefully engineering text prompts. Using thresholds for classification reduces false positives.</p><h5><strong>Storage and Accessibility</strong></h5><p>A large-scale system must handle near-real-time queries. Approximate nearest neighbor search (like FAISS or other specialized data stores) can power fast embedding lookups.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.rohan-paul.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">I write everyday for my readers on actionable AI. Subscribe and instantly get a 1300+ page Python book.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2><strong>Follow-up Question 1</strong></h2><p>How would you handle out-of-vocabulary words and domain-specific jargon that the universal encoder might not have seen during pre-training?</p><p>A candidate solution might involve subword tokenization and reviewing the encoder&#8217;s vocabulary coverage. The universal encoder typically uses tokenization that breaks down unknown tokens into subtokens, which helps with rare or unseen words. Fine-tuning on domain-specific text that contains jargon or abbreviations can further improve embeddings. Explicit data augmentation (for example, synonyms or paraphrases) can also help.</p><h2><strong>Follow-up Question 2</strong></h2><p>How would you incorporate photos into the business embedding beyond simply averaging review text vectors?</p><p>A combined vector can be formed by concatenating or averaging the photo embeddings with the text embeddings. Weighting might give more importance to text when it conveys richer semantic data or to images when visual cues matter. A separate neural network layer could learn an optimal fusion. For example, a small feedforward network might take the concatenated [text_vector, photo_vector] and produce a new embedding. The system would then maintain a single representation that captures both aspects.</p><h2><strong>Follow-up Question 3</strong></h2><p>How would you evaluate the quality of these business embeddings in a real-world setting?</p><p>One direct approach is a similarity-based test. If two businesses are similar, their embeddings should have high cosine similarity. Human-curated pairs (like restaurants offering similar cuisines) can form a test set. The system can also measure downstream performance on tasks like recommendation click-through rate or personalization improvements. Tracking user engagement or dwell time changes after implementing the new embeddings provides feedback on embedding quality in production.</p><h2><strong>Follow-up Question 4</strong></h2><p>How would you optimize the photo classification pipeline if the zero-shot CLIP approach struggles on certain categories?</p><p>Label engineering is key. The text prompts can be modified to better describe each image category, possibly using phrases like &#8220;a photo of a renovated kitchen&#8221; or &#8220;a photo of freshly prepared pasta.&#8221; Another tactic is partial fine-tuning of CLIP. Training a lightweight adapter or additional classification head on top of the image encoder can help the model adapt to domain-specific categories. Augmenting the training data with region-of-interest crops or bounding boxes can guide the model to focus on the relevant portion of the image rather than distracting background elements.</p><h2><strong>Follow-up Question 5</strong></h2><p>How would you scale the embedding refresh process when the system processes millions of new user reviews and photos daily?</p><p>A pipeline can periodically batch process recent data. For text, the universal encoder can run in parallel on multiple workers. For images, a GPU-based solution can accelerate CLIP inference. New embeddings can then be appended to an incremental index, or the system can schedule a periodic rebuild of the entire index if approximate search structures need re-optimization. A streaming or micro-batch approach can keep the embedding store up to date, with a specialized queue that feeds reviews or images to the embedding workers, then pushes results into a central vector database.</p><p></p><p></p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.rohan-paul.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">I write everyday for my readers on actionable AI. Subscribe and instantly get a 1300+ page Python book.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[ML Case-study Interview Question: Real-Time Harmful Text Detection in User Reviews Using LLM Classification]]></title><description><![CDATA[Browse all the ML Case-Studies here.]]></description><link>https://www.rohan-paul.com/p/ml-case-study-interview-question-a1e</link><guid isPermaLink="false">https://www.rohan-paul.com/p/ml-case-study-interview-question-a1e</guid><dc:creator><![CDATA[Rohan Paul]]></dc:creator><pubDate>Tue, 22 Apr 2025 09:40:39 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!C1_5!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabe110a8-d759-4a94-b0a1-2ad1a1625864_1024x573.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!C1_5!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabe110a8-d759-4a94-b0a1-2ad1a1625864_1024x573.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!C1_5!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabe110a8-d759-4a94-b0a1-2ad1a1625864_1024x573.png 424w, https://substackcdn.com/image/fetch/$s_!C1_5!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabe110a8-d759-4a94-b0a1-2ad1a1625864_1024x573.png 848w, https://substackcdn.com/image/fetch/$s_!C1_5!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabe110a8-d759-4a94-b0a1-2ad1a1625864_1024x573.png 1272w, https://substackcdn.com/image/fetch/$s_!C1_5!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabe110a8-d759-4a94-b0a1-2ad1a1625864_1024x573.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!C1_5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabe110a8-d759-4a94-b0a1-2ad1a1625864_1024x573.png" width="1024" height="573" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/abe110a8-d759-4a94-b0a1-2ad1a1625864_1024x573.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:573,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:911562,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.rohan-paul.com/i/161870078?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabe110a8-d759-4a94-b0a1-2ad1a1625864_1024x573.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!C1_5!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabe110a8-d759-4a94-b0a1-2ad1a1625864_1024x573.png 424w, https://substackcdn.com/image/fetch/$s_!C1_5!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabe110a8-d759-4a94-b0a1-2ad1a1625864_1024x573.png 848w, https://substackcdn.com/image/fetch/$s_!C1_5!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabe110a8-d759-4a94-b0a1-2ad1a1625864_1024x573.png 1272w, https://substackcdn.com/image/fetch/$s_!C1_5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabe110a8-d759-4a94-b0a1-2ad1a1625864_1024x573.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Browse all the <strong><a href="https://www.rohan-paul.com/s/ml-case-study/archive?sort=new">ML Case-Studies here</a></strong>.</p><h1><strong>Case-Study question</strong></h1><h2><strong>Imagine you have a user-generated content platform with millions of reviews posted daily. Some reviews contain harmful or offensive text. Your goal is to build a binary classification system that flags highly inappropriate content such as hate speech, lewdness, threats, and other forms of harassment, in near real-time. The platform&#8217;s existing moderation process is partly manual and partly automated. You are asked to propose a machine learning solution to address this at scale, ensuring high precision and recall. How would you approach this problem from data collection, model training, deployment, and post-deployment monitoring?</strong></h2><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://x.com/rohanpaul_ai&quot;,&quot;text&quot;:&quot;Connect with me on X (Twitter)&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://x.com/rohanpaul_ai"><span>Connect with me on X (Twitter)</span></a></p><h2><strong>Detailed Solution</strong></h2><p>This platform collects user reviews. Some are inappropriate, including hate speech, explicit language, or threats. The volume of reviews is massive, so human moderation alone is costly. A Large Language Model (LLM) can help identify these reviews rapidly.</p><h4><strong>Data Curation</strong></h4><p>First, assemble a dataset containing examples of both appropriate and inappropriate content. Work with the moderation team to label past samples, focusing on examples with explicit or hateful elements. Introduce a severity scoring scheme to distinguish levels of harmfulness. Use embedding-based similarity to expand the dataset by finding additional samples that match the labeled examples in semantic space. Handle class imbalance with strategies like:</p><ul><li><p>Oversampling rare sub-categories.</p></li><li><p>Undersampling the majority class.</p></li></ul><h4><strong>Zero Shot and Few Shot Sub-Categorization</strong></h4><p>When explicit sub-category labels (e.g. hate speech vs. lewdness) are missing, use zero shot or few shot classification. Prompt an LLM to predict which category fits the text, then rebalance the training data with the needed sub-categories.</p><h4><strong>Model Architecture and Embeddings</strong></h4><p>Obtain a pretrained LLM from a public repository. Extract embeddings for each review. Visualize separation of appropriate vs. inappropriate reviews by dimensionality reduction (e.g. t-SNE). If there is sufficient separation, proceed to fine-tuning.</p><h4><strong>Fine-Tuning for Classification</strong></h4><p>Attach a classification head to the LLM. Train the model to output 1 for inappropriate and 0 for appropriate text. Use cross-entropy loss to optimize parameters.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!czrE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F12a578e4-41e1-4aca-9f88-56c69b5bb52f_1086x140.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!czrE!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F12a578e4-41e1-4aca-9f88-56c69b5bb52f_1086x140.png 424w, https://substackcdn.com/image/fetch/$s_!czrE!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F12a578e4-41e1-4aca-9f88-56c69b5bb52f_1086x140.png 848w, https://substackcdn.com/image/fetch/$s_!czrE!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F12a578e4-41e1-4aca-9f88-56c69b5bb52f_1086x140.png 1272w, https://substackcdn.com/image/fetch/$s_!czrE!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F12a578e4-41e1-4aca-9f88-56c69b5bb52f_1086x140.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!czrE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F12a578e4-41e1-4aca-9f88-56c69b5bb52f_1086x140.png" width="1086" height="140" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/12a578e4-41e1-4aca-9f88-56c69b5bb52f_1086x140.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:140,&quot;width&quot;:1086,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:18970,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.rohan-paul.com/i/161870078?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F12a578e4-41e1-4aca-9f88-56c69b5bb52f_1086x140.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!czrE!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F12a578e4-41e1-4aca-9f88-56c69b5bb52f_1086x140.png 424w, https://substackcdn.com/image/fetch/$s_!czrE!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F12a578e4-41e1-4aca-9f88-56c69b5bb52f_1086x140.png 848w, https://substackcdn.com/image/fetch/$s_!czrE!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F12a578e4-41e1-4aca-9f88-56c69b5bb52f_1086x140.png 1272w, https://substackcdn.com/image/fetch/$s_!czrE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F12a578e4-41e1-4aca-9f88-56c69b5bb52f_1086x140.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Where y_i is the true label (0 or 1), and hat{y}_i is the predicted probability of class 1 for sample i.</p><p>Assess metrics like precision, recall, F1-score, and confusion matrices on a balanced test set. Analyze false positives carefully because the real-world percentage of inappropriate content is small, and an excessive false positive rate causes poor user experience.</p><h4><strong>Threshold Tuning</strong></h4><p>Even if the model outputs a probability, you must choose a threshold for classification. Because real-world data might have very low prevalence of harmful content, run experiments with different spam prevalence rates in mock traffic. Adjust the threshold to reduce false positives. This ensures only the most egregious content is flagged.</p><h4><strong>Deployment and Real-Time Inference</strong></h4><p>After finalizing the model, package it with your platform&#8217;s ML serving stack. Store historical data in a data warehouse. Run a batch pipeline to preprocess and train or retrain the model regularly. Register the model in a model registry. Serve it with a suitable inference service that exposes an endpoint. The system intercepts new reviews, scores them in real-time, and flags them if the score passes the threshold.</p><h4><strong>Human-in-the-Loop</strong></h4><p>For each flagged review, keep human moderators in the loop. Their final decisions feed back into the pipeline, improving the dataset. Retrain the model periodically using these fresh labels.</p><h4><strong>Example Python Snippet</strong></h4><pre><code><code>import torch
from transformers import AutoModelForSequenceClassification, AutoTokenizer

model_name = "some-llm-model"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForSequenceClassification.from_pretrained(model_name)

sample_review = "This place was terrible. The staff used hateful language."
inputs = tokenizer(sample_review, return_tensors="pt")
outputs = model(**inputs)
logits = outputs.logits
probabilities = torch.softmax(logits, dim=1)
score_inappropriate = float(probabilities[0][1].item())

threshold = 0.75
if score_inappropriate &gt; threshold:
    print("Review flagged as inappropriate.")
else:
    print("Review is appropriate.")
</code></code></pre><p>The tokenizer encodes the text. The model outputs logits for the two classes. Softmax transforms logits into probabilities. If the probability of the inappropriate class exceeds the threshold, flag it.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.rohan-paul.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">I write everyday for my readers on actionable AI. Subscribe and instantly get a 1300+ page Python book.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2><strong>Possible Follow-up Questions and Answers</strong></h2><h2><strong>1) How do you address sarcasm or subtle language that might be offensive?</strong></h2><p>Sarcastic text may not contain obvious hateful terms. Rely on LLM context awareness. Train on examples containing sarcasm by collecting annotated data with subtle cues. Expand labeled examples that moderators consider offensive even if no direct slurs appear. Use these for fine-tuning. If the model struggles, add more human moderation feedback loops.</p><h2><strong>2) What if the dataset is heavily imbalanced?</strong></h2><p>Imbalance is expected, since most content is benign. Use class rebalancing strategies. Over-sample minority classes or synthesize data (e.g. data augmentation). Under-sample the dominant class. Carefully monitor overfitting on minority classes. Maintain a realistic ratio or tune it so the model learns enough from the rare examples.</p><h2><strong>3) How do you set a decision threshold when real-world spam prevalence is small?</strong></h2><p>Generate mock traffic sets with different prevalence levels (for instance 0.1 percent to 5 percent). Calculate false positives and false negatives under varying thresholds. Aim for high precision while maintaining acceptable recall. Start with a conservative threshold, then monitor flagged content in production to see if moderators find too many false positives.</p><h2><strong>4) Why not just use an out-of-the-box LLM without fine-tuning?</strong></h2><p>Pretrained LLMs have general language understanding but might not focus on specific definitions of harmfulness. Fine-tuning aligns the model to the platform&#8217;s policy. Target training ensures it learns examples most relevant to your context. Out-of-the-box models may exhibit higher rates of confusion on borderline offensive language.</p><h2><strong>5) How do you maintain good performance over time?</strong></h2><p>User language evolves. New slurs or coded words may appear. Periodically collect fresh flagged reviews, incorporate them into the training set, and retrain the model. Regular audits help catch drift or new language patterns. Maintain close collaboration with moderators to label any newly surfaced categories of hate speech or inappropriate text.</p><h2><strong>6) Does real-time scoring add latency for users posting reviews?</strong></h2><p>Running an LLM can be resource-intensive. Use optimized inference (GPU acceleration, model quantization, or distillation). Deploy an asynchronous pipeline if real-time blocking is not strictly required. If near-real-time is needed, scale your system with load balancers and hardware accelerators. Use caching or simpler heuristic filters for extremely large volumes, then pass borderline cases to the LLM pipeline.</p><h2><strong>7) How do you deal with false positives that might cause user discontent?</strong></h2><p>False positives can harm trust. At high traffic, a small proportion of misclassifications can still affect many users. Keep precision high. Provide appeals or corrections so users can dispute flagged content. Human moderators should check flagged content. Track your false positive rate and continuously refine the threshold.</p><h2><strong>8) How do you handle the variety of offensive content categories?</strong></h2><p>Break down categories (hate speech vs. sexual content vs. harassment). Create sub-labels. Train a multi-class classifier or a hierarchical approach. Or keep it binary but ensure your training data includes diverse examples. If the platform&#8217;s policy needs more granular detection, add separate classification heads or specialized modules.</p><h2><strong>9) How might you extend this system to other languages?</strong></h2><p>Use multilingual LLMs or distinct models for each target language. Repeat data collection, labeling, and fine-tuning for each language. Monitor differences in cultural norms and slang. Collaborate with bilingual or native-speaking moderators to ensure correct labeling.</p><p>These steps create a robust pipeline. Continue human-in-the-loop feedback, retraining for evolving content, and threshold tuning for real-world conditions.</p><p></p><p></p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.rohan-paul.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">I write everyday for my readers on actionable AI. Subscribe and instantly get a 1300+ page Python book.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[ML Case-study Interview Question: LLM-Powered Real-Time Scam Detection for Livestream Marketplace Messaging]]></title><description><![CDATA[Browse all the ML Case-Studies here.]]></description><link>https://www.rohan-paul.com/p/ml-case-study-interview-question-631</link><guid isPermaLink="false">https://www.rohan-paul.com/p/ml-case-study-interview-question-631</guid><dc:creator><![CDATA[Rohan Paul]]></dc:creator><pubDate>Tue, 22 Apr 2025 09:34:59 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!9Ud_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40952b7b-c825-46c0-802d-aff15369f117_1920x1080.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!9Ud_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40952b7b-c825-46c0-802d-aff15369f117_1920x1080.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!9Ud_!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40952b7b-c825-46c0-802d-aff15369f117_1920x1080.png 424w, https://substackcdn.com/image/fetch/$s_!9Ud_!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40952b7b-c825-46c0-802d-aff15369f117_1920x1080.png 848w, https://substackcdn.com/image/fetch/$s_!9Ud_!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40952b7b-c825-46c0-802d-aff15369f117_1920x1080.png 1272w, https://substackcdn.com/image/fetch/$s_!9Ud_!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40952b7b-c825-46c0-802d-aff15369f117_1920x1080.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!9Ud_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40952b7b-c825-46c0-802d-aff15369f117_1920x1080.png" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/40952b7b-c825-46c0-802d-aff15369f117_1920x1080.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1929827,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.rohan-paul.com/i/161869849?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40952b7b-c825-46c0-802d-aff15369f117_1920x1080.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!9Ud_!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40952b7b-c825-46c0-802d-aff15369f117_1920x1080.png 424w, https://substackcdn.com/image/fetch/$s_!9Ud_!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40952b7b-c825-46c0-802d-aff15369f117_1920x1080.png 848w, https://substackcdn.com/image/fetch/$s_!9Ud_!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40952b7b-c825-46c0-802d-aff15369f117_1920x1080.png 1272w, https://substackcdn.com/image/fetch/$s_!9Ud_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40952b7b-c825-46c0-802d-aff15369f117_1920x1080.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Browse all the <strong><a href="https://www.rohan-paul.com/s/ml-case-study/archive?sort=new">ML Case-Studies here</a></strong>.</p><h1><strong>Case-Study question</strong></h1><h2><strong>A rapidly expanding livestream marketplace faces growing scam attempts where fraudsters target new or unsuspecting users via private messages. The existing rule engine relies on discrete indicators like shipping delays and refunds but struggles to handle nuanced conversational context. Propose a comprehensive solution that integrates Large Language Models to detect suspicious activity. Outline how you would architect the system for real-time scam detection, incorporate human oversight, and integrate enforcement policies. Specify how you handle data ingestion, model orchestration, LLM-based risk scoring, and automated actions against suspicious accounts.</strong></h2><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://x.com/rohanpaul_ai&quot;,&quot;text&quot;:&quot;Connect with me on X (Twitter)&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://x.com/rohanpaul_ai"><span>Connect with me on X (Twitter)</span></a></p><h4><strong>Detailed Solution</strong></h4><p>The system maintains a rules-based core and augments it with advanced Large Language Models (LLMs) to detect malicious or manipulative message patterns. The rules engine alone cannot interpret context-rich conversations or subtle user signals, so the approach is to combine both.</p><h4><strong>Central Rule Engine</strong></h4><p>It collates structured data like message_frequency, account_age, and lifetime_orders, then applies static thresholds and flags. This engine is quick at enforcing well-defined violations, such as large shipping delays or repeat refund requests, but it lacks contextual awareness for more open-ended issues like off-platform scams.</p><h4><strong>LLM-Enhanced Detection</strong></h4><p>Incoming messages or conversations with suspicious signals (for example, large numbers of messages to new accounts) are routed into an LLM-based analyzer. The LLM processes the entire conversation, plus user metadata, to produce scam_likelihood, including an explanation. The system uses the following gating rule inside the engine:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!jVn-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0bc1066-a14d-4d79-81e6-0d40b126e6c5_1180x56.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!jVn-!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0bc1066-a14d-4d79-81e6-0d40b126e6c5_1180x56.png 424w, https://substackcdn.com/image/fetch/$s_!jVn-!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0bc1066-a14d-4d79-81e6-0d40b126e6c5_1180x56.png 848w, https://substackcdn.com/image/fetch/$s_!jVn-!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0bc1066-a14d-4d79-81e6-0d40b126e6c5_1180x56.png 1272w, https://substackcdn.com/image/fetch/$s_!jVn-!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0bc1066-a14d-4d79-81e6-0d40b126e6c5_1180x56.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!jVn-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0bc1066-a14d-4d79-81e6-0d40b126e6c5_1180x56.png" width="1180" height="56" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e0bc1066-a14d-4d79-81e6-0d40b126e6c5_1180x56.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:56,&quot;width&quot;:1180,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:18573,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.rohan-paul.com/i/161869849?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0bc1066-a14d-4d79-81e6-0d40b126e6c5_1180x56.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!jVn-!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0bc1066-a14d-4d79-81e6-0d40b126e6c5_1180x56.png 424w, https://substackcdn.com/image/fetch/$s_!jVn-!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0bc1066-a14d-4d79-81e6-0d40b126e6c5_1180x56.png 848w, https://substackcdn.com/image/fetch/$s_!jVn-!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0bc1066-a14d-4d79-81e6-0d40b126e6c5_1180x56.png 1272w, https://substackcdn.com/image/fetch/$s_!jVn-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0bc1066-a14d-4d79-81e6-0d40b126e6c5_1180x56.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>scam_likelihood is the numeric score from the LLM, from 0 to 1. account_age is how many days the account has existed. message_frequency is how quickly the user is sending messages. lifetime_orders is how many orders the user has ever completed. If these conditions are met, the account is flagged for immediate restricted features or suspension.</p><h4><strong>Data Flow</strong></h4><p>User data, chat messages, prior violations, and other signals feed a pipeline that checks if a conversation needs LLM evaluation. Once flagged, the entire conversation and relevant metadata are passed to an LLM prompt. The output is structured JSON with fields scam_likelihood and explanation. Those numeric scores feed back into the rule engine, which decides on actions (temporary hold, account suspension, or no action). When confidence is moderate, the system routes the case to the trust and safety team for manual review.</p><h4><strong>Implementation Details</strong></h4><p>Use message-based triggers (e.g., user sends large volumes of suspicious text, or newly created account tries to lure others off-platform). Feed those messages to an LLM prompt designed for scam detection. The LLM looks at conversation patterns (mentioning external payment links, repeated urgency, request for private info) that can often bypass naive filters. The outputs are combined with external signals in the rule engine to produce a final decision. Detected violations lead to automated feature revocations (like blocking further messaging), while borderline cases appear in a human moderation dashboard.</p><h4><strong>Model Behavior and Adaptation</strong></h4><p>Maintain a feedback loop where newly discovered threats (like messages hidden in image attachments) trigger updates. When malicious actors adapt by embedding text in images, optical character recognition (OCR) extracts textual content, which the LLM then evaluates. Over time, data from user actions (confirmed scams, false flags) refines thresholds or prompts, improving precision and recall.</p><h4><strong>Performance and Monitoring</strong></h4><p>Monitor detection metrics: the fraction of actual scams caught (recall) and how many legitimate users are falsely flagged (precision). Investigate flagged conversations frequently to update LLM prompts and refine rule thresholds. The system logs outputs, decisions, and final actions for audits and further model retraining.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.rohan-paul.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">I write everyday for my readers on actionable AI. Subscribe and instantly get a 1300+ page Python book.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2><strong>How would you handle images containing scam text?</strong></h2><p>LLMs need textual input, so OCR can convert images to text. The extracted text is appended to the conversation. If the system sees frequent malicious messages embedded in images, it re-checks the conversation in context, calculating scam_likelihood with the newly extracted content. This process remains efficient because images are only analyzed if the message thread is suspicious, optimizing resource usage.</p><h2><strong>What zero-shot or few-shot techniques can be used with LLM-based classification here?</strong></h2><p>Use a carefully crafted prompt with concise instructions and examples of flagged scam attempts. If needed, few-shot examples demonstrate typical scam patterns. This approach helps the LLM identify suspicious language without a custom fine-tuned model. Provide short, representative conversation snippets showing recognized fraud attempts, and ask the LLM to map them to a scam_likelihood. For new patterns, the zero-shot component helps adapt with minimal overhead.</p><h2><strong>How do you measure and optimize precision and recall?</strong></h2><p>Compare flagged conversations against a manually verified set. If the system flags too many harmless messages, lower the scam_likelihood threshold or refine your conversation-level signals. If the system misses actual scams, integrate more context signals into the LLM prompt or reduce the threshold. Evaluate performance through confusion matrix analysis, focusing on minimizing false positives for genuine users, while maintaining high capture rates of real scams.</p><h2><strong>How do you handle user privacy in this pipeline?</strong></h2><p>Mask or tokenize personal data such as emails or card details before sending text to the LLM. Restrict logs to store only hashed user identifiers. Keep data encryption in transit and at rest. The LLM instance (internal or external) must be under strict data governance to avoid accidental leaks of sensitive user information.</p><h2><strong>How do you mitigate bias or potential overreach?</strong></h2><p>Regularly audit flagged conversations for false positives. If certain communities or user behaviors are disproportionately flagged, analyze the root cause. Retrain or adjust thresholds. Provide an appeals process for users who believe they were wrongly flagged. Involve human reviewers for ambiguous cases, and refine LLM prompts or instructions to prevent systematic bias.</p><h2><strong>Which steps ensure robust production deployment?</strong></h2><p>Monitor concurrency to handle high conversation throughput. Cache repeated prompts or partial inferences for performance gains. Implement fallback logic if the LLM or OCR service is unavailable. Log every step of the pipeline to facilitate debugging. Connect to a workflow system that triggers notifications when large spikes in flagged messages occur. Periodically retrain or adjust the system based on real-world outcomes.</p><h2><strong>How would you detect user harassment using a similar framework?</strong></h2><p>Use a specialized harassment_likelihood metric from the same LLM pipeline. Incorporate conversation context and user reports. Possibly define thresholds for toxic language or repeated targeted insults. Feed these signals to the rule engine to decide if immediate user blocking or content removal is warranted. Provide a path for human review when the system is uncertain or the language is ambiguous.</p><h2><strong>What if the system starts seeing new scam patterns it has never encountered before?</strong></h2><p>Continue human reviews of suspicious but uncertain cases. Feed newly confirmed patterns into few-shot prompts, updating the &#8220;known scam patterns&#8221; portion. If patterns diverge widely, consider domain-specific fine-tuning of the base LLM. Track evolving tactics like deepfake content or disguised payment requests, and systematically incorporate them into updated zero-shot or few-shot examples.</p><h2><strong>What main steps ensure this solution scales effectively?</strong></h2><p>Leverage streaming architectures (Kafka or similar) for event-driven message ingestion. Keep the rules engine fast by limiting the frequency of LLM calls. Periodically retrain or refine prompts so the LLM&#8217;s knowledge stays relevant. Employ microservices for modularization: one service for data gathering and orchestration, one for calling the LLM, and one for final enforcement.</p><p></p><p></p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.rohan-paul.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">I write everyday for my readers on actionable AI. Subscribe and instantly get a 1300+ page Python book.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[ML Case-study Interview Question: Fixing E-commerce Search Queries with Language Model Expansion & Rectification]]></title><description><![CDATA[Browse all the ML Case-Studies here.]]></description><link>https://www.rohan-paul.com/p/ml-case-study-interview-question-882</link><guid isPermaLink="false">https://www.rohan-paul.com/p/ml-case-study-interview-question-882</guid><dc:creator><![CDATA[Rohan Paul]]></dc:creator><pubDate>Tue, 22 Apr 2025 09:31:12 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!G5MC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd4d5474c-13bc-40be-9888-f96dbade19f3_1024x599.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!G5MC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd4d5474c-13bc-40be-9888-f96dbade19f3_1024x599.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!G5MC!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd4d5474c-13bc-40be-9888-f96dbade19f3_1024x599.png 424w, https://substackcdn.com/image/fetch/$s_!G5MC!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd4d5474c-13bc-40be-9888-f96dbade19f3_1024x599.png 848w, https://substackcdn.com/image/fetch/$s_!G5MC!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd4d5474c-13bc-40be-9888-f96dbade19f3_1024x599.png 1272w, https://substackcdn.com/image/fetch/$s_!G5MC!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd4d5474c-13bc-40be-9888-f96dbade19f3_1024x599.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!G5MC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd4d5474c-13bc-40be-9888-f96dbade19f3_1024x599.png" width="1024" height="599" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d4d5474c-13bc-40be-9888-f96dbade19f3_1024x599.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:599,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1236238,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.rohan-paul.com/i/161869466?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd4d5474c-13bc-40be-9888-f96dbade19f3_1024x599.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!G5MC!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd4d5474c-13bc-40be-9888-f96dbade19f3_1024x599.png 424w, https://substackcdn.com/image/fetch/$s_!G5MC!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd4d5474c-13bc-40be-9888-f96dbade19f3_1024x599.png 848w, https://substackcdn.com/image/fetch/$s_!G5MC!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd4d5474c-13bc-40be-9888-f96dbade19f3_1024x599.png 1272w, https://substackcdn.com/image/fetch/$s_!G5MC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd4d5474c-13bc-40be-9888-f96dbade19f3_1024x599.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Browse all the <strong><a href="https://www.rohan-paul.com/s/ml-case-study/archive?sort=new">ML Case-Studies here</a></strong>.</p><h1><strong>Case-Study question</strong></h1><h2><strong>You are given a live-shopping e-commerce platform. Users submit many misspelled or abbreviated queries (for example, &#8220;jewlery&#8221; instead of &#8220;jewelry&#8221; or &#8220;lv&#8221; for &#8220;louis vuitton&#8221;), which leads to low recall. Management wants a robust query expansion solution to improve search relevance, reduce user confusion, and drive higher conversions. Propose a strategy to handle these malformed or incomplete queries at scale. Then detail how you would measure success and handle edge cases where expansions might introduce noise or incorrect matches.</strong></h2><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://x.com/rohanpaul_ai&quot;,&quot;text&quot;:&quot;Connect with me on X (Twitter)&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://x.com/rohanpaul_ai"><span>Connect with me on X (Twitter)</span></a></p><h2><strong>Detailed Solution</strong></h2><h4><strong>Problem Overview</strong></h4><p>Users frequently enter queries containing misspellings or acronyms. Failing to match these queries to relevant items leads to missed revenue opportunities. A language model-based rectification system is beneficial for correcting these errors and expanding acronyms.</p><h4><strong>Data Logging and Analysis</strong></h4><p>Collect all user queries, associated filters, and subsequent actions in search sessions. Each query is stored with the final tab (products, shows, etc.) that the user visits. This helps identify which tokens align with high-engagement outcomes. Text normalization (to lowercase and removing punctuation) and tokenization (splitting by whitespace) transform queries into consistent tokens.</p><h4><strong>Generating Corrections and Expansions</strong></h4><p>Schedule a process to extract frequent tokens and feed them to a Generative Pre-trained Transformer. The model outputs potential corrections and expansions. Store results in a key-value system, mapping original tokens to expansions or rectifications with confidence scores.</p><h4><strong>Serving Expanded Queries</strong></h4><p>When a user submits a query, split it into tokens. Look up each token in the expansion cache. Combine user tokens with possible expansions based on confidence scores. Form an augmented query expression used to retrieve more relevant results. Show content matching both the original and expanded tokens.</p><h4><strong>Ongoing Improvements</strong></h4><p>Index-time expansions and n-gram rectifications ensure that longer phrases get the same expansions in reverse (e.g., &#8220;san diego comic con&#8221; matching &#8220;sdcc&#8221;). The strategy can extend to synonyms and brand-specific expansions. Another improvement is extracting attributes from product data using the language model to better map user queries to structured filters.</p><h4><strong>Measuring Success</strong></h4><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!55u7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d5c97f9-e39b-4ad2-afc0-a216542ef9a6_612x187.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!55u7!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d5c97f9-e39b-4ad2-afc0-a216542ef9a6_612x187.png 424w, https://substackcdn.com/image/fetch/$s_!55u7!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d5c97f9-e39b-4ad2-afc0-a216542ef9a6_612x187.png 848w, https://substackcdn.com/image/fetch/$s_!55u7!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d5c97f9-e39b-4ad2-afc0-a216542ef9a6_612x187.png 1272w, https://substackcdn.com/image/fetch/$s_!55u7!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d5c97f9-e39b-4ad2-afc0-a216542ef9a6_612x187.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!55u7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d5c97f9-e39b-4ad2-afc0-a216542ef9a6_612x187.png" width="612" height="187" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1d5c97f9-e39b-4ad2-afc0-a216542ef9a6_612x187.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:187,&quot;width&quot;:612,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:18489,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.rohan-paul.com/i/161869466?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d5c97f9-e39b-4ad2-afc0-a216542ef9a6_612x187.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!55u7!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d5c97f9-e39b-4ad2-afc0-a216542ef9a6_612x187.png 424w, https://substackcdn.com/image/fetch/$s_!55u7!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d5c97f9-e39b-4ad2-afc0-a216542ef9a6_612x187.png 848w, https://substackcdn.com/image/fetch/$s_!55u7!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d5c97f9-e39b-4ad2-afc0-a216542ef9a6_612x187.png 1272w, https://substackcdn.com/image/fetch/$s_!55u7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d5c97f9-e39b-4ad2-afc0-a216542ef9a6_612x187.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Precision is the fraction of returned items that are actually relevant. Recall is the fraction of relevant items returned. F1 is the harmonic mean of precision and recall. Higher recall ensures fewer missed items, while high precision avoids irrelevant items. Tracking changes in user engagement metrics (sessions that lead to purchases or deeper interactions) also signals success.</p><h4><strong>Implementation Example</strong></h4><pre><code><code>def expand_query_tokens(tokens, expansion_map):
    expanded_tokens = []
    for t in tokens:
        if t in expansion_map and expansion_map[t]["confidence"] &gt; 0.7:
            expanded_tokens.append(expansion_map[t]["expansion"])
        else:
            expanded_tokens.append(t)
    return expanded_tokens

user_query = "jewlery"
tokens = user_query.lower().split()
exp_tokens = expand_query_tokens(tokens, expansion_map)
# Then pass exp_tokens to the search engine for retrieval
</code></code></pre><p>This Python function looks up each token in the expansion_map and uses expansions above a confidence threshold of 0.7.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.rohan-paul.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">I write everyday for my readers on actionable AI. Subscribe and instantly get a 1300+ page Python book.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2><strong>How would you handle partial matches for multi-word phrases?</strong></h2><p>Training the language model to rectify or expand single tokens works, but partial matches within multi-word phrases require index-time expansions or offline pre-processing that produces multiple expansions. This captures tokens like &#8220;san diego comic con&#8221; which might also be typed as &#8220;sdcc.&#8221; Creating a standard mapping from full phrase to its acronym ensures bidirectional matching. Storing both forms at index time helps retrieve relevant items.</p><h2><strong>How do you keep latency low with large language models?</strong></h2><p>The model runs offline or on a regular schedule. Fresh expansions are stored in a fast key-value store. The query-time request is limited to a cache lookup plus standard search indexing. This design maintains near real-time response times while leveraging advanced language model knowledge.</p><h2><strong>How do you handle conflicts when expansions produce wrong matches?</strong></h2><p>Some tokens have multiple expansions. For instance, &#8220;ms&#8221; might expand to &#8220;microsoft,&#8221; &#8220;milliseconds,&#8221; or &#8220;mschs.&#8221; Store confidence scores and track user engagement signals to refine expansions over time. The system can automatically demote expansions with low click-through or negative signals (like quick user backtracks).</p><h2><strong>How would you evaluate relevance beyond F1?</strong></h2><p>User journey metrics matter, such as time on page, clicks to item detail pages, and checkout conversion. Queries with expansions producing meaningful engagement improvements signal success. Offline A/B tests compare expansion-based search against a baseline. A lift in conversions or session durations indicates that expansions are improving the user experience.</p><h2><strong>How do you handle brand-specific queries?</strong></h2><p>Enable brand-based expansions with specialized brand dictionaries. A language model remains a good general approach, but adding curated brand maps captures domain-specific expansions. The brand map can override expansions if a known brand name is detected.</p><h2><strong>How do you prevent misinterpretation of short tokens?</strong></h2><p>Short tokens, such as &#8220;lv,&#8221; can be ambiguous. Rely on user interaction data to confirm which expansions make sense. If &#8220;lv&#8221; expansions to &#8220;louis vuitton&#8221; drives more conversions than other expansions, keep it active. Gather feedback from subsequent queries and user actions to refine expansions dynamically.</p><h2><strong>How do you adapt to changes in trending queries?</strong></h2><p>Scheduled reprocessing of query logs ensures new tokens or acronyms are captured as trends emerge. A daily or weekly batch run is enough for most e-commerce sites. Frequent re-training or prompting updates are critical if user behavior shifts quickly, such as new fashion abbreviations during seasonal events.</p><h2><strong>How do you deal with user privacy?</strong></h2><p>Token-level analytics keep data usage abstract. The approach focuses on query text rather than personal information. Logs do not store sensitive details, and only aggregated usage metrics guide expansions. Compliance with data protection regulations remains essential by ensuring no private user data is exposed to the model.</p><p></p><p></p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.rohan-paul.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">I write everyday for my readers on actionable AI. Subscribe and instantly get a 1300+ page Python book.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[ML Case-study Interview Question: Building an LLM-Powered AI Assistant for E-commerce Sales Agent Support]]></title><description><![CDATA[Browse all the ML Case-Studies here.]]></description><link>https://www.rohan-paul.com/p/ml-case-study-interview-question-b45</link><guid isPermaLink="false">https://www.rohan-paul.com/p/ml-case-study-interview-question-b45</guid><dc:creator><![CDATA[Rohan Paul]]></dc:creator><pubDate>Tue, 22 Apr 2025 09:24:56 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!y_GK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22f27280-a87e-4707-a6ee-1eb5c42de8c1_1024x574.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!y_GK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22f27280-a87e-4707-a6ee-1eb5c42de8c1_1024x574.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!y_GK!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22f27280-a87e-4707-a6ee-1eb5c42de8c1_1024x574.png 424w, https://substackcdn.com/image/fetch/$s_!y_GK!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22f27280-a87e-4707-a6ee-1eb5c42de8c1_1024x574.png 848w, https://substackcdn.com/image/fetch/$s_!y_GK!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22f27280-a87e-4707-a6ee-1eb5c42de8c1_1024x574.png 1272w, https://substackcdn.com/image/fetch/$s_!y_GK!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22f27280-a87e-4707-a6ee-1eb5c42de8c1_1024x574.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!y_GK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22f27280-a87e-4707-a6ee-1eb5c42de8c1_1024x574.png" width="1024" height="574" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/22f27280-a87e-4707-a6ee-1eb5c42de8c1_1024x574.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:574,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:968913,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.rohan-paul.com/i/161868955?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22f27280-a87e-4707-a6ee-1eb5c42de8c1_1024x574.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!y_GK!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22f27280-a87e-4707-a6ee-1eb5c42de8c1_1024x574.png 424w, https://substackcdn.com/image/fetch/$s_!y_GK!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22f27280-a87e-4707-a6ee-1eb5c42de8c1_1024x574.png 848w, https://substackcdn.com/image/fetch/$s_!y_GK!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22f27280-a87e-4707-a6ee-1eb5c42de8c1_1024x574.png 1272w, https://substackcdn.com/image/fetch/$s_!y_GK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22f27280-a87e-4707-a6ee-1eb5c42de8c1_1024x574.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Browse all the <strong><a href="https://www.rohan-paul.com/s/ml-case-study/archive?sort=new">ML Case-Studies here</a></strong>.</p><h1><strong>Case-Study question</strong></h1><h2><strong>A major e-commerce retailer is developing an advanced AI assistant to help human sales agents handle live customer chats. The system provides real-time suggestions for agent responses based on company policies, product information, and ongoing conversation context. Agents can accept or edit these suggestions before sending them to customers. You are leading the data science team responsible for designing and evaluating this AI assistant.</strong></h2><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://x.com/rohanpaul_ai&quot;,&quot;text&quot;:&quot;Connect with me on X (Twitter)&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://x.com/rohanpaul_ai"><span>Connect with me on X (Twitter)</span></a></p><p>Describe how you would build and optimize such a system to handle diverse product-related inquiries and policy questions. Include details about how you would incorporate conversation history, policies, and product data when generating prompts for the Large Language Model (LLM). Propose specific metrics to assess the AI assistant&#8217;s performance, including both quantitative and qualitative factors. Explain how you would integrate real-time feedback from agents to further refine the model. Finally, explain how you might improve the assistant&#8217;s contextual capabilities over time.</p><h2><strong>Detailed Solution</strong></h2><h4><strong>System Architecture</strong></h4><p>A natural language pipeline would parse each incoming customer message and build a dynamic prompt for the LLM. The prompt must include relevant policy texts, product data, and the conversation&#8217;s history. A specialized template would inject essential constraints and instructions (for example, &#8220;Maintain consistent tone,&#8221; &#8220;Adhere to current shipping policy,&#8221; and &#8220;Suggest alternative products if out of stock&#8221;). The LLM then generates a candidate response. Sales agents see the suggestion, decide whether to use it as is, or edit it. The final text is sent to the customer.</p><h4><strong>Prompt Construction</strong></h4><p>Prompts should combine policy snippets, product information, conversation context, and desired response style. Each segment of the prompt must be concise to avoid context overflow. Guidelines must be explicit, so the LLM never strays into irrelevant or incorrect details. If the system identifies multiple relevant policies or product data, it appends them. The conversation history is included to provide coherence across messages.</p><h4><strong>Model Output and Post-processing</strong></h4><p>The LLM outputs token-by-token probabilities for each potential response. The highest-probability tokens are selected to form the final suggestion. This suggestion is displayed in an agent-facing interface, where the agent can revise or send. Any manual edits get logged.</p><h4><strong>Monitoring and Quality Checks</strong></h4><p>A second quality-assurance LLM can automatically evaluate the correctness, rule adherence, and clarity of the proposed responses. Agent feedback (&#8220;Why did I edit this suggestion?&#8221;) is captured. If edits occur because the assistant produced extraneous content, we label that scenario as &#8220;stylistic fix&#8221; or &#8220;factual fix.&#8221; Over time, the system learns the agent&#8217;s communication style and policy preferences.</p><h4><strong>Performance Metrics</strong></h4><p>Average handle time (AHT), order conversion rate, and agent adoption rate measure quantitative impact. Factual correctness and policy adherence measure qualitative success. The system should store logs of suggestions, final messages, and agent feedback. Continuous analysis reveals if the AI assistant is speeding up or slowing down the conversation, improving conversions, or generating mistakes.</p><h4><strong>Example of Levenshtein Distance</strong></h4><p>To measure how much the agent&#8217;s final message differs from the AI suggestion, define Levenshtein distance. If s is the LLM&#8217;s suggestion and t is the final agent message, distance(i, j) is the cost of transforming the first i characters of s into the first j characters of t. It is computed by a dynamic programming recurrence:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!OCNd!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61264f76-f27a-47bf-87c0-05c70ae6e913_1115x98.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!OCNd!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61264f76-f27a-47bf-87c0-05c70ae6e913_1115x98.png 424w, https://substackcdn.com/image/fetch/$s_!OCNd!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61264f76-f27a-47bf-87c0-05c70ae6e913_1115x98.png 848w, https://substackcdn.com/image/fetch/$s_!OCNd!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61264f76-f27a-47bf-87c0-05c70ae6e913_1115x98.png 1272w, https://substackcdn.com/image/fetch/$s_!OCNd!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61264f76-f27a-47bf-87c0-05c70ae6e913_1115x98.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!OCNd!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61264f76-f27a-47bf-87c0-05c70ae6e913_1115x98.png" width="1115" height="98" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/61264f76-f27a-47bf-87c0-05c70ae6e913_1115x98.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:98,&quot;width&quot;:1115,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:15819,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.rohan-paul.com/i/161868955?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61264f76-f27a-47bf-87c0-05c70ae6e913_1115x98.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!OCNd!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61264f76-f27a-47bf-87c0-05c70ae6e913_1115x98.png 424w, https://substackcdn.com/image/fetch/$s_!OCNd!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61264f76-f27a-47bf-87c0-05c70ae6e913_1115x98.png 848w, https://substackcdn.com/image/fetch/$s_!OCNd!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61264f76-f27a-47bf-87c0-05c70ae6e913_1115x98.png 1272w, https://substackcdn.com/image/fetch/$s_!OCNd!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61264f76-f27a-47bf-87c0-05c70ae6e913_1115x98.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Where cost_sub is 0 if the i-th character of s equals the j-th character of t, else 1. This distance helps quantify how closely the final text follows the AI&#8217;s suggestion.</p><h4><strong>Python Snippet for Levenshtein Distance</strong></h4><pre><code><code>def levenshtein_distance(s, t):
    m, n = len(s), len(t)
    dp = [[0]*(n+1) for _ in range(m+1)]

    for i in range(m+1):
        dp[i][0] = i
    for j in range(n+1):
        dp[0][j] = j

    for i in range(1, m+1):
        for j in range(1, n+1):
            cost_sub = 0 if s[i-1] == t[j-1] else 1
            dp[i][j] = min(
                dp[i-1][j] + 1,      # deletion
                dp[i][j-1] + 1,      # insertion
                dp[i-1][j-1] + cost_sub  # substitution
            )
    return dp[m][n]
</code></code></pre><p>This function returns the total number of insertions, deletions, or substitutions required to convert the suggestion into the agent&#8217;s final response.</p><h4><strong>Future Enhancements</strong></h4><p>Retrieval Augmented Generation (RAG) could provide real-time data queries, ensuring product specs and policies are always up to date. Fine-tuning the underlying LLM on historical chat data helps match top-performing agents&#8217; style. As the system evolves, new training examples with agent feedback improve accuracy and trustworthiness.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.rohan-paul.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">I write everyday for my readers on actionable AI. Subscribe and instantly get a 1300+ page Python book.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2><strong>Follow-up question 1</strong></h2><p>How would you handle situations where the LLM hallucinates information about product features or policies?</p><p><strong>Answer:</strong> Hallucinations arise when the LLM fills knowledge gaps with false data. One solution is to enhance the prompt with precise product specifications and official policy text. Another solution is to incorporate a retrieval mechanism that fetches verified facts from a document store. If the assistant&#8217;s proposed response contains content not found in the verified source, that part is flagged or removed. This approach ensures the model stays grounded in actual data. Agents can also be prompted to tag incorrect responses, and those tags become training signals to reduce future hallucinations.</p><h2><strong>Follow-up question 2</strong></h2><p>How would you decide if the new AI assistant is truly beneficial compared to a simpler rule-based solution?</p><p><strong>Answer:</strong> One method involves running an A/B test. Half of the agents use the new assistant, while the other half rely on a rule-based system. Measure AHT, conversion rate, and agent satisfaction. If the LLM-based system shows consistent reductions in handle time and improves customer satisfaction, it is more beneficial. Qualitative reviews by experienced agents or managers can complement these metrics. If performance gains are small or overshadowed by errors, additional fine-tuning or prompt engineering might be needed before a full rollout.</p><h2><strong>Follow-up question 3</strong></h2><p>Why is it crucial to track edit reasons and how can these insights feed back into model improvements?</p><p><strong>Answer:</strong> Agent edits reveal exactly where the assistant goes wrong. If an edit reason is &#8220;policy mismatch,&#8221; the system likely needs updated policy data or better policy instructions in the prompt. If the edit is &#8220;stylistic fix,&#8221; the model might overuse certain phrases or tone. Tracking edit reasons highlights the most frequent failure modes. Fine-tuning the model on the corrected responses, or adjusting the prompt structure to fix specific mistakes, systematically reduces error rates. This targeted approach improves output quality and agent trust.</p><h2><strong>Follow-up question 4</strong></h2><p>How would you approach scaling this AI assistant to multiple languages for customers worldwide?</p><p><strong>Answer:</strong> Multilingual support requires either training a multilingual LLM or maintaining separate models for each language. A multilingual LLM can streamline updates since new features can be added once. However, if certain languages require specialized domain terms (for example, region-specific shipping details), additional fine-tuning on targeted data is needed. Quality checks must include bilingual evaluators or language-specific QA models to verify factual correctness, style appropriateness, and policy alignment. Real-time feedback from agents in different locales and thorough localization of policy text ensure consistent accuracy across languages.</p><p></p><p></p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.rohan-paul.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">I write everyday for my readers on actionable AI. Subscribe and instantly get a 1300+ page Python book.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[ML Case-study Interview Question: Precise Ad Targeting: Uplift Decision Trees for Incremental Conversion Lift]]></title><description><![CDATA[Browse all the ML Case-Studies here.]]></description><link>https://www.rohan-paul.com/p/ml-case-study-interview-question-f11</link><guid isPermaLink="false">https://www.rohan-paul.com/p/ml-case-study-interview-question-f11</guid><dc:creator><![CDATA[Rohan Paul]]></dc:creator><pubDate>Tue, 22 Apr 2025 09:16:03 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!mi36!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1eaa194-2e37-48ad-b11c-4a6fcafade82_1024x574.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!mi36!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1eaa194-2e37-48ad-b11c-4a6fcafade82_1024x574.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!mi36!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1eaa194-2e37-48ad-b11c-4a6fcafade82_1024x574.png 424w, https://substackcdn.com/image/fetch/$s_!mi36!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1eaa194-2e37-48ad-b11c-4a6fcafade82_1024x574.png 848w, https://substackcdn.com/image/fetch/$s_!mi36!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1eaa194-2e37-48ad-b11c-4a6fcafade82_1024x574.png 1272w, https://substackcdn.com/image/fetch/$s_!mi36!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1eaa194-2e37-48ad-b11c-4a6fcafade82_1024x574.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!mi36!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1eaa194-2e37-48ad-b11c-4a6fcafade82_1024x574.png" width="1024" height="574" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b1eaa194-2e37-48ad-b11c-4a6fcafade82_1024x574.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:574,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:813927,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.rohan-paul.com/i/161868610?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1eaa194-2e37-48ad-b11c-4a6fcafade82_1024x574.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!mi36!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1eaa194-2e37-48ad-b11c-4a6fcafade82_1024x574.png 424w, https://substackcdn.com/image/fetch/$s_!mi36!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1eaa194-2e37-48ad-b11c-4a6fcafade82_1024x574.png 848w, https://substackcdn.com/image/fetch/$s_!mi36!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1eaa194-2e37-48ad-b11c-4a6fcafade82_1024x574.png 1272w, https://substackcdn.com/image/fetch/$s_!mi36!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1eaa194-2e37-48ad-b11c-4a6fcafade82_1024x574.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Browse all the <strong><a href="https://www.rohan-paul.com/s/ml-case-study/archive?sort=new">ML Case-Studies here</a></strong>.</p><h1><strong>Case-Study question</strong></h1><h2><strong>A major e-commerce platform wants to optimize its display ads by focusing on the incremental impact of showing each ad to a user. They have set up a randomized control trial with a treatment group who sees an ad and a control group who does not. Their goal is to build a model that identifies the users who will respond positively to the ads (and avoid users who would have purchased anyway or who get annoyed by ads). They have user-level features (browsing history, purchase history, demographics, etc.), the treatment indicator (ad served or not), and the conversion outcome (purchase or not). Propose an uplift modeling solution to accurately quantify the incremental effect of the ads at the user level. Also propose how you would avoid suboptimal splits in the data (for example, splits that isolate most of the treatment group in one branch of the tree). Provide pseudocode or code snippets for any core implementation elements.</strong></h2><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://x.com/rohanpaul_ai&quot;,&quot;text&quot;:&quot;Connect with me on X (Twitter)&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://x.com/rohanpaul_ai"><span>Connect with me on X (Twitter)</span></a></p><h4><strong>Provide your high-level solution plan, key model components, choice of algorithms, and reasoning behind your decisions. Show how you will evaluate the model before deploying it. Also outline any modifications needed if multiple treatments are tested simultaneously. Explain all logic.</strong></h4><div><hr></div><h4><strong>Proposed Detailed Solution</strong></h4><p><strong>Modeling Approach</strong> Train an <strong>uplift decision tree</strong> that directly optimizes the difference in outcomes between treatment and control. Each node stores two probability distributions: one for the treatment group outcome, another for the control group outcome. Splits aim to maximize the divergence of these distributions.</p><h4><strong>Key Formulae</strong></h4><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!NIa5!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97280fac-a523-4fd4-aad0-f4fbe55dcf3c_656x195.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!NIa5!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97280fac-a523-4fd4-aad0-f4fbe55dcf3c_656x195.png 424w, https://substackcdn.com/image/fetch/$s_!NIa5!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97280fac-a523-4fd4-aad0-f4fbe55dcf3c_656x195.png 848w, https://substackcdn.com/image/fetch/$s_!NIa5!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97280fac-a523-4fd4-aad0-f4fbe55dcf3c_656x195.png 1272w, https://substackcdn.com/image/fetch/$s_!NIa5!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97280fac-a523-4fd4-aad0-f4fbe55dcf3c_656x195.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!NIa5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97280fac-a523-4fd4-aad0-f4fbe55dcf3c_656x195.png" width="656" height="195" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/97280fac-a523-4fd4-aad0-f4fbe55dcf3c_656x195.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:195,&quot;width&quot;:656,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:19716,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.rohan-paul.com/i/161868610?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97280fac-a523-4fd4-aad0-f4fbe55dcf3c_656x195.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!NIa5!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97280fac-a523-4fd4-aad0-f4fbe55dcf3c_656x195.png 424w, https://substackcdn.com/image/fetch/$s_!NIa5!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97280fac-a523-4fd4-aad0-f4fbe55dcf3c_656x195.png 848w, https://substackcdn.com/image/fetch/$s_!NIa5!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97280fac-a523-4fd4-aad0-f4fbe55dcf3c_656x195.png 1272w, https://substackcdn.com/image/fetch/$s_!NIa5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97280fac-a523-4fd4-aad0-f4fbe55dcf3c_656x195.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!zEXS!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb0b784f0-6dcd-4794-8986-93d1290bda88_600x181.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!zEXS!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb0b784f0-6dcd-4794-8986-93d1290bda88_600x181.png 424w, https://substackcdn.com/image/fetch/$s_!zEXS!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb0b784f0-6dcd-4794-8986-93d1290bda88_600x181.png 848w, https://substackcdn.com/image/fetch/$s_!zEXS!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb0b784f0-6dcd-4794-8986-93d1290bda88_600x181.png 1272w, https://substackcdn.com/image/fetch/$s_!zEXS!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb0b784f0-6dcd-4794-8986-93d1290bda88_600x181.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!zEXS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb0b784f0-6dcd-4794-8986-93d1290bda88_600x181.png" width="600" height="181" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b0b784f0-6dcd-4794-8986-93d1290bda88_600x181.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:181,&quot;width&quot;:600,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:13578,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.rohan-paul.com/i/161868610?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb0b784f0-6dcd-4794-8986-93d1290bda88_600x181.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!zEXS!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb0b784f0-6dcd-4794-8986-93d1290bda88_600x181.png 424w, https://substackcdn.com/image/fetch/$s_!zEXS!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb0b784f0-6dcd-4794-8986-93d1290bda88_600x181.png 848w, https://substackcdn.com/image/fetch/$s_!zEXS!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb0b784f0-6dcd-4794-8986-93d1290bda88_600x181.png 1272w, https://substackcdn.com/image/fetch/$s_!zEXS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb0b784f0-6dcd-4794-8986-93d1290bda88_600x181.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>These two expressions measure how far apart the treatment and control outcome distributions are at a node. KL stands for Kullback-Leibler Divergence; ED stands for Squared Euclidean Distance. p_i and q_i are the probabilities of outcome class i for the treatment and control groups.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!2JN9!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F981b1e24-6880-41ae-8201-410b644f320b_1041x180.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!2JN9!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F981b1e24-6880-41ae-8201-410b644f320b_1041x180.png 424w, https://substackcdn.com/image/fetch/$s_!2JN9!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F981b1e24-6880-41ae-8201-410b644f320b_1041x180.png 848w, https://substackcdn.com/image/fetch/$s_!2JN9!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F981b1e24-6880-41ae-8201-410b644f320b_1041x180.png 1272w, https://substackcdn.com/image/fetch/$s_!2JN9!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F981b1e24-6880-41ae-8201-410b644f320b_1041x180.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!2JN9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F981b1e24-6880-41ae-8201-410b644f320b_1041x180.png" width="1041" height="180" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/981b1e24-6880-41ae-8201-410b644f320b_1041x180.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:180,&quot;width&quot;:1041,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:24204,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.rohan-paul.com/i/161868610?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F981b1e24-6880-41ae-8201-410b644f320b_1041x180.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!2JN9!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F981b1e24-6880-41ae-8201-410b644f320b_1041x180.png 424w, https://substackcdn.com/image/fetch/$s_!2JN9!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F981b1e24-6880-41ae-8201-410b644f320b_1041x180.png 848w, https://substackcdn.com/image/fetch/$s_!2JN9!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F981b1e24-6880-41ae-8201-410b644f320b_1041x180.png 1272w, https://substackcdn.com/image/fetch/$s_!2JN9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F981b1e24-6880-41ae-8201-410b644f320b_1041x180.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>This conditional divergence measures how far apart the distributions are in child nodes formed by a split test A. N(a) is the count in child node a, and N is the count in the parent node.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!tj9s!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e5b5f04-07bb-4f7c-b37d-0c155871fd00_861x142.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!tj9s!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e5b5f04-07bb-4f7c-b37d-0c155871fd00_861x142.png 424w, https://substackcdn.com/image/fetch/$s_!tj9s!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e5b5f04-07bb-4f7c-b37d-0c155871fd00_861x142.png 848w, https://substackcdn.com/image/fetch/$s_!tj9s!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e5b5f04-07bb-4f7c-b37d-0c155871fd00_861x142.png 1272w, https://substackcdn.com/image/fetch/$s_!tj9s!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e5b5f04-07bb-4f7c-b37d-0c155871fd00_861x142.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!tj9s!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e5b5f04-07bb-4f7c-b37d-0c155871fd00_861x142.png" width="861" height="142" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1e5b5f04-07bb-4f7c-b37d-0c155871fd00_861x142.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:142,&quot;width&quot;:861,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:16326,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.rohan-paul.com/i/161868610?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e5b5f04-07bb-4f7c-b37d-0c155871fd00_861x142.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!tj9s!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e5b5f04-07bb-4f7c-b37d-0c155871fd00_861x142.png 424w, https://substackcdn.com/image/fetch/$s_!tj9s!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e5b5f04-07bb-4f7c-b37d-0c155871fd00_861x142.png 848w, https://substackcdn.com/image/fetch/$s_!tj9s!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e5b5f04-07bb-4f7c-b37d-0c155871fd00_861x142.png 1272w, https://substackcdn.com/image/fetch/$s_!tj9s!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e5b5f04-07bb-4f7c-b37d-0c155871fd00_861x142.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>This gain term represents the improvement in separation of treatment vs. control after the split. The node chooses a split that maximizes this gain.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!EpbN!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5f73b16-f71a-4ba6-ae1b-6d909181f460_1230x115.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!EpbN!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5f73b16-f71a-4ba6-ae1b-6d909181f460_1230x115.png 424w, https://substackcdn.com/image/fetch/$s_!EpbN!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5f73b16-f71a-4ba6-ae1b-6d909181f460_1230x115.png 848w, https://substackcdn.com/image/fetch/$s_!EpbN!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5f73b16-f71a-4ba6-ae1b-6d909181f460_1230x115.png 1272w, https://substackcdn.com/image/fetch/$s_!EpbN!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5f73b16-f71a-4ba6-ae1b-6d909181f460_1230x115.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!EpbN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5f73b16-f71a-4ba6-ae1b-6d909181f460_1230x115.png" width="1230" height="115" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a5f73b16-f71a-4ba6-ae1b-6d909181f460_1230x115.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:115,&quot;width&quot;:1230,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:24972,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.rohan-paul.com/i/161868610?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5f73b16-f71a-4ba6-ae1b-6d909181f460_1230x115.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!EpbN!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5f73b16-f71a-4ba6-ae1b-6d909181f460_1230x115.png 424w, https://substackcdn.com/image/fetch/$s_!EpbN!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5f73b16-f71a-4ba6-ae1b-6d909181f460_1230x115.png 848w, https://substackcdn.com/image/fetch/$s_!EpbN!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5f73b16-f71a-4ba6-ae1b-6d909181f460_1230x115.png 1272w, https://substackcdn.com/image/fetch/$s_!EpbN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5f73b16-f71a-4ba6-ae1b-6d909181f460_1230x115.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>This normalization term (for Euclidean Distance) penalizes uneven splits (large imbalance between treatment and control) and splits with too many children. N(a)/N is the proportion of samples in child node a. The bracket includes a small epsilon to avoid division by zero.</p><p><strong>Implementation Explanation</strong> Look for candidate splits on a given feature, compute the divergence gain for each possible split, divide by the normalization factor, and choose the split that yields the maximum ratio. Each leaf of the tree ends with an estimated uplift: predicted probability(treatment) - predicted probability(control).</p><h4><strong>Code Snippet (Pseudocode)</strong></h4><pre><code><code>Initialize tree with root node containing all samples
function build_uplift_tree(node):
    if stopping_criterion(node):
        return

    best_gain = 0
    best_split = None
    for feature in all_features:
        for candidate_threshold in possible_splits(feature):
            left_child, right_child = split(node, feature, candidate_threshold)
            div_cond = divergence_conditional(left_child, right_child)
            div_parent = divergence(node)
            raw_gain = div_cond - div_parent
            norm_val = compute_normalization_factor(left_child, right_child, node)
            normalized_gain = raw_gain / norm_val
            if normalized_gain &gt; best_gain:
                best_gain = normalized_gain
                best_split = (feature, candidate_threshold)

    if best_split is not None:
        node.split_feature = best_split.feature
        node.split_threshold = best_split.threshold
        node.left_child = build_uplift_tree(left_child)
        node.right_child = build_uplift_tree(right_child)
    else:
        return

build_uplift_tree(root_node)
</code></code></pre><p>Stopping criteria can involve a minimum number of treatment/control samples in a node to ensure statistically reliable estimates. Once the tree is grown, each leaf node&#8217;s average outcome in treatment minus average outcome in control is used as that node&#8217;s uplift prediction.</p><h4><strong>Handling Multiple Treatments</strong></h4><p>Use the same strategy but store separate distributions for each treatment variant plus a control group. Extend the divergence measures to multi-distribution format. Evaluate the gain from splits by measuring how the distributions separate across treatments and control.</p><h4><strong>Evaluation Strategy</strong></h4><p>Use <strong>uplift metrics</strong> such as <strong>Qini</strong> or <strong>uplift-at-K</strong> on a validation set. These measure how effectively the model ranks individuals by predicted incremental benefit. A typical approach:</p><ul><li><p>Sort users by predicted uplift.</p></li><li><p>Split them into buckets.</p></li><li><p>Compare the differences in actual outcomes between treatment and control by bucket.</p></li></ul><h4><strong>Avoiding Suboptimal Splits</strong></h4><p>Normalization addresses the bias toward grouping most treatment samples in one node and minimal control in another. After computing the raw gain, dividing by the normalization term penalizes extremely unbalanced splits. Also impose a minimum node size for both treatment and control subsets. This ensures each leaf has meaningful data from both groups.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.rohan-paul.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">I write everyday for my readers on actionable AI. Subscribe and instantly get a 1300+ page Python book.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2><strong>Potential Follow-up Questions</strong></h2><h2><strong>How do you handle sparse features when searching for splits?</strong></h2><p>Convert categorical variables into numerical codes or apply one-hot encoding. Check if a given split threshold leads to enough samples in both subgroups. Possibly group levels to avoid over-splitting. Another approach: treat high-cardinality features through feature hashing or look for domain-specific groupings.</p><h2><strong>How do you choose hyperparameters for this uplift tree?</strong></h2><p>Set maximum depth, minimum samples per leaf for each treatment/control group, and the minimum divergence gain for a split. Grid-search these with a validation set. Evaluate performance by measuring how much real incremental uplift the top deciles deliver.</p><h2><strong>Why not build two separate probability models and subtract their outputs?</strong></h2><p>That two-model approach can fail when the uplift signal is faint. Separate models magnify noise in each probability estimate, leading to weaker uplift predictions. A direct uplift model optimizes for differential prediction between treatment and control more effectively.</p><h2><strong>How do you ensure randomization holds in practice?</strong></h2><p>Check that user assignment to treatment or control is indeed random. Validate that distribution of user-level features in both groups is roughly comparable. If any major shift occurs, the unconfoundedness assumption breaks, reducing reliability of uplift estimates.</p><h2><strong>How do you handle data leakage?</strong></h2><p>Block or remove features that might be correlated with the user&#8217;s treatment assignment. If certain features are only known after the treatment is assigned, that creates data leakage. Keep feature sets that are available at decision time to avoid inflating results.</p><h2><strong>How do you handle cold-start users with no history?</strong></h2><p>Train a default model or fallback node with minimal features. Or use simple demographic or context features that are usually available. As more data accumulates, update the user profile. Alternatively, use hierarchical modeling or a hybrid approach that learns global patterns and then refines for individuals with more data.</p><h2><strong>How would you extend this approach to real-time bidding scenarios?</strong></h2><p>Compute uplift scores in real-time based on user context. Use a fast model (like a shallow ensemble of trees). Score each impression, compute estimated uplift, and set a bid strategy accordingly. Use partial feedback loops for online learning if new conversion data arrives continuously.</p><h2><strong>How do you account for cost vs. reward?</strong></h2><p>Include cost in the objective. For a marketing campaign with cost c per ad, measure net benefit = (expected incremental revenue) - c. Modify the splitting criterion to reflect net gain. Alternatively, post-process predicted uplift by removing users with negative or low net gains before final decisions.</p><h2><strong>How do you validate the business impact beyond offline metrics?</strong></h2><p>Run A/B tests with a subset of traffic. Compare revenue lift or conversion lift between a group targeted via the model vs. a control group. Verify that the differences match offline metrics. If consistent, move forward with larger-scale deployment.</p><h2><strong>Can you combine uplift modeling with deep learning?</strong></h2><p>Yes. One approach uses a two-headed neural network that shares lower layers and outputs separate predictions for treatment and control. Another approach tries a direct optimization for uplift. The principle remains the same: align the architecture to capture the differential effect of treatment vs. control. However, interpretability might drop, so care is required in explaining the model&#8217;s decisions.</p><p></p><p></p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.rohan-paul.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">I write everyday for my readers on actionable AI. Subscribe and instantly get a 1300+ page Python book.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[ML Case-study Interview Question: Ranking Visually Compatible Furniture Using Deep Embeddings and Triplet Loss.]]></title><description><![CDATA[Browse all the ML Case-Studies here.]]></description><link>https://www.rohan-paul.com/p/ml-case-study-interview-question-a01</link><guid isPermaLink="false">https://www.rohan-paul.com/p/ml-case-study-interview-question-a01</guid><dc:creator><![CDATA[Rohan Paul]]></dc:creator><pubDate>Tue, 22 Apr 2025 09:09:52 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!gMbq!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa9d65700-b035-42e0-831e-e83662d210ef_1024x574.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!gMbq!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa9d65700-b035-42e0-831e-e83662d210ef_1024x574.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!gMbq!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa9d65700-b035-42e0-831e-e83662d210ef_1024x574.png 424w, https://substackcdn.com/image/fetch/$s_!gMbq!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa9d65700-b035-42e0-831e-e83662d210ef_1024x574.png 848w, https://substackcdn.com/image/fetch/$s_!gMbq!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa9d65700-b035-42e0-831e-e83662d210ef_1024x574.png 1272w, https://substackcdn.com/image/fetch/$s_!gMbq!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa9d65700-b035-42e0-831e-e83662d210ef_1024x574.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!gMbq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa9d65700-b035-42e0-831e-e83662d210ef_1024x574.png" width="1024" height="574" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a9d65700-b035-42e0-831e-e83662d210ef_1024x574.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:574,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:913040,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.rohan-paul.com/i/161866634?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa9d65700-b035-42e0-831e-e83662d210ef_1024x574.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!gMbq!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa9d65700-b035-42e0-831e-e83662d210ef_1024x574.png 424w, https://substackcdn.com/image/fetch/$s_!gMbq!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa9d65700-b035-42e0-831e-e83662d210ef_1024x574.png 848w, https://substackcdn.com/image/fetch/$s_!gMbq!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa9d65700-b035-42e0-831e-e83662d210ef_1024x574.png 1272w, https://substackcdn.com/image/fetch/$s_!gMbq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa9d65700-b035-42e0-831e-e83662d210ef_1024x574.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Browse all the <strong><a href="https://www.rohan-paul.com/s/ml-case-study/archive?sort=new">ML Case-Studies here</a></strong>.</p><h1><strong>Case-Study question</strong></h1><h2><strong>A furniture e-commerce platform wants to recommend visually compatible products to customers. An item that a user has shown interest in (the anchor) should be paired with another product (the positive) that matches the anchor&#8217;s style, while avoiding items (the negative) that clash. Each product spans varied visual attributes like color, material, and shape. Propose a deep learning approach that ranks complementary products for any given anchor in real time. Clarify data collection strategies, model architecture, training methodology, and how to handle new items with minimal or no historical user interactions.</strong></h2><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://x.com/rohanpaul_ai&quot;,&quot;text&quot;:&quot;Connect with me on X (Twitter)&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://x.com/rohanpaul_ai"><span>Connect with me on X (Twitter)</span></a></p><h2><strong>Detailed solution</strong></h2><p>A common approach is to learn an embedding space where compatible items lie near each other. One way is to use a Siamese Network with a triplet loss that pulls an anchor and a positive close while pushing a negative away. This reduces reliance on extensive user interaction data and allows cold-start items to be embedded based on visual features.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!PS5z!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbc7b765-1548-47fb-b4b6-290dfbba4518_917x136.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!PS5z!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbc7b765-1548-47fb-b4b6-290dfbba4518_917x136.png 424w, https://substackcdn.com/image/fetch/$s_!PS5z!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbc7b765-1548-47fb-b4b6-290dfbba4518_917x136.png 848w, https://substackcdn.com/image/fetch/$s_!PS5z!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbc7b765-1548-47fb-b4b6-290dfbba4518_917x136.png 1272w, https://substackcdn.com/image/fetch/$s_!PS5z!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbc7b765-1548-47fb-b4b6-290dfbba4518_917x136.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!PS5z!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbc7b765-1548-47fb-b4b6-290dfbba4518_917x136.png" width="917" height="136" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/cbc7b765-1548-47fb-b4b6-290dfbba4518_917x136.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:136,&quot;width&quot;:917,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:16904,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.rohan-paul.com/i/161866634?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbc7b765-1548-47fb-b4b6-290dfbba4518_917x136.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!PS5z!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbc7b765-1548-47fb-b4b6-290dfbba4518_917x136.png 424w, https://substackcdn.com/image/fetch/$s_!PS5z!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbc7b765-1548-47fb-b4b6-290dfbba4518_917x136.png 848w, https://substackcdn.com/image/fetch/$s_!PS5z!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbc7b765-1548-47fb-b4b6-290dfbba4518_917x136.png 1272w, https://substackcdn.com/image/fetch/$s_!PS5z!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbc7b765-1548-47fb-b4b6-290dfbba4518_917x136.png 1456w" sizes="100vw"></picture><div></div></div></a></figure></div><p>Here a is the anchor image embedding, p is the compatible item embedding, n is the incompatible item embedding, margin is a non-negative separation threshold, and d() is the squared Euclidean distance.</p><p>A second objective can involve a cross-entropy classification term that helps the model attend to different style criteria for different classes. This is helpful if a sofa-to-table match emphasizes color or shape differently than a sofa-to-rug match.</p><p>A convolutional neural network pretrained on large-scale image data is typically used as the base. One branch processes the anchor, another processes the positive, and a third processes the negative. The outputs go through L2 normalization, then the triplet loss penalizes instances where negatives are closer to the anchor than positives.</p><p>Training data can come from multiple sources. Some curated examples might be from 3D scene designs by in-house stylists, because those items are arranged together by experts. Another source might be existing purchase or browsing data. Items that are co-listed or co-ordered offer clues on real-world compatibility. Combining diverse data ensures the model learns broad style relationships, not just popularity patterns.</p><p>In production, embeddings for every product are precomputed. When a user views an item, the system fetches its embedding and performs a nearest neighbor search among candidate classes, returning top-ranked items with minimal latency. This avoids scanning the entire catalog in real time. Periodic re-embeddings ensure fresh inventory items are included and older items are updated with refined representations.</p><p>Below is an example of how to define a simplified triplet loss in Python using PyTorch:</p><pre><code><code>import torch
import torch.nn as nn

class TripletLoss(nn.Module):
    def __init__(self, margin=1.0):
        super().__init__()
        self.margin = margin

    def forward(self, anchor, positive, negative):
        dist_pos = (anchor - positive).pow(2).sum(1)
        dist_neg = (anchor - negative).pow(2).sum(1)
        losses = torch.relu(self.margin + dist_pos - dist_neg)
        return losses.mean()
</code></code></pre><p>This snippet calculates the core part of the loss. The full model would include a convolutional backbone and a projection head that outputs normalized embeddings. After training, these embeddings help in retrieving compatible products.</p><p>Transfer learning speeds up convergence. One can fine-tune only the last few layers of the pretrained convolutional network or unfreeze the entire model, depending on data volume. Overfitting is mitigated via regularization (dropout, data augmentation, or weight decay). Once trained, the model captures cross-category style cues, allowing it to recommend coherent sets of furniture.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.rohan-paul.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">I write everyday for my readers on actionable AI. Subscribe and instantly get a 1300+ page Python book.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2><strong>Follow-up question 1</strong></h2><p>How do you mitigate biases toward popular or frequently purchased items when training the compatibility model?</p><p><strong>Answer</strong>: Bias often surfaces if the training data heavily skews toward high-selling items. One strategy is mixing multiple data sources. Include balanced samples from scene designs or internal style experts that incorporate lesser-known products, not just user-driven lists. Another approach is importance sampling, giving new or less-visited items a chance to appear in the triplets. A final check involves evaluating whether embeddings for cold-start items separate appropriately from the known popular items. If needed, regularize the triplet selection process or add class-balanced sampling so that the model sees a more representative distribution.</p><h2><strong>Follow-up question 2</strong></h2><p>How would you scale this solution to handle a constantly expanding catalog?</p><p><strong>Answer</strong>: Maintain a dedicated pipeline that processes newly added products by extracting their embeddings immediately or on a fixed schedule. This pipeline uses the same trained model so the new embeddings remain consistent. Store them in an approximate nearest neighbor index (such as a library using Hierarchical Navigable Small World graphs or Product Quantization). When a customer views an anchor product, the system computes or retrieves that anchor&#8217;s embedding, looks up the nearest neighbors among relevant product classes, and returns the results. Periodic index rebuilding or incremental insertion keeps the results fresh. Caching popular items&#8217; embeddings in memory further boosts retrieval speed.</p><h2><strong>Follow-up question 3</strong></h2><p>How would you incorporate color-based or material-based queries if customers specify preferences explicitly?</p><p><strong>Answer</strong>: One option is to enrich the embeddings with features that highlight color or material by adding an auxiliary classification task. For instance, train a network to predict key attributes like &#8220;leather vs. fabric&#8221; or &#8220;gray vs. white,&#8221; then concatenate or fuse those attribute vectors with the main style embeddings. When searching, reweight or filter candidate items based on the requested attribute constraints. Alternatively, train a separate attribute-based model and combine its scores with the triplet-based similarity for the final recommendation. Both approaches let the user filter for specific attributes while still benefiting from the overall style compatibility model.</p><h2><strong>Follow-up question 4</strong></h2><p>How would you diagnose and fix potential failure cases where recommended products appear incompatible?</p><p><strong>Answer</strong>: Start by examining the distance distributions or the embeddings of problematic items. Visualize them with something like t-SNE or UMAP to see if they cluster incorrectly. If certain materials or colors are mixing, refine the training set to ensure those distinctions are present in the triplets. If the model overemphasizes shape but ignores subtle texture differences, incorporate more triplets highlighting texture mismatches. Reviewing negative examples manually helps identify missing style cues. Another debugging approach is model ablation, temporarily removing cross-entropy or other auxiliary heads to see which component leads to improvement or regression. Continuous iteration on data curation and loss balancing usually resolves such misclassifications.</p><p></p><p></p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.rohan-paul.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">I write everyday for my readers on actionable AI. Subscribe and instantly get a 1300+ page Python book.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[ML Case-study Interview Question: Bayesian Thompson Sampling for Product Ranking: Addressing Bias and Sparsity]]></title><description><![CDATA[Browse all the ML Case-Studies here.]]></description><link>https://www.rohan-paul.com/p/ml-case-study-interview-question-bad</link><guid isPermaLink="false">https://www.rohan-paul.com/p/ml-case-study-interview-question-bad</guid><dc:creator><![CDATA[Rohan Paul]]></dc:creator><pubDate>Tue, 22 Apr 2025 08:35:25 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!D3OC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5da563be-82ce-4e76-81c2-620e9c6cc4f4_1024x494.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!D3OC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5da563be-82ce-4e76-81c2-620e9c6cc4f4_1024x494.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!D3OC!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5da563be-82ce-4e76-81c2-620e9c6cc4f4_1024x494.png 424w, https://substackcdn.com/image/fetch/$s_!D3OC!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5da563be-82ce-4e76-81c2-620e9c6cc4f4_1024x494.png 848w, https://substackcdn.com/image/fetch/$s_!D3OC!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5da563be-82ce-4e76-81c2-620e9c6cc4f4_1024x494.png 1272w, https://substackcdn.com/image/fetch/$s_!D3OC!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5da563be-82ce-4e76-81c2-620e9c6cc4f4_1024x494.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!D3OC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5da563be-82ce-4e76-81c2-620e9c6cc4f4_1024x494.png" width="1024" height="494" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5da563be-82ce-4e76-81c2-620e9c6cc4f4_1024x494.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:494,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:932849,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.rohan-paul.com/i/161866162?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5da563be-82ce-4e76-81c2-620e9c6cc4f4_1024x494.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!D3OC!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5da563be-82ce-4e76-81c2-620e9c6cc4f4_1024x494.png 424w, https://substackcdn.com/image/fetch/$s_!D3OC!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5da563be-82ce-4e76-81c2-620e9c6cc4f4_1024x494.png 848w, https://substackcdn.com/image/fetch/$s_!D3OC!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5da563be-82ce-4e76-81c2-620e9c6cc4f4_1024x494.png 1272w, https://substackcdn.com/image/fetch/$s_!D3OC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5da563be-82ce-4e76-81c2-620e9c6cc4f4_1024x494.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Browse all the <strong><a href="https://www.rohan-paul.com/s/ml-case-study/archive?sort=new">ML Case-Studies here</a></strong>.</p><h1><strong>Case-Study question</strong></h1><h2><strong>A major online retailer maintains a massive catalog with millions of products. The goal is to rank these products so that first-time visitors see items with the broadest overall appeal. Historical product performance data is distorted by position bias: items shown in top positions get more orders regardless of their intrinsic appeal. Many products have limited or zero ordering history, creating more uncertainty in estimates. The retailer wants a system that:</strong></h2><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://x.com/rohanpaul_ai&quot;,&quot;text&quot;:&quot;Connect with me on X (Twitter)&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://x.com/rohanpaul_ai"><span>Connect with me on X (Twitter)</span></a></p><ol><li><p>Identifies each product&#8217;s intrinsic popularity, adjusting for position biases and other factors (device type, filtering, etc.).</p></li><li><p>Combines multiple signals (click, cart-add, order) to reduce reliance on sparse order data.</p></li><li><p>Dynamically updates estimates and adapts to new data without retraining on the entire historical dataset each time.</p></li><li><p>Uses an explore-exploit ranking strategy to uncover potential top-performers while still prioritizing best-known products.</p></li></ol><p>Propose a detailed approach to solve this. Outline your methodology, explain the algorithms, demonstrate how you would handle position bias, data sparsity, and incorporate Bayesian updating. Finally, propose how to rank items in real-time for every new visitor.</p><h4><strong>Proposed Detailed Solution</strong></h4><h4><strong>Modeling Intrinsic Appeal</strong></h4><p>Start with a logistic regression model that factors in product-specific effects and position-specific effects. Represent the probability that a customer will order product i at position j as a function of a product effect plus a position effect.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!9_Pa!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa63e2226-8fec-4aa3-9be8-c3c6af1e5440_561x188.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!9_Pa!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa63e2226-8fec-4aa3-9be8-c3c6af1e5440_561x188.png 424w, https://substackcdn.com/image/fetch/$s_!9_Pa!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa63e2226-8fec-4aa3-9be8-c3c6af1e5440_561x188.png 848w, https://substackcdn.com/image/fetch/$s_!9_Pa!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa63e2226-8fec-4aa3-9be8-c3c6af1e5440_561x188.png 1272w, https://substackcdn.com/image/fetch/$s_!9_Pa!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa63e2226-8fec-4aa3-9be8-c3c6af1e5440_561x188.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!9_Pa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa63e2226-8fec-4aa3-9be8-c3c6af1e5440_561x188.png" width="561" height="188" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a63e2226-8fec-4aa3-9be8-c3c6af1e5440_561x188.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:188,&quot;width&quot;:561,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:15043,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.rohan-paul.com/i/161866162?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa63e2226-8fec-4aa3-9be8-c3c6af1e5440_561x188.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!9_Pa!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa63e2226-8fec-4aa3-9be8-c3c6af1e5440_561x188.png 424w, https://substackcdn.com/image/fetch/$s_!9_Pa!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa63e2226-8fec-4aa3-9be8-c3c6af1e5440_561x188.png 848w, https://substackcdn.com/image/fetch/$s_!9_Pa!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa63e2226-8fec-4aa3-9be8-c3c6af1e5440_561x188.png 1272w, https://substackcdn.com/image/fetch/$s_!9_Pa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa63e2226-8fec-4aa3-9be8-c3c6af1e5440_561x188.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Right side: beta_i is the product-specific effect capturing the item&#8217;s intrinsic appeal, and alpha_j is the position effect capturing how visibility influences likelihood of an order.</p><p>Historical click and order patterns drive estimation. Observed order rates at different positions separate product-specific appeal from position bias. In practice, add more factors: device type, filters, and so on.</p><h4><strong>Incorporating Multiple Signals</strong></h4><p>Many products have scant order data. Add intermediate actions (click, add-to-cart) to refine estimates:</p><h1><strong>P(order&#8739;shown)=P(click&#8739;shown)&#215;P(add to cart&#8739;click)&#215;P(order&#8739;add to cart)</strong></h1><p>This chain rule separates the steps leading to an order. Each part uses a smaller logistic regression that updates based on user behavior. If cart-add or order rates are unreliable for a new product, clicks alone still guide partial ranking decisions.</p><h4><strong>Bayesian Estimation and Updating</strong></h4><p>Bayesian estimation uses prior distributions over product effects. This stabilizes estimates for items with scarce data. For example, no item should jump to the very top for a single successful impression. Each day or hour, incorporate new user actions to form a posterior distribution for each product. Maintain an autoregressive &#8220;forgetting&#8221; scheme so the model remains flexible to shifts in product popularity and seasonality, without discarding older data entirely.</p><h4><strong>Ranking and Thompson Sampling</strong></h4><p>Purely exploiting the highest posterior means might overlook hidden gems. Thompson sampling balances exploitation and exploration. Sample from each product&#8217;s posterior. Rank items by their sampled values each time a user arrives. This produces slight variations in item positions, gathering new feedback to refine the model.</p><p>Engineered this way, the system shows high-appeal products on top most of the time but also tests alternatives. Over time, the posterior distributions tighten, and truly appealing products stand out.</p><h4><strong>Practical Implementation Details</strong></h4><p>Use Python for quick iteration. Libraries such as pystan (or other probabilistic frameworks) streamline posterior estimation. Store logistic regression coefficients and covariance matrices. Update them incrementally each day or in real-time. Rerank on page-load or query time by sampling from the posterior distributions, then sorting accordingly. Collect new impressions, clicks, and orders, which become tomorrow&#8217;s input.</p><p>Leverage data pipelines that track user actions at scale. For big catalogs, index product-level data in a scalable store. Use a distributed environment to handle real-time queries efficiently.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.rohan-paul.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">I write everyday for my readers on actionable AI. Subscribe and instantly get a 1300+ page Python book.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2><strong>Follow-up Question 1</strong></h2><p>How would you handle the risk that your Bayesian model might not converge quickly enough for products with extremely volatile or trending popularity?</p><p>The main challenge is that older data can mislead estimates for items experiencing sharp shifts in popularity. Slower-moving priors can delay correct updates.</p><p><strong>Answer and Explanation</strong> Shorten the forgetting horizon to adjust more aggressively. Increase the weight of recent data in the posterior update. Place more flexible priors on the product effects if certain categories have rapidly changing trends. Monitor items with unusual variance or a sudden surge in signals, and boost their exploration rate to gather more data quickly. In a production system, keep a dynamic schedule that speeds up updates for high-volatility items. For instance, if a product experiences massive changes in click-through rates, the system triggers accelerated Bayesian updates for that product alone.</p><h2><strong>Follow-up Question 2</strong></h2><p>How would you detect when a new product under the current approach is showing consistently high add-to-cart rates but a suspiciously low conversion to actual orders?</p><p>Some products might appear to have strong appeal but get abandoned at checkout. This can skew the model if not addressed.</p><p><strong>Answer and Explanation</strong> Compare cart conversion rates (orders / cart-adds) for each item against the average for similar categories or subcategories. If a product has an unusually low ratio, recheck factors like price changes, shipping details, or issues discovered at checkout. Introduce a penalty factor that lowers the final ranking for items with low cart-to-order conversion. Adjust the logistic regression to weigh the final ordering step more heavily. If we see consistently weak transitions from cart to purchase, feed negative updates into that product&#8217;s posterior distribution so its overall order probability is reduced accordingly.</p><h2><strong>Follow-up Question 3</strong></h2><p>What if you want to add extra context, like detailed product attributes or shopper attributes, into the model?</p><p>The business might want to personalize or highlight new items.</p><p><strong>Answer and Explanation</strong> Incorporate product metadata (brand, style, price range) in a feature vector. For user-level personalization, add shopper features (geolocation, browsing history). Switch to a hierarchical Bayesian model or a factorization machine approach. If you suspect nonlinearities, kernel-based methods or neural networks could capture interactions. Adjust the logistic regression to expand the predictor space with cross-terms. Rely on partial pooling: products sharing certain attributes will have correlated priors, helping new items that lack historical data.</p><h2><strong>Follow-up Question 4</strong></h2><p>How would you verify that Thompson sampling is truly beneficial versus a simpler epsilon-greedy strategy in this ranking context?</p><p>The company needs evidence that the explore-exploit method yields tangible gains.</p><p><strong>Answer and Explanation</strong> Run controlled A/B experiments comparing Thompson sampling with an epsilon-greedy baseline. Track average order rates, click-through rates, and coverage of the catalog. Check how often rare items get shown and how many eventually emerge as top sellers. If Thompson sampling outperforms by discovering better products faster and maintaining strong overall performance, then you have empirical proof. Look at engagement metrics and the pace at which new items find traction. If the difference is negligible, revisit hyperparameters and data scale. Sometimes simpler strategies may suffice in smaller catalogs or stable environments.</p><h2><strong>Follow-up Question 5</strong></h2><p>How do you ensure efficient real-time ranking while updating potentially millions of posterior parameters?</p><p>The engineering challenge is huge.</p><p><strong>Answer and Explanation</strong> Cache partial model outputs. Maintain a separate high-speed service that stores the latest posterior parameters. When a user arrives, sample product effects from a fast random generator pre-seeded with the updated means and variances. Sort them for the page. Use approximate sampling methods or low-rank matrix factorizations to reduce overhead. For large catalogs, maintain a stream processing architecture. Break updates into incremental batches so the main service only merges small parameter changes. This keeps daily or hourly updates feasible without blocking real-time recommendations.</p><p></p><p></p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.rohan-paul.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">I write everyday for my readers on actionable AI. Subscribe and instantly get a 1300+ page Python book.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[ML Case-study Interview Question: Explainable ML for Triaging E-commerce Fraud Orders]]></title><description><![CDATA[Browse all the ML Case-Studies here.]]></description><link>https://www.rohan-paul.com/p/ml-case-study-interview-question-e4e</link><guid isPermaLink="false">https://www.rohan-paul.com/p/ml-case-study-interview-question-e4e</guid><dc:creator><![CDATA[Rohan Paul]]></dc:creator><pubDate>Tue, 22 Apr 2025 08:27:09 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!HTkn!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7798ec7-5814-41bd-8b57-ae07b4be126b_1920x1080.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!HTkn!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7798ec7-5814-41bd-8b57-ae07b4be126b_1920x1080.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!HTkn!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7798ec7-5814-41bd-8b57-ae07b4be126b_1920x1080.png 424w, https://substackcdn.com/image/fetch/$s_!HTkn!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7798ec7-5814-41bd-8b57-ae07b4be126b_1920x1080.png 848w, https://substackcdn.com/image/fetch/$s_!HTkn!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7798ec7-5814-41bd-8b57-ae07b4be126b_1920x1080.png 1272w, https://substackcdn.com/image/fetch/$s_!HTkn!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7798ec7-5814-41bd-8b57-ae07b4be126b_1920x1080.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!HTkn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7798ec7-5814-41bd-8b57-ae07b4be126b_1920x1080.png" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e7798ec7-5814-41bd-8b57-ae07b4be126b_1920x1080.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1935328,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.rohan-paul.com/i/161865969?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7798ec7-5814-41bd-8b57-ae07b4be126b_1920x1080.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!HTkn!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7798ec7-5814-41bd-8b57-ae07b4be126b_1920x1080.png 424w, https://substackcdn.com/image/fetch/$s_!HTkn!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7798ec7-5814-41bd-8b57-ae07b4be126b_1920x1080.png 848w, https://substackcdn.com/image/fetch/$s_!HTkn!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7798ec7-5814-41bd-8b57-ae07b4be126b_1920x1080.png 1272w, https://substackcdn.com/image/fetch/$s_!HTkn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7798ec7-5814-41bd-8b57-ae07b4be126b_1920x1080.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Browse all the <strong><a href="https://www.rohan-paul.com/s/ml-case-study/archive?sort=new">ML Case-Studies here</a></strong>.</p><h1><strong>Case-Study question</strong></h1><h2><strong>An e-commerce platform faces suspicious credit card orders that might be fraudulent. They want a binary classification system to distinguish fraudulent orders from legitimate ones. The solution must handle three categories: Fraud, Non-Fraud, and a middle region of uncertain cases sent to human reviewers. The leadership demands explanations for each automated decision to assist the manual review process. Design a fraud detection pipeline using machine learning, describe how you would train and evaluate it, and explain how you would integrate model interpretability techniques for local and global explanations.</strong></h2><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://x.com/rohanpaul_ai&quot;,&quot;text&quot;:&quot;Connect with me on X (Twitter)&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://x.com/rohanpaul_ai"><span>Connect with me on X (Twitter)</span></a></p><h4><strong>Detailed Solution Approach</strong></h4><p>Treat this as a supervised classification problem with labeled historical orders. Split the data into Fraud and Non-Fraud labels, and place uncertain samples into a third set for manual escalation. Use features like account age, billing-to-shipping address match, previous order count, and others relevant to suspicious activity. Train a predictive model such as a tree-based classifier or a neural network.</p><p>Model performance must be measured in terms of precision and recall for Fraud detection. Avoid high false positives because that annoys genuine customers, and avoid high false negatives because that can lose money.</p><p>Use an explainability framework that supports local (per order) and global (across all orders) interpretations. Global explanations help the data science team verify overall feature importance. Local explanations help human reviewers see why a particular order is flagged.</p><h4><strong>Model Selection and Training</strong></h4><p>Many start with logistic regression or decision trees. For logistic regression, an interpretable global view is straightforward because the model is a weighted sum of features. A typical logistic regression prediction for probability p can be shown by:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!FlP3!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8b00ff71-efcd-46ca-bc14-90b5b60744bd_682x214.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!FlP3!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8b00ff71-efcd-46ca-bc14-90b5b60744bd_682x214.png 424w, https://substackcdn.com/image/fetch/$s_!FlP3!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8b00ff71-efcd-46ca-bc14-90b5b60744bd_682x214.png 848w, https://substackcdn.com/image/fetch/$s_!FlP3!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8b00ff71-efcd-46ca-bc14-90b5b60744bd_682x214.png 1272w, https://substackcdn.com/image/fetch/$s_!FlP3!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8b00ff71-efcd-46ca-bc14-90b5b60744bd_682x214.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!FlP3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8b00ff71-efcd-46ca-bc14-90b5b60744bd_682x214.png" width="682" height="214" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8b00ff71-efcd-46ca-bc14-90b5b60744bd_682x214.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:214,&quot;width&quot;:682,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:10200,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.rohan-paul.com/i/161865969?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8b00ff71-efcd-46ca-bc14-90b5b60744bd_682x214.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!FlP3!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8b00ff71-efcd-46ca-bc14-90b5b60744bd_682x214.png 424w, https://substackcdn.com/image/fetch/$s_!FlP3!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8b00ff71-efcd-46ca-bc14-90b5b60744bd_682x214.png 848w, https://substackcdn.com/image/fetch/$s_!FlP3!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8b00ff71-efcd-46ca-bc14-90b5b60744bd_682x214.png 1272w, https://substackcdn.com/image/fetch/$s_!FlP3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8b00ff71-efcd-46ca-bc14-90b5b60744bd_682x214.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Here, p is the predicted probability of Fraud. b0, b1, ..., bn are learned coefficients, and x1, x2, ..., xn are input features. Large positive coefficients for a feature mean that feature increases the likelihood of Fraud, and large negative coefficients do the opposite.</p><p>Decision trees also have a direct explanation path from root to leaf. Random forests or gradient boosting frameworks can improve accuracy but require more intricate explanation methods. After initial hyperparameter tuning, evaluate with cross-validation and measure classification metrics such as AUC or average precision.</p><h4><strong>Introducing Explanation Methods</strong></h4><p>Permutation Importance checks how shuffling each feature affects model performance. For correlated features, it may underestimate importance because one feature can compensate for another.</p><p>LIME (Local Interpretable Model-Agnostic Explanations) perturbs one sample&#8217;s features and trains a simpler model to mimic the complex model&#8217;s decision boundaries near that sample. This local surrogate reveals which feature changes drive the decision for a single order. However, LIME can produce variability in the presence of redundant features.</p><p>SHAP (SHapley Additive exPlanations) uses ideas from game theory to measure each feature&#8217;s contribution. It often yields consistent local explanations and can also aggregate results to give a global perspective. Tree-based models can be explained very efficiently with specialized SHAP implementations.</p><h4><strong>Integrating Human Review</strong></h4><p>Some orders remain uncertain. Route them to a manual queue. Provide a local explanation so reviewers see which features contributed most to classifying an order as Fraud. For example, if no 2-factor authentication is present, or the billing city doesn&#8217;t match the shipping city, highlight those as key risk signals. This transparency builds trust in the model.</p><h4><strong>Example Code Snippet</strong></h4><p>A simple Python snippet using scikit-learn could look like this:</p><pre><code><code>import pandas as pd
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report

data = pd.read_csv("orders.csv")
X = data.drop("fraud_label", axis=1)
y = data["fraud_label"]

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)

model = DecisionTreeClassifier(max_depth=5, random_state=42)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
print(classification_report(y_test, y_pred))
</code></code></pre><p>Train separate models or a single model with a threshold for uncertain outputs that get escalated. Then integrate LIME or SHAP to generate local explanations for each order.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.rohan-paul.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">I write everyday for my readers on actionable AI. Subscribe and instantly get a 1300+ page Python book.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2><strong>Potential Follow-Up Question 1</strong></h2><p>How do you handle correlated features in permutation-based importance?</p><p><strong>Answer:</strong> Correlated features lead to confusion in permutation importance because shuffling one feature at a time may not degrade performance if the same information is captured by another feature. Group features into sets or permute them jointly. Another approach is to use SHAP or partial dependency plots, which better handle shared information between features.</p><h2><strong>Potential Follow-Up Question 2</strong></h2><p>Why would you pick SHAP over LIME in certain scenarios?</p><p><strong>Answer:</strong> SHAP assigns consistent importance values anchored in coalitional game theory. It fairly distributes credit among features for each prediction and shows stable results across many samples. LIME generates local surrogates via randomized perturbations, so it can produce less stable explanations if features are highly correlated or if the data manifold is complex. SHAP also offers a fast tree-based explainer.</p><h2><strong>Potential Follow-Up Question 3</strong></h2><p>How would you address model bias in Fraud detection?</p><p><strong>Answer:</strong> Check for bias by slicing data on sensitive attributes and inspecting metrics. Compare false positive and false negative rates across demographic groups. Use fairness frameworks or specialized constraints like demographic parity or equalized odds. If bias is found, rebalance the dataset or adjust training with reweighing or adversarial methods. Evaluate interpretability across groups to ensure the model is consistent.</p><h2><strong>Potential Follow-Up Question 4</strong></h2><p>How do you handle real-time scoring and updates to the model?</p><p><strong>Answer:</strong> Use a pipeline that loads the trained model into a service endpoint. When a new order arrives, extract the relevant features, apply any transformations, and run the model inference. Capture feedback from the fraud investigation team and continuously retrain the model as fraud patterns evolve. Consider a feature store for consistent transformations. Monitor model drift by analyzing changing data distributions.</p><h2><strong>Potential Follow-Up Question 5</strong></h2><p>What kind of logging and monitoring would you implement?</p><p><strong>Answer:</strong> Log prediction probabilities and final classification decisions for each order. Track feedback loops when manual reviewers override the decision. Keep metrics over time (daily or weekly) to detect shifts in patterns or performance drops. Implement alerting when certain thresholds (like false positives or recall) go out of range. Logging helps with auditing and regulatory requirements for explainable decisions.</p><p></p><p></p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.rohan-paul.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">I write everyday for my readers on actionable AI. Subscribe and instantly get a 1300+ page Python book.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[ML Case-study Interview Question: Scalable Personalized Ad Optimization with Contextual Bandits & Importance Weighted Regression.]]></title><description><![CDATA[Browse all the ML Case-Studies here.]]></description><link>https://www.rohan-paul.com/p/ml-case-study-interview-question-e97</link><guid isPermaLink="false">https://www.rohan-paul.com/p/ml-case-study-interview-question-e97</guid><dc:creator><![CDATA[Rohan Paul]]></dc:creator><pubDate>Tue, 22 Apr 2025 08:23:35 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!iEKq!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F732c57ca-8064-4bf0-b8e2-fb6a846416b5_1024x576.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!iEKq!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F732c57ca-8064-4bf0-b8e2-fb6a846416b5_1024x576.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!iEKq!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F732c57ca-8064-4bf0-b8e2-fb6a846416b5_1024x576.png 424w, https://substackcdn.com/image/fetch/$s_!iEKq!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F732c57ca-8064-4bf0-b8e2-fb6a846416b5_1024x576.png 848w, https://substackcdn.com/image/fetch/$s_!iEKq!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F732c57ca-8064-4bf0-b8e2-fb6a846416b5_1024x576.png 1272w, https://substackcdn.com/image/fetch/$s_!iEKq!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F732c57ca-8064-4bf0-b8e2-fb6a846416b5_1024x576.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!iEKq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F732c57ca-8064-4bf0-b8e2-fb6a846416b5_1024x576.png" width="1024" height="576" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/732c57ca-8064-4bf0-b8e2-fb6a846416b5_1024x576.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:576,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1058335,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.rohan-paul.com/i/161865791?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F732c57ca-8064-4bf0-b8e2-fb6a846416b5_1024x576.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!iEKq!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F732c57ca-8064-4bf0-b8e2-fb6a846416b5_1024x576.png 424w, https://substackcdn.com/image/fetch/$s_!iEKq!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F732c57ca-8064-4bf0-b8e2-fb6a846416b5_1024x576.png 848w, https://substackcdn.com/image/fetch/$s_!iEKq!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F732c57ca-8064-4bf0-b8e2-fb6a846416b5_1024x576.png 1272w, https://substackcdn.com/image/fetch/$s_!iEKq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F732c57ca-8064-4bf0-b8e2-fb6a846416b5_1024x576.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Browse all the <strong><a href="https://www.rohan-paul.com/s/ml-case-study/archive?sort=new">ML Case-Studies here</a></strong>.</p><h1><strong>Case-Study question</strong></h1><h2><strong>A major tech company manages a large-scale online retail platform and needs to optimize marketing decisions at the customer level for paid media channels. Each day, millions of user-level decisions must be made on whether to show an ad or not, how much to bid for the ad space, and how to adjust strategies based on real-time feedback. Propose a contextual bandit approach to make these decisions efficiently. Specifically, describe how you would set up the problem (defining context, actions, rewards), design the reward estimation process, address bias in observational data, and choose an exploration algorithm. How would you ensure that the system can operate at scale with continuous updates to the model?</strong></h2><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://x.com/rohanpaul_ai&quot;,&quot;text&quot;:&quot;Connect with me on X (Twitter)&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://x.com/rohanpaul_ai"><span>Connect with me on X (Twitter)</span></a></p><h4><strong>Detailed Solution</strong></h4><p>Contextual bandits can optimize personalized marketing treatments by combining two components: a <strong>reward estimator</strong> and an <strong>exploration algorithm</strong>.</p><p>Explain the steps:</p><p>(1) <strong>Problem Setup</strong> Use a contextual bandit framework with:</p><ul><li><p>Context x capturing user attributes such as browsing history and demographics.</p></li><li><p>Actions a representing whether to display an ad or not (or multiple ad variants).</p></li><li><p>Reward r representing profit or revenue generated if the user converts.</p></li></ul><p>(2) <strong>Reward Estimation</strong> Model the conditional expected reward for each action. One way is to train a separate regressor per action, f(x, a). Another way is to combine x with action-dependent features x_a and learn a single model parameterized by theta. Naively fitting these regressors to minimize mean squared error can cause bias when certain actions are favored more frequently, reducing data coverage elsewhere.</p><p>(3) <strong>Correcting for Bias</strong> Importance Weighted Regression (IWR) is used to remove bias introduced by uneven propensities of actions in historical or ongoing data collection. The main formula for importance weighted mean squared error is:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!oniX!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8fbdb376-5ae1-4a28-9428-4347b1c93496_972x202.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!oniX!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8fbdb376-5ae1-4a28-9428-4347b1c93496_972x202.png 424w, https://substackcdn.com/image/fetch/$s_!oniX!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8fbdb376-5ae1-4a28-9428-4347b1c93496_972x202.png 848w, https://substackcdn.com/image/fetch/$s_!oniX!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8fbdb376-5ae1-4a28-9428-4347b1c93496_972x202.png 1272w, https://substackcdn.com/image/fetch/$s_!oniX!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8fbdb376-5ae1-4a28-9428-4347b1c93496_972x202.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!oniX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8fbdb376-5ae1-4a28-9428-4347b1c93496_972x202.png" width="972" height="202" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8fbdb376-5ae1-4a28-9428-4347b1c93496_972x202.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:202,&quot;width&quot;:972,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:26515,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.rohan-paul.com/i/161865791?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8fbdb376-5ae1-4a28-9428-4347b1c93496_972x202.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!oniX!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8fbdb376-5ae1-4a28-9428-4347b1c93496_972x202.png 424w, https://substackcdn.com/image/fetch/$s_!oniX!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8fbdb376-5ae1-4a28-9428-4347b1c93496_972x202.png 848w, https://substackcdn.com/image/fetch/$s_!oniX!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8fbdb376-5ae1-4a28-9428-4347b1c93496_972x202.png 1272w, https://substackcdn.com/image/fetch/$s_!oniX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8fbdb376-5ae1-4a28-9428-4347b1c93496_972x202.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Here, p_{a_i} is the propensity of having chosen action a_i for context x_i. When p_{a_i} is small, the sample is given a higher weight.</p><p>(4) <strong>Exploration Algorithms</strong> An explorer uses the learned reward estimates to generate a probability distribution over actions. The simplest is epsilon-greedy, which picks the best action most of the time and randomly explores otherwise. More advanced methods like Softmax or SquareCB assign probabilities proportional to estimated rewards, balancing exploration and exploitation more fluidly.</p><p>(5) <strong>Scalability</strong> Implementing this approach at scale requires:</p><ul><li><p>A fast data pipeline to collect new rewards.</p></li><li><p>Near real-time updates to the model parameters.</p></li><li><p>Efficient libraries (for example, an online active learning library) that handle large volumes of data with incremental training.</p></li></ul><p>(6) <strong>Practical Deployment</strong> Maintain a feedback loop:</p><ul><li><p>For each user context, produce action probabilities.</p></li><li><p>Stochastically choose an action based on these probabilities.</p></li><li><p>Observe the reward.</p></li><li><p>Update the model using importance weighted regression or cost-sensitive classification.</p></li></ul><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.rohan-paul.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">I write everyday for my readers on actionable AI. Subscribe and instantly get a 1300+ page Python book.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2><strong>How would you handle multiple actions or creative variants?</strong></h2><p>A system with many possible ads or creative treatments can still follow the same procedure. Represent each ad variant with its own parameter set or expand the feature vector to include ad-specific attributes. Use the same approach of reward estimation with inverse propensity weighting and an exploration strategy that scales over large action sets.</p><h2><strong>How would you tackle delayed rewards?</strong></h2><p>Often users may convert hours or days after an ad impression. One approach is to build a separate model to forecast eventual conversion or profit. Feed the predicted reward into the contextual bandit model. Continuously update with real outcomes once they become known.</p><h2><strong>What about cold-start scenarios?</strong></h2><p>When there is little data for certain user segments or new ad treatments, the system can default to uniform exploration or a prior-based approach. Over time, data collection fills the gaps, and the bandit algorithm adjusts accordingly.</p><h2><strong>How do you ensure unbiased reward estimation in production?</strong></h2><p>Use inverse propensity scoring or doubly robust methods to reweight logged data. Log the propensities and actions to correct for any distributional shifts. Periodically audit the model's predictions and actual outcomes for signs of bias.</p><h2><strong>How would you manage hyperparameters or tuning?</strong></h2><p>Techniques include:</p><ul><li><p>Using a hold-out set or offline evaluation with counterfactual estimators (IPS or doubly robust).</p></li><li><p>Tuning exploration parameters (epsilon, temperature in Softmax, or parameters in ensemble methods) by measuring cumulative reward or other internal metrics.</p></li></ul><h2><strong>How would you evaluate this approach offline?</strong></h2><p>Use counterfactual policy evaluation:</p><ul><li><p>Logged data has context x_i, action a_i, reward r_i, and logging probability p_{a_i}.</p></li><li><p>Estimate the policy's expected reward with an IPS estimator: E[R_policy] = (1/N) * sum( r_i / p_{a_i} ) for all i where the policy chooses action a_i. Compare multiple candidate policies or hyperparameters before online deployment.</p></li></ul><h2><strong>How do you handle non-stationary environments?</strong></h2><p>Implement continuous exploration and frequent model updates. Methods like Softmax or ensemble-based explorers keep sampling different actions to detect changes. Adaptive discounting of older data can help if user behavior shifts over time.</p><h2><strong>How can you address cost or budget constraints?</strong></h2><p>Add cost factors into the reward definition. Instead of only tracking revenue, define reward = revenue - cost. The same contextual bandit techniques apply. If the cost is high, the model may learn to reduce expensive exposures that do not yield enough benefit.</p><h2><strong>How would you structure the engineering pipeline?</strong></h2><p>Store and stream user events in real time. Train or update the reward estimators with importance-weighted methods incrementally. Serve the model behind an API that returns action probabilities. Log chosen actions, probabilities, and rewards. Schedule periodic retraining or continuous online learning, depending on the tooling.</p><h2><strong>What if there are privacy concerns about storing user data?</strong></h2><p>Anonymize or hash identifiers. Aggregate sensitive features. Apply differential privacy or stricter security measures if needed. The bandit framework still works with high-level or obfuscated features.</p><h2><strong>How would you integrate contextual bandits with existing rules-based marketing?</strong></h2><p>Blend rules-based constraints (such as never serving certain ads to minors) into the action space or the reward function. The bandit model can then select from the remaining feasible actions. Alternatively, apply policy constraints that override or filter out invalid actions before sampling from the bandit.</p><p></p><p></p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.rohan-paul.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">I write everyday for my readers on actionable AI. Subscribe and instantly get a 1300+ page Python book.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[ML Case-study Interview Question: Constrained Optimization for Personalized Promotion Assignment with Share of Voice Targets.]]></title><description><![CDATA[Browse all the ML Case-Studies here.]]></description><link>https://www.rohan-paul.com/p/ml-case-study-interview-question-615</link><guid isPermaLink="false">https://www.rohan-paul.com/p/ml-case-study-interview-question-615</guid><dc:creator><![CDATA[Rohan Paul]]></dc:creator><pubDate>Tue, 22 Apr 2025 08:20:29 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!6S4w!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F19b01d87-4866-4cc3-8a68-13b91919cda4_1024x509.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!6S4w!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F19b01d87-4866-4cc3-8a68-13b91919cda4_1024x509.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!6S4w!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F19b01d87-4866-4cc3-8a68-13b91919cda4_1024x509.png 424w, https://substackcdn.com/image/fetch/$s_!6S4w!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F19b01d87-4866-4cc3-8a68-13b91919cda4_1024x509.png 848w, https://substackcdn.com/image/fetch/$s_!6S4w!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F19b01d87-4866-4cc3-8a68-13b91919cda4_1024x509.png 1272w, https://substackcdn.com/image/fetch/$s_!6S4w!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F19b01d87-4866-4cc3-8a68-13b91919cda4_1024x509.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!6S4w!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F19b01d87-4866-4cc3-8a68-13b91919cda4_1024x509.png" width="1024" height="509" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/19b01d87-4866-4cc3-8a68-13b91919cda4_1024x509.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:509,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:860426,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.rohan-paul.com/i/161865505?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F19b01d87-4866-4cc3-8a68-13b91919cda4_1024x509.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!6S4w!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F19b01d87-4866-4cc3-8a68-13b91919cda4_1024x509.png 424w, https://substackcdn.com/image/fetch/$s_!6S4w!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F19b01d87-4866-4cc3-8a68-13b91919cda4_1024x509.png 848w, https://substackcdn.com/image/fetch/$s_!6S4w!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F19b01d87-4866-4cc3-8a68-13b91919cda4_1024x509.png 1272w, https://substackcdn.com/image/fetch/$s_!6S4w!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F19b01d87-4866-4cc3-8a68-13b91919cda4_1024x509.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Browse all the <strong><a href="https://www.rohan-paul.com/s/ml-case-study/archive?sort=new">ML Case-Studies here</a></strong>.</p><h1><strong>Case-Study question</strong></h1><h2><strong>You are given a commerce platform that displays multiple promotional messages to customers on its homepage. Each homepage has several placements where one message can appear. You have a broad set of possible promotional messages, each corresponding to a product category or service. Marketing leaders require specific minimum and maximum Share of Voice (SoV) targets for each category. They also want to ensure each customer sees only one message per placement, and certain messages are not repeated across placements for the same customer. You have machine learning scores indicating each customer's likelihood to respond to each message, plus a measure of how valuable each placement is. Formulate a solution that assigns exactly one message to each placement for each customer, maximizing overall relevance while satisfying SoV targets and business constraints. Propose an end-to-end strategy, including the mathematical formulation, algorithmic approach, and plan for production deployment and real-time assignment.</strong></h2><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://x.com/rohanpaul_ai&quot;,&quot;text&quot;:&quot;Connect with me on X (Twitter)&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://x.com/rohanpaul_ai"><span>Connect with me on X (Twitter)</span></a></p><h2><strong>Detailed solution approach</strong></h2><h4><strong>Problem Definition</strong></h4><p>This scenario requires maximizing the total relevance of messages shown to customers while adhering to Share of Voice (SoV) targets. SoV targets specify how often (as a percentage of total impressions) certain categories or messages appear. The challenge is to assign messages to multiple homepage placements. Each assignment must observe constraints such as not duplicating a message for the same customer and respecting which messages can appear in which placements.</p><h4><strong>Mathematical Formulation</strong></h4><p>Define a binary decision variable X_{i,j,k} indicating whether customer i sees message j in placement k. Let relevance(i,j) be the predicted relevance score of message j for customer i, and let value(k) be a factor representing the importance of placement k.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!GWIA!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8e4800b-d634-48eb-848f-552cf4b65a5e_1050x154.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!GWIA!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8e4800b-d634-48eb-848f-552cf4b65a5e_1050x154.png 424w, https://substackcdn.com/image/fetch/$s_!GWIA!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8e4800b-d634-48eb-848f-552cf4b65a5e_1050x154.png 848w, https://substackcdn.com/image/fetch/$s_!GWIA!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8e4800b-d634-48eb-848f-552cf4b65a5e_1050x154.png 1272w, https://substackcdn.com/image/fetch/$s_!GWIA!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8e4800b-d634-48eb-848f-552cf4b65a5e_1050x154.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!GWIA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8e4800b-d634-48eb-848f-552cf4b65a5e_1050x154.png" width="1050" height="154" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a8e4800b-d634-48eb-848f-552cf4b65a5e_1050x154.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:154,&quot;width&quot;:1050,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:24368,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.rohan-paul.com/i/161865505?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8e4800b-d634-48eb-848f-552cf4b65a5e_1050x154.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!GWIA!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8e4800b-d634-48eb-848f-552cf4b65a5e_1050x154.png 424w, https://substackcdn.com/image/fetch/$s_!GWIA!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8e4800b-d634-48eb-848f-552cf4b65a5e_1050x154.png 848w, https://substackcdn.com/image/fetch/$s_!GWIA!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8e4800b-d634-48eb-848f-552cf4b65a5e_1050x154.png 1272w, https://substackcdn.com/image/fetch/$s_!GWIA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8e4800b-d634-48eb-848f-552cf4b65a5e_1050x154.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Each variable X_{i,j,k} can be 0 or 1. The objective function adds up the overall relevance across all customers, messages, and placements, weighted by the placement value.</p><p>Constraints include:</p><ol><li><p>Each placement must be filled: for every customer i and placement k, exactly one message is assigned. In text form: sum of j over X_{i,j,k} = 1.</p></li><li><p>A message cannot appear multiple times for the same customer. For each i and j, sum of k over X_{i,j,k} &lt;= 1.</p></li><li><p>Share of Voice constraints: for each message j, the proportion of total assigned impressions must fall within predefined lower and upper SoV bounds.</p></li><li><p>Placement applicability constraints: if message j is not allowed in placement k, then X_{i,j,k} = 0.</p></li></ol><h4><strong>Model Inputs</strong></h4><p>A matrix of relevance(i,j) values is produced by product-specific or service-specific propensity models. Each row i is a customer, each column j is a message. A placement value matrix stores the relative worth of each homepage slot. The SoV constraints come from marketing.</p><h4><strong>Solver and Algorithmic Approach</strong></h4><p>Using a solver such as Gurobi, define X_{i,j,k} as binary decision variables. Include the SoV constraints as linear inequalities. The solver will then optimize the objective under these constraints. Because the dimension of (customers, messages, placements) can be large, batch customers into smaller groups in parallel. Randomly sample large sets of customers in batches and solve each batch separately. Collect batch outputs into a single final assignment. Store these results in a data repository or caching service.</p><p>When a recognized customer arrives, a lookup returns that customer's assigned messages for each placement. If the customer is unknown, show messages based on a random assignment that respects SoV bounds.</p><h4><strong>Engineering Implementation</strong></h4><p>Use Python code with Gurobi's Python API. For each batch:</p><ol><li><p>Load the subset of customers and their propensity scores.</p></li><li><p>Define the decision variables X_{i,j,k}.</p></li><li><p>Add constraints for SoV, single-message-per-placement, and no message repetition.</p></li><li><p>Add the objective function.</p></li><li><p>Call the solver.</p></li><li><p>Write results to a table for consumption by the homepage service.</p></li></ol><p>Example Python snippet for setting up Gurobi:</p><pre><code><code>import gurobipy as gp
from gurobipy import GRB

m = gp.Model("SoV_Optimization")

X = {}
for i in range(num_customers):
    for j in range(num_messages):
        for k in range(num_placements):
            X[(i,j,k)] = m.addVar(vtype=GRB.BINARY, name=f"X_{i}_{j}_{k}")

# Objective
m.setObjective(
    gp.quicksum(
        relevance[i][j] * placement_value[k] * X[(i,j,k)]
        for i in range(num_customers)
        for j in range(num_messages)
        for k in range(num_placements)
    ),
    GRB.MAXIMIZE
)

# Constraints (single example shown)
# Each customer i and placement k must have exactly one message
for i in range(num_customers):
    for k in range(num_placements):
        m.addConstr(
            gp.quicksum(X[(i,j,k)] for j in range(num_messages)) == 1
        )

m.optimize()
</code></code></pre><p>Parallelize this process across multiple machines or in a distributed manner if needed to handle large datasets.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.rohan-paul.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">I write everyday for my readers on actionable AI. Subscribe and instantly get a 1300+ page Python book.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2><strong>Follow-up question: Handling conflicting SoV bounds</strong></h2><p>How would you handle a scenario where the lower and upper SoV bounds for a certain message conflict with other messages' SoV bounds, making the solution infeasible?</p><h4><strong>Detailed Answer</strong></h4><p>Identify if the sum of lower bounds across all messages exceeds the total available placements or if the sum of upper bounds is less than the total placements to fill. Adjust or relax certain constraints based on business priorities. Another approach is to introduce a small slack variable in the SoV constraints. Penalize the slack in the objective to keep the solution close to feasible SoV requirements while allowing the solver to find a solution.</p><h2><strong>Follow-up question: Reducing computational complexity</strong></h2><p>What methods would you use to speed up or approximate the solver if the number of customers is extremely large?</p><h4><strong>Detailed Answer</strong></h4><p>Apply batching by randomly sampling subsets of customers. Optimize each subset independently. Merge results into a final assignment table. Use warm starts or partial solutions from previous runs to guide the solver for the next batch. Reduce message categories by grouping similar items under one label. Use heuristics or approximate algorithms like Lagrangian relaxation if an exact solver proves too slow. Cache stable assignments to avoid re-solving for the same customers.</p><h2><strong>Follow-up question: Ensuring fairness among different product categories</strong></h2><p>If you need to ensure that new or niche product categories also get enough representation without always losing to popular products, how do you modify your solution?</p><h4><strong>Detailed Answer</strong></h4><p>Add constraints or a custom weighting scheme favoring newer categories. Increase their predicted relevance via a prior or offset factor. Set mandatory minimum SoV constraints for these categories. In the optimization function, add higher placement_value multipliers for these categories or create a penalty term if certain categories fall below a threshold. These adjustments push the solver to assign them more impressions.</p><h2><strong>Follow-up question: Handling real-time or near real-time assignment changes</strong></h2><p>When you need to update messages dynamically (for instance, a flash sale for a certain product line), how do you adapt the solver approach?</p><h4><strong>Detailed Answer</strong></h4><p>Pre-run daily or hourly optimizations and store the solution. For sudden changes, run a smaller incremental solver pass focusing only on impacted messages or subsets of customers, reassigning only those cells. Maintain the existing assignment for unaffected segments. This keeps computations lower while still adapting quickly. If the system requires near-instant updates, switch to a streaming or approximate approach, such as a fast heuristic that respects updated SoV constraints until the next batch solver run.</p><h2><strong>Follow-up question: Model calibration</strong></h2><p>How do you address potential errors in the relevance predictions, ensuring the optimization still meets business goals?</p><h4><strong>Detailed Answer</strong></h4><p>Periodically evaluate predicted versus actual conversion or engagement metrics. Retrain or recalibrate propensity models. Adjust the solver's objective function weights if certain categories are being over- or under-promoted. Implement an online learning loop to refine model parameters. If some categories perform worse than predicted, reduce their assigned SoV or their relevance scores. Continually monitor Key Performance Indicators like click-through rates and orders to fine-tune.</p><h2><strong>Follow-up question: Implementation pitfalls</strong></h2><p>What are common pitfalls you must watch out for in production?</p><h4><strong>Detailed Answer</strong></h4><p>Inconsistent data feeds for customer scores lead to incorrect assignments. Overly strict SoV bounds can create infeasible solutions. Missing constraints cause messages to repeat or remain unfilled. Large-scale solver timeouts if batching is not configured efficiently. Inadequate monitoring of the final assignments can mask performance issues. Validation checks after solver output are critical before serving the assignments to users.</p><p></p><p></p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.rohan-paul.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">I write everyday for my readers on actionable AI. Subscribe and instantly get a 1300+ page Python book.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[ML Case-study Interview Question: Optimizing Cross-Channel Marketing Spend Using Reinforcement Learning and Uplift Modeling]]></title><description><![CDATA[Browse all the ML Case-Studies here.]]></description><link>https://www.rohan-paul.com/p/ml-case-study-interview-question-154</link><guid isPermaLink="false">https://www.rohan-paul.com/p/ml-case-study-interview-question-154</guid><dc:creator><![CDATA[Rohan Paul]]></dc:creator><pubDate>Tue, 22 Apr 2025 08:14:51 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!qGfS!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fc04873-6001-4d35-9a22-ee8d4691f93d_1920x1080.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!qGfS!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fc04873-6001-4d35-9a22-ee8d4691f93d_1920x1080.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!qGfS!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fc04873-6001-4d35-9a22-ee8d4691f93d_1920x1080.png 424w, https://substackcdn.com/image/fetch/$s_!qGfS!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fc04873-6001-4d35-9a22-ee8d4691f93d_1920x1080.png 848w, https://substackcdn.com/image/fetch/$s_!qGfS!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fc04873-6001-4d35-9a22-ee8d4691f93d_1920x1080.png 1272w, https://substackcdn.com/image/fetch/$s_!qGfS!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fc04873-6001-4d35-9a22-ee8d4691f93d_1920x1080.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!qGfS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fc04873-6001-4d35-9a22-ee8d4691f93d_1920x1080.png" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3fc04873-6001-4d35-9a22-ee8d4691f93d_1920x1080.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1922704,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.rohan-paul.com/i/161865336?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fc04873-6001-4d35-9a22-ee8d4691f93d_1920x1080.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!qGfS!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fc04873-6001-4d35-9a22-ee8d4691f93d_1920x1080.png 424w, https://substackcdn.com/image/fetch/$s_!qGfS!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fc04873-6001-4d35-9a22-ee8d4691f93d_1920x1080.png 848w, https://substackcdn.com/image/fetch/$s_!qGfS!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fc04873-6001-4d35-9a22-ee8d4691f93d_1920x1080.png 1272w, https://substackcdn.com/image/fetch/$s_!qGfS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fc04873-6001-4d35-9a22-ee8d4691f93d_1920x1080.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Browse all the <strong><a href="https://www.rohan-paul.com/s/ml-case-study/archive?sort=new">ML Case-Studies here</a></strong>.</p><h1><strong>Case-Study question</strong></h1><h2><strong>A large online retailer manages many ads across social media, search, email, push notifications, and direct mail. They want to optimize marketing spend, improve ad effectiveness, and personalize messaging to the right audience. They have general-purpose models predicting purchase intent and channel-specific models for individual campaigns. They also experiment with uplift modeling to measure true incremental impact. They recently started developing a multi-layer system that uses reinforcement learning to balance &#8220;explore vs. exploit&#8221; actions across multiple channels. Propose a comprehensive plan to design, build, and maintain their marketing ML system. Include details on how you would approach data collection, training, model deployment, and long-term scaling. Suggest how to measure success, incorporate feedback loops, and integrate new business or industry changes. Describe what you would prioritize first if you were hired as a Senior Data Scientist.</strong></h2><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://x.com/rohanpaul_ai&quot;,&quot;text&quot;:&quot;Connect with me on X (Twitter)&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://x.com/rohanpaul_ai"><span>Connect with me on X (Twitter)</span></a></p><h4><strong>Detailed Solution</strong></h4><p>General marketing ML systems aim to select relevant content, present it to the right audience, and manage budget constraints. A robust ecosystem usually has the following layers.</p><h4><strong>General Propensity Modeling</strong></h4><p>Many organizations first build a propensity modeling pipeline to identify users most likely to buy or engage. One common model is a binary classification system (for example, logistic regression) that outputs a conversion probability for each user. This approach leverages historical behavioral data (page views, past purchases, etc.) to predict future purchase likelihood.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!-zVr!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0130cf6-9f2f-4e86-be22-d6167696f705_467x153.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!-zVr!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0130cf6-9f2f-4e86-be22-d6167696f705_467x153.png 424w, https://substackcdn.com/image/fetch/$s_!-zVr!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0130cf6-9f2f-4e86-be22-d6167696f705_467x153.png 848w, https://substackcdn.com/image/fetch/$s_!-zVr!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0130cf6-9f2f-4e86-be22-d6167696f705_467x153.png 1272w, https://substackcdn.com/image/fetch/$s_!-zVr!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0130cf6-9f2f-4e86-be22-d6167696f705_467x153.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!-zVr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0130cf6-9f2f-4e86-be22-d6167696f705_467x153.png" width="467" height="153" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d0130cf6-9f2f-4e86-be22-d6167696f705_467x153.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:153,&quot;width&quot;:467,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:9253,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.rohan-paul.com/i/161865336?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0130cf6-9f2f-4e86-be22-d6167696f705_467x153.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!-zVr!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0130cf6-9f2f-4e86-be22-d6167696f705_467x153.png 424w, https://substackcdn.com/image/fetch/$s_!-zVr!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0130cf6-9f2f-4e86-be22-d6167696f705_467x153.png 848w, https://substackcdn.com/image/fetch/$s_!-zVr!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0130cf6-9f2f-4e86-be22-d6167696f705_467x153.png 1272w, https://substackcdn.com/image/fetch/$s_!-zVr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0130cf6-9f2f-4e86-be22-d6167696f705_467x153.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Here, p(x) is the probability of conversion for feature vector x. w is the weight vector learned from data. b is the bias term. The model can be extended with more sophisticated algorithms, such as gradient boosting or neural networks. The output is used to rank users by their likelihood to convert.</p><p>This solution is scalable because the same model output can be applied to many channels. Maintenance is also easier: a single pipeline calculates conversion probabilities and shares them with downstream campaigns. However, it can cause over-messaging if different channels all chase the same high-propensity audience. It also lacks explicit measurement of incremental impact.</p><h4><strong>Specialized Response and Uplift Modeling</strong></h4><p>Some channels need their own specialized models that predict a user&#8217;s response to a specific ad or measure true incremental lift. A channel-specific response model can handle unique data signals (for example, retargeting signals if someone left items in a cart). For deeper insights, an uplift model compares predicted outcomes under treatment vs. control.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!D1cu!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1c6904d-48e9-45c8-b5d6-c32fcebec7cd_1230x103.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!D1cu!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1c6904d-48e9-45c8-b5d6-c32fcebec7cd_1230x103.png 424w, https://substackcdn.com/image/fetch/$s_!D1cu!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1c6904d-48e9-45c8-b5d6-c32fcebec7cd_1230x103.png 848w, https://substackcdn.com/image/fetch/$s_!D1cu!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1c6904d-48e9-45c8-b5d6-c32fcebec7cd_1230x103.png 1272w, https://substackcdn.com/image/fetch/$s_!D1cu!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1c6904d-48e9-45c8-b5d6-c32fcebec7cd_1230x103.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!D1cu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1c6904d-48e9-45c8-b5d6-c32fcebec7cd_1230x103.png" width="1230" height="103" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f1c6904d-48e9-45c8-b5d6-c32fcebec7cd_1230x103.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:103,&quot;width&quot;:1230,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:20152,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.rohan-paul.com/i/161865336?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1c6904d-48e9-45c8-b5d6-c32fcebec7cd_1230x103.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!D1cu!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1c6904d-48e9-45c8-b5d6-c32fcebec7cd_1230x103.png 424w, https://substackcdn.com/image/fetch/$s_!D1cu!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1c6904d-48e9-45c8-b5d6-c32fcebec7cd_1230x103.png 848w, https://substackcdn.com/image/fetch/$s_!D1cu!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1c6904d-48e9-45c8-b5d6-c32fcebec7cd_1230x103.png 1272w, https://substackcdn.com/image/fetch/$s_!D1cu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1c6904d-48e9-45c8-b5d6-c32fcebec7cd_1230x103.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>P(conversion|treated) is the predicted conversion rate if an ad is shown. P(conversion|control) is the predicted rate if no ad is shown. This approach requires randomized tests for ground truth data. Each channel might run A/B tests to gather labeled outcomes (treated vs. control). This is expensive if done across many campaigns. Maintenance becomes harder because each channel gets its own model and experiment framework.</p><h4><strong>Multi-layer RL-based Platform</strong></h4><p>A multi-layer RL-based system maximizes overall marketing performance rather than focusing on single-channel metrics. One layer learns user-level embeddings or scores (as above). Another layer, typically a reinforcement learning module, assigns actions (which ad, which channel, how often) to each user. It adjusts decisions over time based on observed rewards (clicks, revenue, or long-term metrics).</p><p>A feedback layer also helps the RL system learn from delayed outcomes. The system might map short-term events (like clicks) into a forecast of longer-term revenue. This approach updates the treatment policy at regular intervals to keep pace with new conditions. It can handle multiple objectives, such as preventing ad fatigue or capping daily budget.</p><h4><strong>Practical Implementation Details</strong></h4><p>Data collection starts with pipelines that aggregate user behavior, ad impressions, conversions, and campaign costs. The data is stored in a centralized warehouse. Daily or weekly training jobs update general propensity models and specialized models. A separate process runs reinforcement learning training using the data feed of past actions and rewards.</p><p>Model deployment uses versioned artifacts. General propensity models get updated at intervals (monthly or quarterly). The RL optimization layer might refresh more frequently (daily or even hourly) if the system is built to handle real-time training. A strategic approach ensures that if the RL policy fails or data changes unexpectedly, a backup rule-based system can keep marketing running.</p><p>Long-term scaling involves automating experiment management. For uplift modeling, building robust pipelines for randomizing treatment and control is crucial. Data scientists track each user&#8217;s experimental condition to label outcomes accurately. This RCT framework ensures that any new channel or targeting strategy can integrate with uplift measurement.</p><p>Monitoring success requires tracking business KPIs over time: incremental revenue, return on ad spend, and engagement. Each channel feeds data into a central dashboard so the team can spot problems early and refine model parameters. If a channel&#8217;s strategy changes&#8212;like new creative or a shift in user privacy policies&#8212;the RL layer adjusts as soon as the reward signals show changes in user response.</p><p>Early priorities might include:</p><ul><li><p>Ensuring consistent, high-quality data ingestion.</p></li><li><p>Implementing a stable pipeline for training and serving general propensity scores.</p></li><li><p>Setting up frameworks to run incremental tests and measure actual lift.</p></li><li><p>Deploying an RL-based optimization layer once consistent data streams and baseline models are stable.</p></li></ul><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.rohan-paul.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">I write everyday for my readers on actionable AI. Subscribe and instantly get a 1300+ page Python book.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2><strong>What strategies would you adopt for validation and backtesting?</strong></h2><p>A robust validation strategy checks that the models deliver stable and accurate predictions. Historical backtesting can replicate how the model would have performed if it had been deployed during past time windows. It involves splitting data by time and ensuring that training data does not overlap with future events. Once the model is live, an online experiment&#8212;such as an A/B test at the campaign level&#8212;verifies whether predicted improvements translate into real outcomes.</p><p>Cross-validation on rolling time windows is often done for offline validation. Models should be retrained on older slices of data, then tested on the subsequent time segment. This reveals performance drift if user behavior changes or seasonality appears. After offline testing, real-world A/B tests confirm whether the uplift the model promises actually occurs. Such tests are especially critical for uplift modeling, where random treatment assignment is required to measure genuine incremental impacts.</p><h2><strong>How would you address over-messaging and campaign cannibalization?</strong></h2><p>Over-messaging occurs when multiple campaigns target the same group too often, causing annoyance and diminishing returns. An RL-based approach can incorporate penalty terms in its reward function to reduce repeated impressions on the same user. Alternatively, it can cap the maximum number of impressions per user within a time window.</p><p>A centralized coordinator can track each user&#8217;s total impression count and enforce global frequency constraints. If two channels both plan to send messages to a user in the same day, the coordinator can let only the highest expected-value campaign proceed. This logic can be part of the decision optimization layer. If a user is at high risk of unsubscribing or ignoring ads, the system can pause or reduce the marketing frequency.</p><h2><strong>Why is uplift modeling more expensive to maintain than propensity modeling?</strong></h2><p>Uplift modeling requires continuous randomization for building labeled datasets. For every wave of marketing, a subset of users must be held out to receive no treatment. This ensures that the uplift model learns the counterfactual: what would have happened without exposure. Such holdouts can result in opportunity costs because some users will not see a potentially profitable ad. The process also demands extra tracking to mark who is in treatment vs. control, then measure the outcome differences.</p><p>Propensity modeling, on the other hand, uses observational data with no special experimental design. It is cheaper to scale, but it cannot directly quantify incremental impact since it lacks a true untreated control group. Uplift modeling is more accurate for measuring net gain, but it is more costly and complex to maintain.</p><h2><strong>How would you design the reinforcement learning system for real-time adjustment?</strong></h2><p>A reinforcement learning agent collects user and ad features, runs an action selection policy (which ad or channel to show), and observes a reward signal (click, purchase, or longer-term KPI). A typical architecture uses an online learning loop with the following steps:</p><ol><li><p>For each user impression opportunity, the system scores actions based on the current policy.</p></li><li><p>It logs the chosen action, the user&#8217;s context, and the immediate or short-term outcome.</p></li><li><p>A separate process periodically updates model parameters using batch data from the logged interactions.</p></li><li><p>The new policy is deployed to production.</p></li></ol><p>To handle delayed rewards such as conversions that happen hours or days later, a forward-looking forecast can estimate partial rewards from immediate signals (clicks, site visits). A longer training window accounts for conversions that arrive after some delay. If the environment changes frequently (new products, marketing constraints), the system retrains more often. Thorough monitoring flags any policy drift or performance shortfall.</p><h2><strong>How would you measure the system&#8217;s overall success?</strong></h2><p>Return on Ad Spend (ROAS) and incremental revenue are primary metrics. One approach is to run a global holdout group that does not receive these advanced model-driven treatments. The difference in cumulative revenue and profit between the treatment group and the holdout group shows the net benefit. Another approach is to track user-level metrics such as sign-up rates, average revenue per user, or retention, especially if the business cares about long-term relationships. If overall performance lifts without damaging user experience, the system is succeeding.</p><p>Technical stability also matters. Monitoring the number of model crashes, data pipeline failures, or unusual CPU/memory usage can help ensure the system is robust. If the system remains stable under traffic spikes, that is a strong sign of readiness for more channels.</p><h2><strong>How do you handle privacy or industry changes?</strong></h2><p>Privacy regulations or shifts in ad-tech (for example, less access to certain user identifiers) can disrupt features used for targeting. A robust pipeline must adapt by limiting PII usage, anonymizing data, and relying on aggregated signals. If an identifier becomes unavailable, feature engineering may refocus on contextual or first-party site data. The RL system can rely more on aggregated performance signals. Frequent retraining helps recalibrate decisions when data distributions shift.</p><p>Models can also incorporate synthetic or privacy-preserving signals: for instance, summary-level statistics for a user segment instead of detailed user-level data. If the system is well modularized, removing or replacing certain features does not break the entire pipeline. Documentation and monitoring are critical. As soon as performance drops or data coverage changes, the team can retrain or refactor.</p><p></p><p></p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.rohan-paul.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">I write everyday for my readers on actionable AI. Subscribe and instantly get a 1300+ page Python book.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[ML Case-study Interview Question: Transformer Self-Attention Models for Adaptive E-commerce Recommendations]]></title><description><![CDATA[Browse all the ML Case-Studies here.]]></description><link>https://www.rohan-paul.com/p/ml-case-study-interview-question-26a</link><guid isPermaLink="false">https://www.rohan-paul.com/p/ml-case-study-interview-question-26a</guid><dc:creator><![CDATA[Rohan Paul]]></dc:creator><pubDate>Tue, 22 Apr 2025 08:11:20 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!AsyO!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e671356-0203-4dc2-9dd0-a3c25f7629e0_1920x1080.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!AsyO!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e671356-0203-4dc2-9dd0-a3c25f7629e0_1920x1080.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!AsyO!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e671356-0203-4dc2-9dd0-a3c25f7629e0_1920x1080.png 424w, https://substackcdn.com/image/fetch/$s_!AsyO!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e671356-0203-4dc2-9dd0-a3c25f7629e0_1920x1080.png 848w, https://substackcdn.com/image/fetch/$s_!AsyO!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e671356-0203-4dc2-9dd0-a3c25f7629e0_1920x1080.png 1272w, https://substackcdn.com/image/fetch/$s_!AsyO!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e671356-0203-4dc2-9dd0-a3c25f7629e0_1920x1080.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!AsyO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e671356-0203-4dc2-9dd0-a3c25f7629e0_1920x1080.png" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9e671356-0203-4dc2-9dd0-a3c25f7629e0_1920x1080.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1928620,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.rohan-paul.com/i/161865144?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e671356-0203-4dc2-9dd0-a3c25f7629e0_1920x1080.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!AsyO!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e671356-0203-4dc2-9dd0-a3c25f7629e0_1920x1080.png 424w, https://substackcdn.com/image/fetch/$s_!AsyO!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e671356-0203-4dc2-9dd0-a3c25f7629e0_1920x1080.png 848w, https://substackcdn.com/image/fetch/$s_!AsyO!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e671356-0203-4dc2-9dd0-a3c25f7629e0_1920x1080.png 1272w, https://substackcdn.com/image/fetch/$s_!AsyO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e671356-0203-4dc2-9dd0-a3c25f7629e0_1920x1080.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Browse all the <strong><a href="https://www.rohan-paul.com/s/ml-case-study/archive?sort=new">ML Case-Studies here</a></strong>.</p><h1><strong>Case-Study question</strong></h1><h2><strong>A fast-growing e-commerce company experiences rapidly shifting customer preferences. They observe that customers often browse many products in one category, then suddenly shift to new styles or categories. They want a new recommendation system that can adapt to these changes and transfer learned preferences from one product class to another. They only have access to user browsing history sequences. Design a system that addresses these challenges, improves top-n recall, and leverages minimal data beyond the browse sequence. How would you build this model, and why? Propose the solution, outline the data transformations, model architecture, training approach, and explain how you would evaluate it.</strong></h2><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://x.com/rohanpaul_ai&quot;,&quot;text&quot;:&quot;Connect with me on X (Twitter)&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://x.com/rohanpaul_ai"><span>Connect with me on X (Twitter)</span></a></p><h2><strong>Detailed solution approach</strong></h2><h4><strong>Model Architecture</strong></h4><p>Transformers are well-suited for sequence modeling of user browse histories. They use <strong>self-attention</strong> to capture which items in a sequence are most relevant at predicting a user's next product interest. They handle parallel computation effectively, training faster than recurrent methods.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!lEi3!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed06959c-76b9-4100-b2af-c99224285ffe_901x178.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!lEi3!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed06959c-76b9-4100-b2af-c99224285ffe_901x178.png 424w, https://substackcdn.com/image/fetch/$s_!lEi3!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed06959c-76b9-4100-b2af-c99224285ffe_901x178.png 848w, https://substackcdn.com/image/fetch/$s_!lEi3!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed06959c-76b9-4100-b2af-c99224285ffe_901x178.png 1272w, https://substackcdn.com/image/fetch/$s_!lEi3!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed06959c-76b9-4100-b2af-c99224285ffe_901x178.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!lEi3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed06959c-76b9-4100-b2af-c99224285ffe_901x178.png" width="901" height="178" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ed06959c-76b9-4100-b2af-c99224285ffe_901x178.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:178,&quot;width&quot;:901,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:23876,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.rohan-paul.com/i/161865144?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed06959c-76b9-4100-b2af-c99224285ffe_901x178.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!lEi3!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed06959c-76b9-4100-b2af-c99224285ffe_901x178.png 424w, https://substackcdn.com/image/fetch/$s_!lEi3!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed06959c-76b9-4100-b2af-c99224285ffe_901x178.png 848w, https://substackcdn.com/image/fetch/$s_!lEi3!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed06959c-76b9-4100-b2af-c99224285ffe_901x178.png 1272w, https://substackcdn.com/image/fetch/$s_!lEi3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed06959c-76b9-4100-b2af-c99224285ffe_901x178.png 1456w" sizes="100vw"></picture><div></div></div></a></figure></div><p>Q, K, and V are the query, key, and value matrices derived from the same input embeddings of the user's browse sequence. d_k is the dimensionality of the key vectors.</p><p>The model processes each item in the input sequence, creating item embeddings and adding positional embeddings to reflect the order in which products were viewed. The final output is a vector of scores over all items in the product catalog, ranking them to produce top-n recommendations.</p><h4><strong>Data Preparation</strong></h4><p>Browsing data is sorted chronologically. Rare items are filtered out to reduce noise. Consecutive duplicate items are removed because they do not add extra signals. If a user has viewed more than 100 items, only the 100 most recent are kept; if fewer, zero-padding is applied.</p><h4><strong>Training Details</strong></h4><p>A binary cross-entropy loss is used to predict whether a user will interact with a given item. A sigmoid function produces a probability for each item. Dropout and L2-regularization mitigate overfitting. Layer normalization and residual connections stabilize gradients and ease training. Learned positional embeddings capture how recent interactions affect current preferences.</p><h4><strong>Transfer of Learned Preferences</strong></h4><p>Truncating or zero-padding sequences focuses the model on the most relevant portion of a user&#8217;s browsing history. Self-attention highlights recent product transitions, enabling the model to shift recommendations when user style changes. Substitutable classes (for example, multiple sofa types) share strong feature similarities like color or material. Complementary classes (like sofas and coffee tables) share weaker signals, but the model uncovers them through style or aesthetic cues. Subtracting the mean embedding per class isolates style preferences from strong class-specific signals.</p><h4><strong>Metrics and Performance</strong></h4><p>Recall at top-n is a key metric. The model is evaluated on whether the recommended items match future purchases. The model should show significant lift over simpler methods such as matrix factorization or top-popular baselines. A 67% lift in recall for top-6 predictions indicates high accuracy gains. Visualizing positional embeddings and item embedding clusters confirms that the transformer is modeling user preference shifts and grouping similar styles together.</p><h4><strong>Practical Example</strong></h4><p>Users browsing beds may switch from a traditional design to a modern design. The model sees the recency of the modern product views and re-ranks modern products higher. When users change categories, the embedding space uncovers style consistency across different classes, recommending items with similar aesthetics or price range.</p><h4><strong>Implementation Snippet</strong></h4><pre><code><code>import torch
import torch.nn as nn
import torch.nn.functional as F

class TransformerRec(nn.Module):
    def __init__(self, num_items, embed_dim, num_heads, num_layers):
        super().__init__()
        self.item_embedding = nn.Embedding(num_items, embed_dim)
        self.position_embedding = nn.Embedding(100, embed_dim)
        encoder_layers = nn.TransformerEncoderLayer(d_model=embed_dim,
                                                    nhead=num_heads,
                                                    batch_first=True)
        self.transformer_encoder = nn.TransformerEncoder(encoder_layers, num_layers)
        self.fc = nn.Linear(embed_dim, num_items)

    def forward(self, x):
        seq_len = x.size(1)
        positions = torch.arange(0, seq_len, device=x.device).unsqueeze(0)
        x = self.item_embedding(x) + self.position_embedding(positions)
        x = self.transformer_encoder(x)
        x = x[:, -1, :]  # Use last hidden state
        logits = self.fc(x)
        return logits
</code></code></pre><p>No advanced features like residual gating or class-based embedding subtraction are included here, but it demonstrates how to encode item and positional embeddings, feed them through a transformer, and output product scores.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.rohan-paul.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">I write everyday for my readers on actionable AI. Subscribe and instantly get a 1300+ page Python book.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2><strong>What if the dataset is sparse?</strong></h2><p>Sparse data arises when many users view few items or vice versa. Transformers can handle zero-padded sequences. L2-regularization, dropout, and restricted vocabulary (filtering rare items) reduce overfitting. Data augmentation strategies or content-based features (such as product images) may help with extremely sparse segments.</p><h2><strong>How to handle cold-start users or items?</strong></h2><p>New users lack browsing history. The model might default to popular items or rely on minimal signals. Cold-start items have no interactions. Embedding initialization from related items or using shared metadata helps. Another approach is to incorporate item side information (images, descriptive text) so the model can represent new items.</p><h2><strong>How to ensure scalability in production?</strong></h2><p>Transformers are more resource-intensive than simple matrix factorization. Techniques like limiting sequence length to 100 items, adjusting embedding dimensions, and employing multi-GPU distribution can handle large-scale e-commerce catalogs. Batching requests and caching the final hidden states for partial sequences speed up inference.</p><h2><strong>How to extend the model beyond browsing history?</strong></h2><p>Use user demographic or product content embeddings (images, text) to enrich item representations. Use multi-modal attention that fuses item IDs with learned representations from images or text. This approach captures style nuances better, improves generalization, and addresses cases where purely behavioral data is insufficient.</p><p></p><p></p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.rohan-paul.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">I write everyday for my readers on actionable AI. Subscribe and instantly get a 1300+ page Python book.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[ML Case-study Interview Question: Optimizing Millions of E-commerce Ad Bids via a Hybrid ML/Rules Architecture.]]></title><description><![CDATA[Browse all the ML Case-Studies here.]]></description><link>https://www.rohan-paul.com/p/ml-case-study-interview-question-449</link><guid isPermaLink="false">https://www.rohan-paul.com/p/ml-case-study-interview-question-449</guid><dc:creator><![CDATA[Rohan Paul]]></dc:creator><pubDate>Tue, 22 Apr 2025 08:06:55 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!zmPi!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93dc0b56-9ef8-47ea-a21b-07075d3e6794_1024x533.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!zmPi!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93dc0b56-9ef8-47ea-a21b-07075d3e6794_1024x533.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!zmPi!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93dc0b56-9ef8-47ea-a21b-07075d3e6794_1024x533.png 424w, https://substackcdn.com/image/fetch/$s_!zmPi!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93dc0b56-9ef8-47ea-a21b-07075d3e6794_1024x533.png 848w, https://substackcdn.com/image/fetch/$s_!zmPi!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93dc0b56-9ef8-47ea-a21b-07075d3e6794_1024x533.png 1272w, https://substackcdn.com/image/fetch/$s_!zmPi!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93dc0b56-9ef8-47ea-a21b-07075d3e6794_1024x533.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!zmPi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93dc0b56-9ef8-47ea-a21b-07075d3e6794_1024x533.png" width="1024" height="533" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/93dc0b56-9ef8-47ea-a21b-07075d3e6794_1024x533.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:533,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:951448,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.rohan-paul.com/i/161864558?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93dc0b56-9ef8-47ea-a21b-07075d3e6794_1024x533.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!zmPi!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93dc0b56-9ef8-47ea-a21b-07075d3e6794_1024x533.png 424w, https://substackcdn.com/image/fetch/$s_!zmPi!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93dc0b56-9ef8-47ea-a21b-07075d3e6794_1024x533.png 848w, https://substackcdn.com/image/fetch/$s_!zmPi!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93dc0b56-9ef8-47ea-a21b-07075d3e6794_1024x533.png 1272w, https://substackcdn.com/image/fetch/$s_!zmPi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93dc0b56-9ef8-47ea-a21b-07075d3e6794_1024x533.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Browse all the <strong><a href="https://www.rohan-paul.com/s/ml-case-study/archive?sort=new">ML Case-Studies here</a></strong>.</p><h1><strong>Case-Study question</strong></h1><h2><strong>You are given an e-commerce platform's ads bidding scenario. The system must generate optimal cost-per-click bids across millions of product listings and keywords. The platform attempts to combine heuristic- and ML-based algorithms under a single architecture, while ensuring scalability, observability, and easy experimentation. How would you design a complete end-to-end ads bidding solution for this company, including data ingestion, feature engineering, model training, bid arbitration, and final bid deployment? What challenges do you foresee, and how do you address them?</strong></h2><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://x.com/rohanpaul_ai&quot;,&quot;text&quot;:&quot;Connect with me on X (Twitter)&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://x.com/rohanpaul_ai"><span>Connect with me on X (Twitter)</span></a></p><h4><strong>Detailed In-Depth Solution</strong></h4><p>The core challenge is to decide how much to pay for each click without overspending or missing potential traffic. This requires high-volume data pipelines, robust model deployment, real-time adjustments, and analytics.</p><h4><strong>Data Engineering</strong></h4><p>Large streams of events flow in from internal logs and external ad platforms. Engineers build a unified pipeline that aggregates, cleans, and standardizes features. These features include historical spend, click-through rates, conversions, product attributes, and search keywords. A modular data transformation system avoids large fragile scripts. Instead, each transformation is a small, reusable unit. Records are enriched with various flags or values (for example, abnormal spikes can be filtered or imputed).</p><h4><strong>Bidding Console</strong></h4><p>A console allows business analysts or data scientists to specify objectives such as ROI = (Revenue - Cost)/Cost. It also enables them to calibrate aggressiveness or maintain budgets for specific product groups. Users tune these levers at different granularity (for example, individual product lines).</p><h4><strong>Single Bid Calculators</strong></h4><p>Each calculator takes a bidding unit (for example, a single SKU) and uses the relevant features to produce a bid. One calculator might use a rule-based approach (for instance, a simple multiple of past average cost-per-click). Another might load a trained regression or neural model to forecast expected profit margin, then output a maximum willingness to pay.</p><p>The platform supports multiple calculators in parallel, each generating its own bid. This modular design encourages experimentation. If a new calculator performs well for certain products, the system can route relevant traffic to it.</p><h4><strong>Arbitration</strong></h4><p>When multiple calculators produce different bids, an arbitration component decides which bid to finalize. Sometimes the system picks the highest. Sometimes it falls back if the primary calculator lacks enough data. Sometimes it runs an A/B test to compare. This mixing approach broadens coverage and facilitates quick swaps of new approaches.</p><h4><strong>Vendor Mapping</strong></h4><p>Once the platform selects final bids, the system maps internal product identifiers into the identifiers expected by external channels (for example, vendor-specific campaign IDs). Bids are then pushed out through APIs (for instance, Google Ads or Bing Ads) at scale.</p><h4><strong>Key Technologies</strong></h4><p>A parallel data processing framework (such as a managed big data platform) scales these computations. A fast key-value store can fetch features and store final results with low latency. Python code can quickly load ML models in-memory. A robust SQL/analytics warehouse is essential for advanced queries, debugging, and validation. Containerized web services handle control-plane functionalities such as real-time updates and health checks.</p><h4><strong>Example Python Snippet</strong></h4><p>Below is a simplified illustration for a single bid calculator that uses a trained regression model:</p><pre><code><code>import joblib
import aerospike

# Load the regression model
model = joblib.load("my_regression_model.pkl")

# Connect to Aerospike for features
client = aerospike.client({"hosts": [("127.0.0.1", 3000)]}).connect()

def single_bid_calculator(bidding_unit):
    # Retrieve features
    key = ("namespace", "set_name", bidding_unit)
    _, _, record = client.get(key)

    # Example features
    avg_conversion_rate = record["avg_conversion_rate"]
    past_cpc = record["past_cpc"]
    # More features...

    # Model inference
    features_vec = [avg_conversion_rate, past_cpc]  # plus others as needed
    predicted_margin = model.predict([features_vec])[0]

    # Simple logic to produce a bid
    # We can refine formula or add business constraints
    recommended_bid = predicted_margin * 0.5

    return recommended_bid
</code></code></pre><h4><strong>Multi-Armed Bandit for Rapid Optimization</strong></h4><p>Some solutions use a multi-armed bandit approach to continuously adapt bidding strategies. A key formula for the upper confidence bound (UCB) method is:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Qvwv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9fe0cdd-ecbc-4d90-b3a1-1873d7232f85_620x214.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Qvwv!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9fe0cdd-ecbc-4d90-b3a1-1873d7232f85_620x214.png 424w, https://substackcdn.com/image/fetch/$s_!Qvwv!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9fe0cdd-ecbc-4d90-b3a1-1873d7232f85_620x214.png 848w, https://substackcdn.com/image/fetch/$s_!Qvwv!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9fe0cdd-ecbc-4d90-b3a1-1873d7232f85_620x214.png 1272w, https://substackcdn.com/image/fetch/$s_!Qvwv!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9fe0cdd-ecbc-4d90-b3a1-1873d7232f85_620x214.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Qvwv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9fe0cdd-ecbc-4d90-b3a1-1873d7232f85_620x214.png" width="620" height="214" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b9fe0cdd-ecbc-4d90-b3a1-1873d7232f85_620x214.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:214,&quot;width&quot;:620,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:17383,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.rohan-paul.com/i/161864558?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9fe0cdd-ecbc-4d90-b3a1-1873d7232f85_620x214.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Qvwv!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9fe0cdd-ecbc-4d90-b3a1-1873d7232f85_620x214.png 424w, https://substackcdn.com/image/fetch/$s_!Qvwv!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9fe0cdd-ecbc-4d90-b3a1-1873d7232f85_620x214.png 848w, https://substackcdn.com/image/fetch/$s_!Qvwv!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9fe0cdd-ecbc-4d90-b3a1-1873d7232f85_620x214.png 1272w, https://substackcdn.com/image/fetch/$s_!Qvwv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9fe0cdd-ecbc-4d90-b3a1-1873d7232f85_620x214.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Where:</p><ul><li><p>t is the total number of observations so far (sum of all arms&#8217; trials).</p></li><li><p>n_k(t) is how many times arm k was chosen until time t.</p></li><li><p>x_k(t) is the average observed reward for arm k.</p></li><li><p>UCB_k(t) is the optimistic estimate of the expected reward for arm k.</p></li></ul><p>The system picks the arm with the highest UCB, explores it, and updates statistics accordingly. This mechanism continuously balances exploration (trying new strategies or product categories) with exploitation (investing more heavily in proven strategies).</p><h4><strong>Challenges</strong></h4><p>Large catalogs demand careful scaling. Many items have sparse data or irregular traffic, so pure ML might fail unless combined with rules or fallback heuristics. Auction dynamics change frequently, so real-time or near-real-time updates are important. Observability is also vital. Analysts must see logs, metrics, or dashboards showing which model set a given bid and why.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.rohan-paul.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">I write everyday for my readers on actionable AI. Subscribe and instantly get a 1300+ page Python book.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2><strong>Follow-Up Question 1</strong></h2><p>How do you handle cold-start scenarios for new products or keywords with insufficient historical data?</p><p><strong>Answer Explanation</strong></p><p>Models rely on historical performance signals. New products have no clicks or conversions. A fallback model might produce a baseline bid (for instance, a category-average-based approach). Another possibility is to cluster products by similar attributes or predicted popularity, then use aggregated historical data from those clusters. A bandit-based approach that systematically tries uncertain arms speeds up the learning. Over time, new items accumulate enough data for more specialized models.</p><h2><strong>Follow-Up Question 2</strong></h2><p>How do you run experiments to compare different bidding models without harming overall performance?</p><p><strong>Answer Explanation</strong></p><p>Experimentation is controlled by the arbitration layer. The system can randomly assign a small percentage of traffic to a candidate model. The rest uses the incumbent approach. Analysts compare metrics such as click-through rate, conversion rate, cost per conversion, and overall ROI. If the new model outperforms the baseline, the system can gradually expand traffic. If performance drops or hits a safeguard threshold, the system reverts to the baseline to mitigate losses.</p><h2><strong>Follow-Up Question 3</strong></h2><p>How do you maintain system observability when multiple Single Bid Calculators and fallback rules exist?</p><p><strong>Answer Explanation</strong></p><p>Each calculator logs its decision path. The arbitration layer also logs which calculator's bid was chosen. Telemetry records final bids, real-time spend, and conversions. A unified dashboard aggregates these metrics by channel, product category, or date range. Engineers can pinpoint anomalies. Historical logs reveal how each model behaved over time and why certain bids were chosen. Continuous monitoring flags deviations from expected performance.</p><h2><strong>Follow-Up Question 4</strong></h2><p>What would you do if external ad platform constraints changed? For example, a new vendor requires daily budget caps in a different format.</p><p><strong>Answer Explanation</strong></p><p>A vendor-mapping step adapts bids and metadata to the external format. If a new vendor enforces daily budgets in a unique structure, engineers update the mapping logic without reworking the core platform. The console can add a parameter for daily budget caps per vendor, hooking into an API call that sets these caps. This separation ensures the core system remains consistent, and only vendor-specific translation layers change.</p><h2><strong>Follow-Up Question 5</strong></h2><p>How do you ensure the system remains modular when adding new ML algorithms or rules?</p><p><strong>Answer Explanation</strong></p><p>Each new approach is a separate Single Bid Calculator. That calculator reads the same standardized features. It calculates a new bid, returning either a numeric value or indicating insufficient data. The arbitration layer processes all returned bids. Because each calculator is a plug-in module, changes do not affect the rest of the pipeline. Observability, data ingestion, and vendor mapping remain consistent.</p><h2><strong>Follow-Up Question 6</strong></h2><p>Why might you consider switching from rules-based optimizations to a more automated bandit approach?</p><p><strong>Answer Explanation</strong></p><p>Manually setting or tuning rules is labor-intensive and might overfit historical patterns. A bandit approach explores unseen conditions and quickly identifies winning strategies. It adapts to real-time signals, making it more reactive to changing user behaviors, product availability, or shifts in competitor bidding. Automated exploration can discover opportunities that a fixed rules-based approach could overlook.</p><h2><strong>Follow-Up Question 7</strong></h2><p>How do you handle data latency and synchronization, given that you must update bids frequently?</p><p><strong>Answer Explanation</strong></p><p>Frequent updates need efficient data aggregation windows (for example, daily or hourly). Real-time streaming might be too costly for every calculation, so a near-real-time approach using micro-batching is typical. The platform uses a fast in-memory store to retrieve current statistics for quick lookups. Larger offline processes compute aggregated metrics. The system merges these pieces to produce stable bids with minimal lag.</p><h2><strong>Follow-Up Question 8</strong></h2><p>How would you scale this approach to millions of SKUs while maintaining accuracy and speed?</p><p><strong>Answer Explanation</strong></p><p>Use distributed data processing frameworks that split the workload across many executors. Each Single Bid Calculator runs independently on each SKU, enabling parallelism. A key-value or columnar store with indexing accelerates lookups. The entire pipeline is orchestrated so transformations and model predictions happen in parallel chunks. Containerization or managed job frameworks can spin up additional nodes for large spikes in SKU volume.</p><h2><strong>Follow-Up Question 9</strong></h2><p>What error or cost metrics do you monitor after deployment?</p><p><strong>Answer Explanation</strong></p><p>Ads cost can spike if bids are too high. Click volume can drop if bids are too low. ROI can degrade if user conversions do not keep pace with ad spend. Observing cost per conversion, overall click volume, conversions, and margins is critical. Significant deviations prompt investigation. The logs and dashboards let you see if a particular model or fallback is systematically bidding incorrectly.</p><h2><strong>Follow-Up Question 10</strong></h2><p>If a new acquisition channel emerges with a different bidding mechanism, how can you extend your platform?</p><p><strong>Answer Explanation</strong></p><p>The platform&#8217;s modular design applies. A new Single Bid Calculator can be developed for that channel&#8217;s unique data. The new channel also goes through the vendor-mapping step to convert internal identifiers to external IDs or handle unique budget constraints. Arbitration logic can incorporate this channel as an additional participant in the final bid mix. The same console and data pipeline handle configurations unless the new channel requires new features, in which case the pipeline is extended accordingly.</p><p></p><p></p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.rohan-paul.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">I write everyday for my readers on actionable AI. Subscribe and instantly get a 1300+ page Python book.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[ML Case-study Interview Question: Hierarchical Color Clustering for Accurate E-commerce Product Image Tagging]]></title><description><![CDATA[Browse all the ML Case-Studies here.]]></description><link>https://www.rohan-paul.com/p/ml-case-study-interview-question-33f</link><guid isPermaLink="false">https://www.rohan-paul.com/p/ml-case-study-interview-question-33f</guid><dc:creator><![CDATA[Rohan Paul]]></dc:creator><pubDate>Tue, 22 Apr 2025 07:50:21 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!BnZy!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbeaeb89f-9a0a-4d13-b8ab-860622479f92_1024x573.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!BnZy!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbeaeb89f-9a0a-4d13-b8ab-860622479f92_1024x573.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!BnZy!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbeaeb89f-9a0a-4d13-b8ab-860622479f92_1024x573.png 424w, https://substackcdn.com/image/fetch/$s_!BnZy!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbeaeb89f-9a0a-4d13-b8ab-860622479f92_1024x573.png 848w, https://substackcdn.com/image/fetch/$s_!BnZy!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbeaeb89f-9a0a-4d13-b8ab-860622479f92_1024x573.png 1272w, https://substackcdn.com/image/fetch/$s_!BnZy!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbeaeb89f-9a0a-4d13-b8ab-860622479f92_1024x573.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!BnZy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbeaeb89f-9a0a-4d13-b8ab-860622479f92_1024x573.png" width="1024" height="573" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/beaeb89f-9a0a-4d13-b8ab-860622479f92_1024x573.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:573,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1015572,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.rohan-paul.com/i/161864456?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbeaeb89f-9a0a-4d13-b8ab-860622479f92_1024x573.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!BnZy!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbeaeb89f-9a0a-4d13-b8ab-860622479f92_1024x573.png 424w, https://substackcdn.com/image/fetch/$s_!BnZy!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbeaeb89f-9a0a-4d13-b8ab-860622479f92_1024x573.png 848w, https://substackcdn.com/image/fetch/$s_!BnZy!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbeaeb89f-9a0a-4d13-b8ab-860622479f92_1024x573.png 1272w, https://substackcdn.com/image/fetch/$s_!BnZy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbeaeb89f-9a0a-4d13-b8ab-860622479f92_1024x573.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Browse all the <strong><a href="https://www.rohan-paul.com/s/ml-case-study/archive?sort=new">ML Case-Studies here</a></strong>.</p><h1><strong>Case-Study question</strong></h1><h2><strong>A large online retailer sells millions of products where color is a key attribute for customer search and filtering. The retailer&#8217;s existing system fails to accurately tag product colors, leading to poor search results (for example, showing navy furniture under black). Design a robust approach to:</strong></h2><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://x.com/rohanpaul_ai&quot;,&quot;text&quot;:&quot;Connect with me on X (Twitter)&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://x.com/rohanpaul_ai"><span>Connect with me on X (Twitter)</span></a></p><ul><li><p>Build a hierarchy of related colors that captures near-synonyms and different shades.</p></li><li><p>Assign descriptive color names to each layer of this hierarchy.</p></li><li><p>Tag products with appropriate color labels from high-level (e.g. &#8220;blue&#8221;) to more specific (e.g. &#8220;navy&#8221;).</p></li><li><p>Evaluate and improve the system&#8217;s accuracy, especially given limited ground truth data. Explain the full pipeline design for color extraction, hierarchical color taxonomy construction, color naming, and method of deployment at scale.</p></li></ul><h2><strong>Detailed In-Depth Solution</strong></h2><h4><strong>Color Hierarchy Construction</strong></h4><p>Cluster Red-Green-Blue values into multiple levels of granularity. A human eye perceives color differences in a specific way, so define a distance metric that aligns with human perception. Use:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!PEL7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0865690b-8c9a-4b53-8c2c-98ab98aa711e_1017x113.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!PEL7!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0865690b-8c9a-4b53-8c2c-98ab98aa711e_1017x113.png 424w, https://substackcdn.com/image/fetch/$s_!PEL7!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0865690b-8c9a-4b53-8c2c-98ab98aa711e_1017x113.png 848w, https://substackcdn.com/image/fetch/$s_!PEL7!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0865690b-8c9a-4b53-8c2c-98ab98aa711e_1017x113.png 1272w, https://substackcdn.com/image/fetch/$s_!PEL7!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0865690b-8c9a-4b53-8c2c-98ab98aa711e_1017x113.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!PEL7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0865690b-8c9a-4b53-8c2c-98ab98aa711e_1017x113.png" width="1017" height="113" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0865690b-8c9a-4b53-8c2c-98ab98aa711e_1017x113.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:113,&quot;width&quot;:1017,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:14916,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.rohan-paul.com/i/161864456?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0865690b-8c9a-4b53-8c2c-98ab98aa711e_1017x113.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!PEL7!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0865690b-8c9a-4b53-8c2c-98ab98aa711e_1017x113.png 424w, https://substackcdn.com/image/fetch/$s_!PEL7!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0865690b-8c9a-4b53-8c2c-98ab98aa711e_1017x113.png 848w, https://substackcdn.com/image/fetch/$s_!PEL7!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0865690b-8c9a-4b53-8c2c-98ab98aa711e_1017x113.png 1272w, https://substackcdn.com/image/fetch/$s_!PEL7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0865690b-8c9a-4b53-8c2c-98ab98aa711e_1017x113.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Delta E measures perceived visual distance. L, a, and b are values in a color space (often CIELAB) that approximates how the eye distinguishes color. If delta E is under a small threshold, colors appear almost identical. If it is above a larger threshold, they look different.</p><p>Start with a bottom-up approach:</p><ul><li><p>Run clustering (for example, K-Means) on extracted product Red-Green-Blue values to form the most granular color clusters. Each cluster has a centroid representing a distinct hue.</p></li><li><p>Assign initial names by comparing each centroid with a known set of labeled Red-Green-Blue values from public data sources. If the distance between a centroid and a known color is below a threshold, inherit that color name.</p></li><li><p>Merge visually similar clusters using a technique such as Birch clustering at an intermediate level of granularity.</p></li><li><p>Group the narrower clusters into broader color families using a graph-based or clique-finding algorithm. Allow overlap, so certain clusters (like teal) can be associated with both blue and green families.</p></li><li><p>Use a small set of basic colors (red, green, blue, yellow, purple, pink, black, white, orange, brown, gray, plus any relevant additions) at the top level. Tie these basic colors to the broader clusters by searching for the nearest neighbors in color space.</p></li></ul><h4><strong>Color Tagging for Products</strong></h4><p>Crop or isolate the region of interest in product images. Cluster pixels (for instance, mini-batch K-Means) to find up to five dominant colors. For each extracted color, match it to the closest centroid in the hierarchy&#8217;s finest level using a high-performance similarity search library (like Faiss). Roll up or roll down through the hierarchy to obtain names at multiple levels.</p><p>If a product has multiple colors, store up to five color tags with associated volumes or proportions. Provide the final color names both at the granular and more general levels, ensuring users can filter by &#8220;blue,&#8221; or get more specific as &#8220;teal,&#8221; &#8220;navy,&#8221; etc.</p><h4><strong>Handling Accuracy and Human Review</strong></h4><p>Ground-truth tags can be incomplete or noisy. Treat supplier tags as a weak source of truth only for cases where the product is a single color at a basic level. For disagreement between the system&#8217;s predictions and supplier tags, rely on human review. Keep track of the acceptance rate, where a prediction is deemed correct if it is visually judged acceptable even if it differs from the supplier&#8217;s label.</p><p>Use additional sources of information if image shadows or lighting cause errors. Text descriptions or digital swatches can fill gaps. If the model consistently misclassifies whites as grays, add specialized logic or more robust features (color histogram, hue-saturation-value transforms) to handle shadows.</p><h4><strong>Implementation Example (Python Snippet)</strong></h4><pre><code><code>import numpy as np
from sklearn.cluster import MiniBatchKMeans
import faiss

# Suppose 'pixels' is an array of shape (N, 3) for the bounding box
k = 5
clusterer = MiniBatchKMeans(n_clusters=k, random_state=42)
clusterer.fit(pixels)
dominant_colors = clusterer.cluster_centers_

# Suppose 'level4_centroids' is a NumPy array of shape (M, 3) for your color taxonomy
index = faiss.IndexFlatL2(3)
index.add(level4_centroids.astype(np.float32))
D, I = index.search(dominant_colors.astype(np.float32), 1)

# 'I' holds indices of the nearest color centroid in the taxonomy
# Map these to color names and roll up or down the hierarchy as needed
</code></code></pre><h4><strong>Operational Concerns</strong></h4><p>Store the hierarchy in a stable format (database or specialized search index) that can scale. Retrain or refresh the clusters when new products introduce new color varieties. Maintain a pipeline where images flow in, bounding boxes are parsed, colors are extracted, and nearest-centroid searches are done in near real-time. Track acceptance metrics for continuous quality checks.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.rohan-paul.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">I write everyday for my readers on actionable AI. Subscribe and instantly get a 1300+ page Python book.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2><strong>Possible Follow-Up Question 1</strong></h2><p>How would you handle color synonyms such as &#8220;turquoise,&#8221; &#8220;teal,&#8221; and &#8220;aquamarine,&#8221; which can belong to more than one parent color?</p><p>Answer: Map each cluster centroid to multiple parents if the distances are below a certain threshold. Use a graph structure that captures overlaps. The final labeling step can display one or more color families. For instance, if the color centroid is near both blue and green, link it to each parent. During search or filtering, the product will appear for queries of both color families.</p><h2><strong>Possible Follow-Up Question 2</strong></h2><p>How would you incorporate text data (like supplier descriptions) to refine color predictions?</p><p>Answer: Extract color words from textual descriptions (for example, &#8220;navy upholstery&#8221;) and match them to the color taxonomy. If the text indicates a strong color label that conflicts with the image-based label, recheck the extracted Red-Green-Blue clusters for any shadows, overexposure, or partial coverage. Combine text-based signals as features in a model that re-ranks final color tags.</p><h2><strong>Possible Follow-Up Question 3</strong></h2><p>How would you handle continuous intake of new product images that might include unfamiliar colors?</p><p>Answer: Implement a monitoring system that detects when a new product&#8217;s centroid is above a high threshold of distance from all existing centroids. Queue these colors for manual labeling and decide whether to introduce a new cluster or merge them with an existing cluster. Update the hierarchy periodically so it remains representative of all products.</p><h2><strong>Possible Follow-Up Question 4</strong></h2><p>How would you ensure the pipeline remains efficient as the catalog grows to billions of images?</p><p>Answer: Use approximate similarity search libraries such as Faiss or Annoy for scale. Partition the images and parallelize the color extraction and clustering steps. Store centroids in a GPU-accelerated index so lookups can be done rapidly. Periodically retrain or incrementally update clusters to manage memory usage. Cache repeated color lookups for commonly encountered hues.</p><p></p><p></p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.rohan-paul.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">I write everyday for my readers on actionable AI. Subscribe and instantly get a 1300+ page Python book.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item></channel></rss>