{
  "id": 9750,
  "title": "Anyone interested in sharing methodologies?",
  "url": "/competitions/acquire-valued-shoppers-challenge/discussion/9750",
  "author_name": "",
  "post_date": "2014-07-15T00:03:33.460Z",
  "votes": 4,
  "comment_count": 58,
  "views": 16538,
  "content": "<p>Great work everyone. Just quick pulse on seeing if anyone is interested in sharing methodologies. Similar to like a post mortem. That way we can all benefit from learning what worked and what didn't.</p>",
  "messages": [
    {
      "id": "50501",
      "postDate": "07/15/2014 00:03:33",
      "content": "<p>Great work everyone. Just quick pulse on seeing if anyone is interested in sharing methodologies. Similar to like a post mortem. That way we can all benefit from learning what worked and what didn't.</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50503",
      "postDate": "07/15/2014 00:16:45",
      "content": "<p>I'm game. :-)</p>\n<p>An important key was&nbsp;understanding that many CustIDs&nbsp;did not have a years worth of transactions. I only considered 180 days when doing calculations.</p>\n<p>Then I counted the number of visits (i.e., distinct purchase dates) for each CustID for the entire 180 days:</p>\n<ul>\n<ul>\n<li>All transactions</li>\n<li>Visits with transactions where dept = offer dept</li>\n<li>Visits with transactions where category = offer category</li>\n<li>Visits with transactions where company = offer company</li>\n<li>Visits with transactions where brand = offer brand</li>\n<li>Visits with transactions where cat/comp/brand = offer cat/comp/brand (Tcob)</li>\n</ul>\n</ul>\n<p>I scaled the data (using asinh), and split the data by offer department, and then again by those that had a Tcob &gt; 0 and those that had Tcob = 0.</p>\n<p>I used&nbsp;a decision tree classifier to train and test each&nbsp;corresponding dept / Tcob chunk of data.</p>\n<p>For the depts in the test data that did not show up on the training data, I did PCA to find depts in the training that were similar in purchase behavior, and used that dept instead.</p>\n<p>I placed #36. &nbsp;:-)</p>\n<p>Also - I used mostly Excel and Python, and also did a fair amount of PLS exploration to find important attributes.</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50505",
      "postDate": "07/15/2014 00:28:03",
      "content": "<p>I think this is a feature-engineering and feature-selection game. I'd like to hear any unusual features generated.</p>\n<p>Also I couldn't get more advanced methods (random forest, gradient boosting) to work better than simple logistic regressions. My best two&nbsp;submissions are blends of logistic regression and random forest models, but it turned out I could get about the same scores without the random forest models.</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50506",
      "postDate": "07/15/2014 00:30:07",
      "content": "<p>The most interesting technique I found for this competition was Bayesian Personalized Ranking,&nbsp; which is a collaborative filtering algorithm that optimizes for rank.&nbsp; Unfortunately, I didn't get a chance to properly test it with different regularization coefficients, but it gave a .01 point bump when I ran it using only one department at a time and plugged the results into my regression.&nbsp; I really wanted to try binning by month and making a model based off count-based panel data, but I couldn't find any readily-made packages for such a model able to handle a dataset of this size.</p>\n<p>Another interesting collaborative filtering algorithm I came across was Bayesian Probabilistic Tensor Factorization which allows you to incorporate time (or I suppose any other axis) into the PMF.</p>\n<p>Papers for the collaborative filtering algorithms if anyone is interested:</p>\n<p>http://www.cs.mcgill.ca/~uai2009/papers/UAI2009_0139_48141db02b9f0b02bc7158819ebfa2c7.pdf</p>\n<p>http://www.autonlab.org/autonweb/19394/version/4/part/5/data/225_Xiong.pdf?branch=main&amp;language=en</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50507",
      "postDate": "07/15/2014 00:31:10",
      "content": "<p>I can't stress enough how important it was to treat high-transaction IDs separate from &quot;regular&quot; IDs.&nbsp;</p>\n<p>I shot up&nbsp;150 places on the leader board just by doing that.</p>\n<p>Then, breaking out training/testing by offer department was what made the rest of the difference.</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50508",
      "postDate": "07/15/2014 00:34:36",
      "content": "<p>I would have loved to have considered the data as a time series. That's an obvious step (that I wasn't able to do since I was stuck using a laptop for most of the 2 weeks prior to contest end).</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50509",
      "postDate": "07/15/2014 00:41:02",
      "content": "<p>My score (public&nbsp;0.61070, private 0.60618) was from a weighted average of random forest&nbsp;(mtry around 3 to 5, replace=FALSE, around 800 trees), bagged random forest (sample size of around 40-50k, around 400-500 reps), gbm (&quot;bernoulli&quot;, small shrinkage, high interaction depth of around 25, around 11k trees), and bagged lasso (sample 1000 without replacement, 8000 reps).</p>\n<p>I didn't do that much feature transformation or selection other than dummy variables for categorical features. I used mostly Triskelion's features (thanks). I had to do a bit of transformation on the bagged lasso output since all the values were so close together. In R this was: &quot; tt4[,2] = pcauchy((tt4[,2]-min(tt4[,2]))*45) &quot;</p>\n<p>I did all of this on a virtual machine with about 10 GB ram. Sometimes I leverage AWS and just throw ram at the problem, but I didn't do that in this case. What I learned in this competition is that while feature engineering is probably the most important thing, sometimes just parallel bagging and model averaging can do wonders if you have enough time and computational resources.</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50511",
      "postDate": "07/15/2014 00:46:49",
      "content": "<p>Hi, everyone. This is our 2nd Kaggle contest literally and we are very very lucky! Many thanks to Triskelion and all others who contribute codes and ideas. All our predictions except one are based on Triskelion's features. As absolute newbies, we find feature engineering most challenging and difficult. Our model averages three Neural networks models and 1 random forests model. For neural networks (logistic regression) model, we found that the features with value 0 ( e.g. repeaters who never buy the offer's brand ) may cause serious overfitting. That's why we come up with three different neural network models to mitigate the side effect.</p>\n<p>1) use all brand, company and category features but the customers who never bought the same brand or company or category as the coupon's product get a discount of all their feature values. (very subjective) 0.59661</p>\n<p>2) use all brand, company and category features but the predictions are only based on neurons that have positive weights along the path. &nbsp;0.59590&nbsp;</p>\n<p>3) use brand, company and category features to train and test separately and average their predictions. &nbsp;0.59607</p>\n<p>We also trained a very basic random forest with 1000 estimators using all features and we get 0.56958. In the end we took a weighted average of the predictions based on public leaderboard score (not good?).</p>\n<p>We really love to be a Kaggler and even being a newbie here can be so much fun! There are a lot to learn here and thank you guys very much to be THE great Sensei here. &nbsp;To be continued.. : )</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50515",
      "postDate": "07/15/2014 01:47:52",
      "content": "<p>I improved my benchmark a little bit, by:</p>\n<p>- reducing the number of passes to 1,</p>\n<p>- doing quantile regression on the &quot;number of repeat trips&quot; for the labels, instead of binary labels.</p>\n<p>- Somewhat tighter binning for the time-related features (bought_company_a_170, etc.)</p>\n<p>Then I teamed up with&nbsp;Phil Culliton who had made many more effective VW models trained on different and new features. I think he can tell more about those.</p>\n<p>Then we basically ensembled all these models. We ended up with a combination of 10 VW models (each trained on their own features) that was a good pick for private&nbsp;leaderboard. Also private public split was good in general (the best submission was only +4 spots).</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50516",
      "postDate": "07/15/2014 01:56:08",
      "content": "<p>Did you guys make cross-validation work? I had been frustrated with that all the time in the competition...</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50517",
      "postDate": "07/15/2014 01:59:07",
      "content": "<p>I just CVed via the public leaderboard. I usually do this when it's forecasting because I assume non-stationary data unless I see evidence of otherwise. However, you got 5th, so it's likely it wasn't the biggest problem for you?</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50518",
      "postDate": "07/15/2014 02:04:56",
      "content": "<p>[quote=Guocong Song;50516]</p>\n<p>Did you guys make cross-validation work? I had been frustrated with that all the time in the competition...</p>\n<p>[/quote]</p>\n<p>The best I could come up with was CV by offer ID. With this approach, there're big differences between folds, but when averaged, it was my best CV method.</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50519",
      "postDate": "07/15/2014 02:08:46",
      "content": "<p>@inversion : Offer doesn't have a dept, did I miss something?</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50520",
      "postDate": "07/15/2014 02:12:36",
      "content": "<p>The offer department was the first two digits of the offer category. (Or the first digit for a 3-digit category).</p>\n<p>So, e.g, for offer&nbsp;1200578 which had a category of 1703, I analyzed everything for dept 17.</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50521",
      "postDate": "07/15/2014 02:17:29",
      "content": "<p>My model was an average of gbm and logistic regression.</p>\n\n<p>For gbm, I used similar features as Triskelion but condensed them into fewer features. Rather than counting last30, 60, etc. I weighted each transaction that matched&nbsp;offer cat/comp/brand&nbsp;by how close its date was to the offerdate.</p>\n<p>For example, a transaction purchase amount that matched the offer category and was made 5 days before the offer date would be given weight = amount*exp(-5/60). I found 60 days a good decay parameter. Using something like this was the only way I could get gbm to work reasonably (~.605) with params (adaboost, ~1000 trees, depth = 3, shrinkage=~0.01)</p>\n\n<p>For logistic regression, I basically used&nbsp;tks' approach with some minor tweaking but got better results with bagging fraction ~0.5.</p>\n\n<p>For me, the most significant&nbsp;improvement was combining the models, but not with a straight average of probabilities. Instead, for each model, I ordered each test offer by&nbsp;repeatProbability, then reassigned them with evenly distributed probabilities on a scale of 0 to 1, and then performed the average. I figured given the AUC metric, the ordering was more important than the actual probability from any model. This gave an improvement on the public&nbsp;leaderboard from ~0.605 to ~0.611.</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50524",
      "postDate": "07/15/2014 02:47:47",
      "content": "<p>[quote=inversion;50507]</p>\n<p>I can't stress enough how important it was to treat high-transaction IDs separate from &quot;regular&quot; IDs.</p>\n<p>I shot up 150 places on the leader board just by doing that.</p>\n<p>Then, breaking out training/testing by offer department was what made the rest of the difference.</p>\n<p>[/quote]</p>\n<p>How did you handle the departments when it came time to make the predictions? I also broke my data up by department, but I found that the test set had quite a few offers for departments that weren't in the train set and vice versa.</p>\n<p>Also, on a related note, when I broke up the data by time I found that there were many months--as much as half-- where the only purchases made by customers in the test set for the companies of those that made offers were the brands associated with the offer. I have the suspicion that the test and train sets might actually have been collected from two different sources and combined into one. At the very least it would indicate that transactions history from the test data might have been mixed in at a later date and not sampled from the same original pool of data.</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50525",
      "postDate": "07/15/2014 02:55:33",
      "content": "<p>[quote=Mike Kim;50517]</p>\n<p>I just CVed via the public leaderboard. I usually do this when it's forecasting because I assume non-stationary data unless I see evidence of otherwise. However, you got 5th, so it's likely it wasn't the biggest problem for you?</p>\n<p>[/quote]</p>\n<p>It was the biggest problem for me. My scores were very fluctuating over time. I generated similar features inversion did, and tried many normalization over offers, which helped lift the score, but the improvement of CV was limited. Since the training time was short, I just kept submitting...</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50527",
      "postDate": "07/15/2014 02:56:50",
      "content": "<p>Regarding cross validation:<br>I think the major problem that made life difficult with building a proper validation set might have been caused&nbsp;due to the fact that the test set and train set had different products offered to them (6 products are in train but not in test, 8 products are both in train and test, and 7 more products are in test but not in train). I've used 'product' as the basic unit since several different offers were actually different discounts offered to the same product.<br><br>Anyway, when I tried mimicking these 'product split' ratio's using the 14 products in the train set and tried learning to generalize from a random split of 4 randomly chosen products in train only, 5 randomly chosen products in test only, and 5 remaining products split by time to train and test, I've found that the amounts of 'noise' were huge from fold to fold. for some splits the validation error was in the ranges of 0.55, and for some other splits in the ranges of 0.63 (for my earliest models). I concluded that this is too much noise and that I needed to do about 100 such random splits (folds) and average their results to get a reliable cross validation scheme and decided it would take too much, so instead I tried finding a representative single split. I couldn't find anything really good, but I've found something that was OK, and used that as a general guide to guide me to &quot;the general ballpark&quot;.<br><br><br>Regarding the features we've used:<br>My initial&nbsp;way of thinking about this problem was like a recommender system. <br>The&nbsp;basic assumption I used was&nbsp;that most people are not aware of all the products that are out there (there are about 120,000 products in the&nbsp;data set),&nbsp;but, that at the same time, people can be characterized by the specific products they tend to buy, and similarities between people can be drawn according to each persons 'long term shopping cart', and similarities between products can be drawn according to the 'the population demographic' that buys different products.</p>\n<p>So I constructed the matrix that contains 310K consumers as rows and the 120K products as columns, and filled the (i,j) th element in it to be the amount of times that consumer bought that specific product.<br>this matrix is of course very very sparse. meaning, most of it's elements are 0. <br>As I've said, my basic assumption was that some of these 0 elements account for &quot;that person is not interested in that product&quot;, but that most of these zeros account for &quot;that person has never heard of that product&quot;.</p>\n<p>So I wanted to&nbsp;fill in these zeros by &quot;if that person were to know about this product, will this product be part of his long term shopping cart?&quot;.</p>\n<p>There are several simple ways that I know of that are able to achieve this: consumer kNN (find consumer i's k most similar consumers, and average their j'th column values), product kNN (similar to consumer kNN but with switching the rows and columns), and matrix factorization (construct a low rank matrix approximation to the large matrix by performing SVD or PCA).</p>\n<p>Non of these approaches were feasible running on the entire 310000x120000 matrix, so I've subsampled the products and kept only&nbsp;the most popular products across all population (largest amount of consumer that bought them) and those products that were most similar to the query products (the products that were initially offered with discount).&nbsp;so in the end, I had&nbsp;a matrix of about 310000x2000 as the basic feature set to work with. this proved to be quite good.<br><br>My partner (who I teamed up with toward the end of the competition) took an entirely different approach and managed to squeeze a lot out of&nbsp;Triskelion's features (and some more features of the same type), by training&nbsp;many different types of learners with the same feature set and mixing them together.<br><br>In the end, blending our very different&nbsp;approaches has resulted in quite a large increase in score.</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50528",
      "postDate": "07/15/2014 02:59:14",
      "content": "<p>As to the features, besides the basic factor features - brand,category,chain,and company,I also tried to construct additional features from the following business perspectives for forcasting repurchase.</p>\n<p><strong>1.Customer's purchasing behiviours in the past.</strong></p>\n<p>I used RFM method.&nbsp;<a href=\"http://en.wikipedia.org/wiki/RFM_(customer_value)\">RFM</a> stands for<br>Recency - How recently did the customer purchase?<br>Frequency - How often do they purchase?<br>Monetary Value - How much do they spend?</p>\n<p>I mainly leveraged Triskelion's work for these variables construction and I also used Triskelion's original score as my base line.</p>\n<p><strong>2.Brand's quality</strong> - average return rate of a brand</p>\n<p><strong>3.BrandPopularity/Influence</strong></p>\n<p>BrandPopularity1 - brand's average revenue per month<br>BrandPopularity2 - brand's average repeat rate</p>\n<p><strong>4.Price</strong></p>\n<p>Brand's price - average price of the brand<br>Preferred price for a customer - average price of the customer spent in the same category of a brand<br>Offer value - offervalue/brand_value</p>\n<p><strong>5.Competition</strong> - number of brands in the same category</p>\n<p><strong>6.Easy to Get</strong> - number of total brands or revenue in a chain, to measure the chain's popularity or scale.</p>\n<p>However, I found that only the feature of brand's quality can improve the base line (Triskelion's original score) a little bit.&nbsp; </p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50531",
      "postDate": "07/15/2014 03:55:50",
      "content": "<p>I discovered the same very effective mixing/ensembling method as cherrybarry. Since with AUC only the ranking matters, and the predictions from different models have very different scale/ranges, so averaging their rankings instead of the prediction values makes more sense and gives much better results.</p>\n<p>Once I found the fact that mixing results from two very different models can improve the results significantly, even if the results of&nbsp;individual models are not very impressive. I try to add many different models:</p>\n<p>Using a bigger set of features&nbsp;similar to&nbsp;Triskelion's but expanded and also&nbsp;calculated&nbsp;using the full transactions data I tried:</p>\n<p>1. Triskelion's VW model</p>\n<p>The rest of the models using R packages.</p>\n<p>2. R's glmnet model with bagging</p>\n<p>3. randomForest with bagging</p>\n<p>4. Single gbm model</p>\n<p>5. gbm model bagging with very small number of trees</p>\n<p>6. knn3, R's k-nearest neighbor model</p>\n<p>7. NaiveBayes model</p>\n<p>Then using the above mixing/ensemble method to get the final results.</p>\n<p>Once I teamed up with Selfish Gene, since there was not much time left, and we are in different parts of the globe, we just independently worked on our own models and&nbsp;once I submitted my models&nbsp;he will download the&nbsp;my best results and using&nbsp;the above stated mixing method to mix his results with mine. We furthur see meaningful improvements from best of either models.</p>\n<p>I suspect, that if we mix/ensemble the top 10/20 models of this competitions, we may get again some meaningful improvements from any of the single models, as from the shared ideas from this thread, the approaches&nbsp;are very different. Perfect candidates for mixing/ensembling.</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50533",
      "postDate": "07/15/2014 04:12:55",
      "content": "",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50534",
      "postDate": "07/15/2014 04:28:45",
      "content": "<p>Hi,</p>\n<p>I am new to this field, and this was my first competition. I am placed at #249</p>\n<p>I used Logistic Regression (Feature engineering in Java, and trained my model in Octave). I tried to fine tune my solution using Random Forest, but it did not help much.</p>\n<p>I want to share few things which helped me to move up on leader-board rapidly.</p>\n<p>1. Removing noise: There were few customers whose feature values (total purchase amount, total number of transactions) were too big. So I removed that data which 8 times more than mean.</p>\n<p>2. Polynomial degrees of feature values. (square and cube)</p>\n<p>3. After training I found below were high weighted features</p>\n<p>Total purchase amount</p>\n<p>Total number of transactions</p>\n<p>Total quantity purchased</p>\n<p>Total purchased amount by same company-category-brand</p>\n<p>Total number of transactions by same company-category-brand</p>\n<p>Total quantity by same company-category-brand</p>\n<p>Thanks.</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50537",
      "postDate": "07/15/2014 05:17:40",
      "content": "<p>We started with Triskelion's features and also had the idea of adding recommender based features. We tried item-based collaborative filtering (used mahout) and latent factor models (Koren's work from Netflix prize). Best submissions were item-based.</p>\n<p>By pruning the number of most similar items I tuned the number of actual recommendation values (which are always &gt;=1) vs N/A (no similar items found, converted to 0 ), which is effective to&nbsp; balance between explicit and implicit recommendation (implicit meaning user didn't buy because they didn't like, not&nbsp; just weren't aware). Adding two such features with different thresholds helped.</p>\n<p>We used logistic regression with 10% sub-sampling and bagging 2000 models,&nbsp; using code of tks . I found taking median was better than average (but now realizes from others that should have tried averaging ranks too).. As tks pointed out, need extreme L2 regularization (lambda~2^13). Strong regularization must be needed due to the large variance but&nbsp; I'm&nbsp; puzzled by how big lambda is. Trying elastic net with mix in L1 reduced the optimal lambda but didn't give best result.I'm interested if someone was able to make less regularized&nbsp; logistic regression to work.</p>\n<p>For CV I&nbsp; used K-folds stratified by&nbsp; offer labels and averaged. It seems pretty consistent with progress on LB..</p>\n<p>.</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50544",
      "postDate": "07/15/2014 07:36:51",
      "content": "<p>Hi. And thank you to everyone to share all this information. I&#8217;m new and I appreciate this.</p>\n<p>The features that I create was basically descriptions features about how customer buy, especially in each department, and features about the offer.</p>\n<p>Them I did diferent random forest, and then I esambled it.</p>\n<p>The random forest was focusing in the repeater variable, but if I'd had&nbsp;more time I would&nbsp;have tried some glm with repeattrips, using the Poisson distribution.</p>\n<p>Did anyone use a glm in that way?</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50547",
      "postDate": "07/15/2014 07:41:45",
      "content": "<p>It is interesting&nbsp;has somebody tried to use Assosiation Rules for this task? As for me it`s classic task for Recommendation System, but I couldn't find no significant rule.</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50549",
      "postDate": "07/15/2014 08:52:59",
      "content": "<p>I created several&nbsp;new variables and used glmnet with alpha 0 lambda 0.00371. Where the lambda obtained from cv.glmnet from full trainset. It scored&nbsp;0.61093 on public 0.60313 on private</p>\n<p>st_change :OLS cusum test for each customer (to capture structural break)<br>both_contained_offer: is the offer contained in both train and test set?<br>ratio_offer_bought_all: offered product (brand+company+category) / numbers of purchased product<br>ratio_offer_bought_180:offered product (brand+company+category) / numbers of purchased product within 180 days<br>ratio_offer_bought_90:....<br>ratio_offer_bought_60:..<br>ratio_offer_bought_30:...<br>last_date_purchased: offer date - last date that each customer purchased offered product<br>mean_pur_amount: daily purchase / total spent<br>mean_pur_amount_180: daily purchase / total spent within 180days<br>mean_pur_amount_90:...<br>mean_pur_amount_60:...<br>mean_pur_amount_30:...<br>cate_sensitive: numbers of different brand+category / numbers of different brand+category+category<br>cate_sensitive_180:numbers of different brand+category / numbers of different brand+category+category within 180 days<br>cate_sensitive_90<br>cate_sensitive_60<br>cate_sensitive_30<br>cust_cate_sensitive:&nbsp;numbers of different brand / numbers of different brand+category+category<br>cust_cate_sensitive_180<br>cust_cate_sensitive_90<br>cust_cate_sensitive_60<br>cust_cate_sensitive_30<br>cust_company_sensitive:&nbsp;numbers of different company/ numbers of different brand+category+category<br>cust_company_sensitive_180:&nbsp;numbers of different company&nbsp;/ numbers of different brand+category+category within 180days<br>cust_company_sensitive_90<br>cust_company_sensitive_60<br>cust_company_sensitive_30<br>cust_brand_sensitive:&nbsp;numbers of different brand/ numbers of different brand+category+category<br>cust_brand_sensitive_180<br>cust_brand_sensitive_90<br>cust_brand_sensitive_60<br>cust_brand_sensitive_30</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50552",
      "postDate": "07/15/2014 09:39:11",
      "content": "<p>We added in &quot;general&quot; features. In total had 750 features</p>\n<p>- customer / dept boolean matrix</p>\n<p>- brand / category boolean matrix</p>\n<p>- brand / company counts</p>\n<p>etc</p>\n<p>Training by different subsets and averaging increased the score</p>\n<p>XGBOOST and GBM worked the best. Code coming soon</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50564",
      "postDate": "07/15/2014 13:02:23",
      "content": "<p>Quick and dirty solution that we implemented in a week with limited computational resources:</p>\n<p>1. Created ~100 features that explain users behavior, from transactions.&nbsp;</p>\n<p>2. Created another ~50-100 features from clustering users, to have some more meaningful features for users with very few transactions. Not sure these helped at all.</p>\n<p>3. Run average sized RF. Also tried logistic and adaboost. None of the 2 performed as good as RF. RF was also preferable cause there was little or no need to preprocess the features and time was limited.</p>\n<p>4. Combined 4-5 methods, with the highest weight put on our best RF. This improved performance just enough to get AUC 0.5997.</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50565",
      "postDate": "07/15/2014 13:38:12",
      "content": "<p>[quote=Guocong Song;50516]</p>\n<p>Did you guys make cross-validation work? I had been frustrated with that all the time in the competition...</p>\n<p>[/quote]</p>\n<p>Did you try splitting via offer? E.g train on all offers but one and test on that one. That worked fairly well for me with a little bit more tweaking. E.g to say there should be at least X uplift in order to trust it. For me the was was 0.002 (from AUC 0.610 to AUC 0.612).&nbsp;</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50566",
      "postDate": "07/15/2014 13:52:35",
      "content": "<p>For cross validation, I tried to take into account that observations in the test set were for offers on later dates than the training set, and also that many were for different product categories. I ordered the data by offer date, and used the first half for training (75,000 observations). For the cross-validation set, I used the remaining rows of data, but only selected the categories that had not appeared in the first 75,000 rows, i.e. 2202, 2119, 5616, and 6202.</p>\n<p>Of course, this wasn&#8217;t perfect, but it did help in identifying larger jumps. I could also do it fairly quickly as opposed to using K folds.</p>\n<p>For my score (public: 0.61228, private: 0.60575), I used features similar to Triskelion&#8217;s, as well as inversion&#8217;s, and trained a single random forest (500 trees, mtry=2, nodesize=5).</p>\n<p>I&#8217;d be interested to know if anyone had any good feature selection methods. I noticed that my score dropped when adding certain features, and increased when removing some, but I had no systematic way of testing each feature.</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50568",
      "postDate": "07/15/2014 14:10:09",
      "content": "<p>For me it was the very first kaggle. My secret was lots of hard work (ended doing exactly 400 submissions all by myself.)&nbsp;I found very specific features to this data set, I don't think anyone&nbsp;will gain from them&nbsp;outside the company running the competition.</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50570",
      "postDate": "07/15/2014 14:31:18",
      "content": "<p>[quote=zzspar;50568]</p>\n<p>For me it was the very first kaggle. My secret was lots of hard work (ended doing exactly 400 submissions all by myself.)&nbsp;I found very specific features to this data set, I don't think anyone&nbsp;will gain from them&nbsp;outside the company running the competition.</p>\n<p>[/quote]</p>\n<p>Congratulations! I appreciate it if you could share the methodology to discover golden features, if it's not all about intuitions and prior knowledge. Thank you very much! Again, all by yourself, that's really impressive!</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50571",
      "postDate": "07/15/2014 14:40:13",
      "content": "<p>CV was the hardest item also for me. In one of my attempts at inventing a CV method I realized I had a bug in the code but on the other hand this CV was very effective on the leader board so I had to dig into the data to find out what was behind the buggy algorithm</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50572",
      "postDate": "07/15/2014 14:58:40",
      "content": "<p>For customers that purchased the same category + company + brand, one feature that seems to have some significance was the discount rate of the coupon. I calculated this based on the median amount per qty.</p>\n<p>Lower discount rate seems to have more repeat ability than high.</p>\n<p>Other working theories I had was:</p>\n<p>1) Brand loyalist to a particular brand may be more likely to try a coupon but less likely to switch brands</p>\n<p>2) Whereas brand shifters, maybe more likely to switch brands after trying a coupon.</p>\n<p>One thing wanted to try was time-series clustering by customers buying patterns. Was wondering if anyone had luck with this? or found variables with a time dimension was useful?</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50579",
      "postDate": "07/15/2014 16:11:25",
      "content": "<p>This was my first Kaggle competition. Big thanks to my teammate turbonerd for introducing me to it and keeping the spirit up! Without him, this would not have happened. Thanks to Kaggle for hosting and excellent competition and to the anonymous data provider for the interesting dataset.</p>\n<p>Here are some lessons learned, helpful or not.</p>\n<p><strong>1)</strong> Spent far too much time worrying about our setup, ending up with a combination of MySQL, python scripts with a task-oriented class structure and csv files. Using SQL limited a bit in what aggregates could be produced (no medians etc), but speeded up the feature engineering process. In hindsight, a clean map-reduce would probably have been better.</p>\n<p><strong>2)</strong> It took some time for to figure out what the problem was. When, finally, cross-validation started to work (somewhat), dividing up train set by unique product (company,category,brand combination), a lot of time and wasted effort had elapsed.</p>\n<p><strong>3)</strong> This competition was a lot about feature engineering, and having no experience with that, it took a lot of time and many mistakes were made.</p>\n<p>Some of the best features turned out to be hierarchical, trained separately on data from transactions. E.g. a logistic regression-based probability of buying the product on offer, given which of the top100 most popular products this user had purchased (also did this with brand, category, company, department).</p>\n<p>Other good ones were simple stuff like which fraction of previous trips the user bought this product on. Other ones tried, besides the ones suggested on forums, fall broadly into these categories: weekday statistics (quantities, amounts, measures purchased on certain days), loyalty to products (how many categories in a department a user bought, how many brands for a company etc &#8211; almost all permutations), prior purchase-based (how many times, how often, ), loyalty to store (which weekdays visited, how many times, time period between first and last visit), market, chain, dept-level aggregates of , basket sizes, relative price of offered product to this users usual level for this department, many of above based on 1, 2, 3 months of data prior to offerdate. In total, 214 features.</p>\n<p>We also tried some association rule learning, but dropped it pretty quickly.</p>\n<p><strong>4)</strong> The main mistake was to not be more systematic, which seems obvious in hindsight. We knew that CV was a problem; that offers were very different (repeating ranging 10-40%); that purchase because of coupon and purchase because of prior habits needed to be modeled separately; but somehow did not spend enough time systematically solving these issues, spending most time on feature engineering. A lot more time should have gone into thinking about good ways to train. The absurdity of life is that after all effort with random forests, ridge regression and many others, vowpal vabbit ended up handily beating all out blended attempts at cool models.<br>Also, more time could have gone into looking and visualizing the data.</p>\n<p><strong>5)</strong> Not doing feature selection probably hurt the final performance a lot, since some features ended up to be highly correlated. This is a lesson for next time and it would be interesting to hear if someone managed to automate feature selection somehow.</p>\n<p>We ended up with a ROC AUC of 0.57485 on the private leaderboard, netting us the 545th place. Hard to say if its good or bad for beginners, at least it was very fun and a learning experience.</p>\n<p>Some of the above will probably seem very stupid after reading this thread :)</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50580",
      "postDate": "07/15/2014 16:11:38",
      "content": "<p>One problem&nbsp;I noticed sometimes when cross-validating was that although the classifier had good AUC on each offer individually, the classifier overall had much much poorer total AUC. I'm thinking that this was because the relative probabilities of the different offers was not aligned somehow, but that's just a guess. Did anyone find a principled way to deal with this? I looked around for some theoretical approach to this, but could not find any.</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50581",
      "postDate": "07/15/2014 16:15:43",
      "content": "<p>[quote=auduno;50580]</p>\n<p>One problem&nbsp;I noticed sometimes when cross-validating was that although the classifier had good AUC on each offer individually, the classifier overall had much much poorer total AUC. I'm thinking that this was because the relative probabilities of the different offers was not aligned somehow, but that's just a guess. Did anyone find a principled way to deal with this? I looked around for some theoretical approach to this, but could not find any.</p>\n<p>[/quote]</p>\n\n<p>You needed 2 models! One to optimize for individual (offer-specific) &nbsp;AUCs and one for the general AUC :) At least, this is what we did. Also scaling helped in this one.</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50589",
      "postDate": "07/15/2014 16:52:27",
      "content": "<p>[quote=KazAnova;50581]</p>\n<p>You needed 2 models! One to optimize for individual (offer-specific) &nbsp;AUCs and one for the general AUC :) At least, this is what we did. Also scaling helped in this one.</p>\n<p>[/quote]</p>\n<p>Ah, I considered that, but didn't get enough time to try it, unfortunately. Did you blend the two models to get final result, or did you use the second model to adjust the relative predictions of the offer-specific models?</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50590",
      "postDate": "07/15/2014 16:53:20",
      "content": "<p>[quote=auduno;50589]</p>\n<p>[quote=KazAnova;50581]</p>\n<p>You needed 2 models! One to optimize for individual (offer-specific) &nbsp;AUCs and one for the general AUC :) At least, this is what we did. Also scaling helped in this one.</p>\n<p>[/quote]</p>\n<p>Ah, I considered that, but didn't get enough time to try it, unfortunately. Did you blend the two models to get final result, or did you use the second model to adjust the relative predictions of the offer-specific models?</p>\n<p>[/quote]</p>\n\n<p>Blend!</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50591",
      "postDate": "07/15/2014 16:54:28",
      "content": "<p>[quote=Grigory;50579]</p>\n<p>We ended up with a ROC AUC of 0.57485 on the private leaderboard, netting us the 545th place. Hard to say if its good or bad for beginners, at least it was very fun and a learning experience.</p>\n<p>[/quote]</p>\n<p>It doesn't matter where you place, it matters what you learned. And it sounds like you learned a lot!</p>\n<p>I placed in the <em>bottom</em> 10% my first competition, then top 40%, then top 30%, and now top 5% with this competition.</p>\n<p>I'd say you rocked it for your first time. &nbsp;:-)</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50595",
      "postDate": "07/15/2014 17:05:58",
      "content": "<p>[quote=econoraptor;50524]</p>\n<p>[quote=inversion;50507]</p>\n<p>I can't stress enough how important it was to treat high-transaction IDs separate from &quot;regular&quot; IDs.</p>\n<p>I shot up 150 places on the leader board just by doing that.</p>\n<p>Then, breaking out training/testing by offer department was what made the rest of the difference.</p>\n<p>[/quote]</p>\n<p>How did you handle the departments when it came time to make the predictions? I also broke my data up by department, but I found that the test set had quite a few offers for departments that weren't in the train set and vice versa.</p>\n<p>[/quote]</p>\n<p>For each CustID, I did a pivot (using pandas) of the total amount purchased for each dept. (More accurately, I only counted purchases that were &lt;= 180 days from the date of the offer given to that CustID, filtering out any transactions with a 0 count or negative amount.)</p>\n<p>Then I did a PCA on the table. By inspecting the loading plot, I was able to find a dept in the training data that was similarly correlated to a dept in the test data.</p>\n<p>There were 2 depts in the test set that didn't correlate well to any in the training set. For those, I just trained on all the depts in aggregate.</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50597",
      "postDate": "07/15/2014 17:46:38",
      "content": "<p>[quote=KazAnova;50565]</p>\n\n<p>Did you try splitting via offer? E.g train on all offers but one and test on that one. That worked fairly well for me with a little bit more tweaking. E.g to say there should be at least X uplift in order to trust it. For me the was was 0.002 (from AUC 0.610 to AUC 0.612).&nbsp;</p>\n<p>[/quote]</p>\n<p>Hmm, I did split by offer, but didn't try leave-one-out&nbsp;CV. I should try it see what happens.</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50599",
      "postDate": "07/15/2014 18:06:02",
      "content": "<p>[quote=KazAnova;50565]</p>\n<p>[quote=Guocong Song;50516]</p>\n<p>Did you guys make cross-validation work? I had been frustrated with that all the time in the competition...</p>\n<p>[/quote]</p>\n<p>Did you try splitting via offer? E.g train on all offers but one and test on that one. That worked fairly well for me with a little bit more tweaking. E.g to say there should be at least X uplift in order to trust it. For me the was was 0.002 (from AUC 0.610 to AUC 0.612).&nbsp;</p>\n<p>[/quote]</p>\n\n<p>I did a quick try in which I used one offer data to train models against the rest, but didn't work out. I should do normal splitting... &nbsp;Single offer has too large variance:) &nbsp;</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50608",
      "postDate": "07/15/2014 19:55:34",
      "content": "<p>Hi folks, I'm a recent &quot;graduate&quot; of Andrew Ng's machine learning course. I entered this, my first competition, as a training exercise and have thoroughly enjoyed it.</p>\n<p><br>Like Jack Han, I started with RFM (recency, frequency, monetary). Frequency didn't help, but monetary did, especially when binned. I used total spend over the previous 90 days. <br>I used dummy variables for prod, category and dept in bins of &quot;never bought&quot;, 1-15 days ago, 16-30 ago, 31-70 ago. The bins were chosen based on histograms/box-and-whisker plots in Tableau. This is similar to Triskelion's approach, but I didn't use product quantity, just ones and zeros. For brand, I ended up just using the &quot;never bought&quot; bin. I used logistic regression in vw. My features were generated from HP Vertica using SQL, and I used perf to calculate ROC.</p>\n<p><br>I experimented to no avail with various other features to find a proxy for customers who tend to flit between products in the same category: category spend ratios, category entropy, price paid relative to mean. The customer's ratio of distinct products bought per category relative to the average ratio per category worked well on the training set, but harmed my score on the public test set. Like 'inversion', I noticed higher take up for those with high IDs, but it was late in the day and I wasn't able to exploit it with my best model.</p>\n<p><br>In the end, my best submission (0.60291 public and 0.59738 private) was achieved by adding total number of distinct products as a feature. I found that the difference between my train ROC using vw holdout and public ROC varied between 0.47 and 0.57. Is this what others are seeing too?</p>\n<p><br>I had planned to implement a brand loyalty measure (anyone try Guadagni and Little 1983?) and itemset mining. Sadly the day job needed attending to.</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50661",
      "postDate": "07/16/2014 05:43:20",
      "content": "<p>Similar to Jack Han, for each customer I computed the following score</p>\n<p><code style=\"padding-left: 30px\"> customer_value_score = total_spend_per_day * trxn_per_trip * (1.0/recency) * lifetime * (1.0/avg_interpurchase_time)</code></p>\n<p>where:</p>\n<p style=\"padding-left: 30px\">trxn_per_trip = number of transactions per trip</p>\n<p style=\"padding-left: 30px\">recency = days between last purchase date relative to last date in data</p>\n<p style=\"padding-left: 30px\">lifetime = time elapsed from first purchase date to last purchase date</p>\n<p style=\"padding-left: 30px\">avg_interpurchase_time = is the average time gap between purchases</p>\n\n<p>Being new to Kaggle competitions, I benefited a great deal from combining Triskelion's features with tks's glmnet code + bagging (thanks to meet thakar and clustifier). Additionally, I added return events (quantity &lt; 0) as features. I used the full 22GB dataset.&nbsp;</p>\n\n<p>A great many thanks to Triskelion, tks, culstifier, meet thakar and everyone else for sharing their ideas, insights, and code.</p>\n<p>Cheers!</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50740",
      "postDate": "07/16/2014 22:37:04",
      "content": "<p>[quote=KazAnova;50581]</p>\n<p>You needed 2 models! One to optimize for individual (offer-specific) &nbsp;AUCs and one for the general AUC :) At least, this is what we did. Also scaling helped in this one.</p>\n<p>[/quote]</p>\n<p>I'm guessing you might share the code eventually, but I'm curious : how did you optimize for individual offer-specific AUCs? Most of the offers in the testset were not in the training set, so did you just optimize for those that were in the training set, or did you use some method similar to inversion's method, i.e. finding some combination of the closest &quot;similar&quot; offers to the ones in testset and optimizing for those?</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50741",
      "postDate": "07/16/2014 22:43:06",
      "content": "<p>[quote=auduno;50740]</p>\n<p>&nbsp;how did you optimize for individual offer-specific AUCs? Most of the offers in the testset were not in the training set, so did you just optimize for those that were in the training set</p>\n<p>[/quote]</p>\n\n<p>For those in the training set only. When I optimized for individual AUCs, I was ignoring the sample size of the offer and I was just averaging the results of the AUCs of the different offers ( 1-out format), When we were optimizing for the total AUC we were appending the results of each offer's prediction&nbsp;in an array and calculating the total AUC once all results had been appended. I hope that helps.&nbsp;</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50765",
      "postDate": "07/17/2014 11:25:11",
      "content": "<p>[quote=inversion;50507]</p>\n<p>For each CustID, I did a pivot (using pandas) of the total amount purchased for each dept. (More accurately, I only counted purchases that were &lt;= 180 days from the date of the offer given to that CustID, filtering out any transactions with a 0 count or negative amount.)</p>\n<p>Then I did a PCA on the table. By inspecting the loading plot, I was able to find a dept in the training data that was similarly correlated to a dept in the test data.</p>\n<p>There were 2 depts in the test set that didn't correlate well to any in the training set. For those, I just trained on all the depts in aggregate.</p>\n<p>[/quote]</p>\n<p>Hello,<br>Interesting approach. We have applied a Kolmogorov-Smirnov test and selected only features with similar distributions in de train and test sets.<br> Can you give more details about your PCA procedure?</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50779",
      "postDate": "07/17/2014 13:52:25",
      "content": "<p>[quote=inversion;50507]</p>\n<p>I can't stress enough how important it was to treat high-transaction IDs separate from &quot;regular&quot; IDs.</p>\n<p>I shot up 150 places on the leader board just by doing that.</p>\n<p>Then, breaking out training/testing by offer department was what made the rest of the difference.</p>\n<p>[/quote]</p>\n<p>I read your previous post about your method. I didn't understand how you treat the high-transactions IDs and low-transactions IDs. Can you explain more on it?</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50786",
      "postDate": "07/17/2014 15:21:59",
      "content": "<p>[quote=inversion;50507]</p>\n<p>That's a very wise move. I wonder if a clustering algorithm to assign&nbsp;customers to different groups based on similarities in their shopping habits would have been helpful; then each group from the test set and train set would have been treated individually.&nbsp;I guess I will never know &nbsp;;)</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50810",
      "postDate": "07/18/2014 00:17:08",
      "content": "<p>[quote=Yiqun Hu;50779]</p>\n<p>I read your previous post about your method. I didn't understand how you treat the high-transactions IDs and low-transactions IDs. Can you explain more on it?</p>\n<p>[/quote]</p>\n<p>Looking at the customer id data (training set), there were ~1,300 ids that had more than 4,000 total transactions. (The highest had&nbsp;2,647,164 transactions!) As was mentioned in the forum earlier, this was probably a &quot;default&quot; card that is used at check-out, e.g., when a shopper doesn't have a loyalty card the store scans a &quot;default&quot; card&nbsp;at the register.</p>\n<p>If you reverse sort the training data by the number of transactions, you'll see that those ids were <em>almost always</em> repeat shoppers. (See the image below.) The fact that these are repeat buyers is an artifact of including these &quot;default&quot; cards in with normal shoppers.</p>\n<p>I simply removed these high-transaction ids and trained without them. For the test set, any id that had a high transaction count, I manually set it to &quot;1&quot; for the estimated repeater probability. Doing this was a &quot;freebie&quot; improvement in score.</p>\n<p><img src=\"http://i.imgur.com/rH6LMUL.png\" alt=\"Repeaters\" width=\"416\" height=\"762\"></p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50811",
      "postDate": "07/18/2014 00:33:49",
      "content": "<p>[quote=inversion;50810]</p>\n<p>I simply removed these high-transaction ids and trained without them. For the test set, any id that had a high transaction count, I manually set it to &quot;1&quot; for the estimated repeater probability. Doing this was a &quot;freebie&quot; improvement in score.</p>\n<p>[/quote]</p>\n<p>How much improvement did you get from this ?</p>\n<p>Another possible &quot;freebie&quot; is to train the offers that are in both train and test sets separately. However I didn't use&nbsp;this in the end because the improvement was small, and the CV unreliable.</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50814",
      "postDate": "07/18/2014 01:21:20",
      "content": "<p>[quote=B Yang;50811]</p>\n<p>[quote=inversion;50810]</p>\n<p>I simply removed these high-transaction ids and trained without them. For the test set, any id that had a high transaction count, I manually set it to &quot;1&quot; for the estimated repeater probability. Doing this was a &quot;freebie&quot; improvement in score.</p>\n<p>[/quote]</p>\n<p>How much improvement did you get from this ?</p>\n<p>[/quote]</p>\n<p>From 0.59507 to 0.61017</p>\n<p>+150 positions on the leader board or so.</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50816",
      "postDate": "07/18/2014 01:36:58",
      "content": "<p>[quote=RW;50765]</p>\n<p>[quote=inversion;50507]</p>\n<p>For each CustID, I did a pivot (using pandas) of the total amount purchased for each dept. (More accurately, I only counted purchases that were &lt;= 180 days from the date of the offer given to that CustID, filtering out any transactions with a 0 count or negative amount.)</p>\n<p>Then I did a PCA on the table. By inspecting the loading plot, I was able to find a dept in the training data that was similarly correlated to a dept in the test data.</p>\n<p>There were 2 depts in the test set that didn't correlate well to any in the training set. For those, I just trained on all the depts in aggregate.</p>\n<p>[/quote]</p>\n<p>Hello,<br>Interesting approach. We have applied a Kolmogorov-Smirnov test and selected only features with similar distributions in de train and test sets.<br> Can you give more details about your PCA procedure?</p>\n<p>[/quote]</p>\n<p>Sure. My data table looked like this. (Rows = CustIDs, Columns = Depts, Values = sum of customer transactions for each dept [truncated at 180 days from offer date and ignoring negative transaction amounts]) The amounts were transformed with arcsinh for scaling.</p>\n<p><img src=\"http://i.imgur.com/Ld5cXdw.png\" alt=\"Dept Pivot Table.\" width=\"449\" height=\"204\"></p>\n<p>I then did a 2-component PCA on the table. (I don't have an image of the loading plot handy, otherwise I'd show it. I used 3 different computers . . . so my files are all over the place. If I stumble upon it I'll post it later.)<br><br>The loading plot showed a position for each department.&nbsp;</p>\n<p>For departments that were in the test set but not in the train set, I looked at the loading plot to find a department that was close to that point that was also in the training set.</p>\n<p>For instance, I trained on Dept 44 to test for Dept 7. For Dept 45 and 51, I used Dept 55 for training.</p>\n<p>Departments 72 and 91 didn't covary well with any departments in the training set, so I used the entire training set to predict those departments.</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50861",
      "postDate": "07/18/2014 16:43:47",
      "content": "<p>Like many mention before the CV problem with he public leader board came from the very strong &quot;Offer ID&quot; bias (some offers were much more successful then others). The way I dealt with it was to find a &quot;repeat ratio&quot; for each &quot;Offer ID&quot; and use that as a feature. I also did the same for all the offers info (Market, dept, brand, etc..). These were all quite strong features for me. This method had the obvious issue that some offers were not in the training data (or had very low statistics), but that's the best I could come up with.</p>\n<p>The other features I didn't see people talk about, but that I though were clever, was a measure of how faithful a customer was to products in general. For that I when through all the products a customer ever bought and found how many times he bought it again. From that data I found the usual statistics (min/max, mean. median, standard deviation, etc...), and more importantly a &quot;repeater ratio&quot;, which is basically how many purchases they made divided by the number of different products they bought.&nbsp;I liked that feature the most because:</p>\n<p>1 - It makes sense - people that are faithful to their products (or don't bother looking for new ones) are more likely to become faithful to a &nbsp;new product they try. &nbsp; &nbsp;</p>\n<p>2 - It turned out to be quite a strong feature.</p>\n<p>My best model was using Scikit-learn with AdaBoost (n_estimators=200) with Random Forest (n_estimators=200, max_depth=2) for base_estimator.</p>\n<p>PS. If someone is good with Neural Networks, I would be very curious to see how my set of features would do with that. It was my next step, but I never had a chance to try it.</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50866",
      "postDate": "07/18/2014 17:46:23",
      "content": "<p>[quote=cherrybarry;50521]</p>\n<p>For me, the most significant&nbsp;improvement was combining the models, but not with a straight average of probabilities. Instead, for each model, I ordered each test offer by&nbsp;repeatProbability, then reassigned them with evenly distributed probabilities on a scale of 0 to 1, and then performed the average. I figured given the AUC metric, the ordering was more important than the actual probability from any model. This gave an improvement on the public&nbsp;leaderboard from ~0.605 to ~0.611.</p>\n<p>[/quote]</p>\n\n<p>Thank you for sharing your method. I have struggled on how to ensemble different models. Can you elaborate on how you assigned scores from different models&nbsp;evenly distributed probabilities on a scale of 0 to 1?&nbsp;</p>\n<p>Thank you for your help.&nbsp;</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50867",
      "postDate": "07/18/2014 17:50:26",
      "content": "<p>[quote=Wei Wu;50531]</p>\n<p>I discovered the same very effective mixing/ensembling method as cherrybarry. Since with AUC only the ranking matters, and the predictions from different models have very different scale/ranges, so averaging their rankings instead of the prediction values makes more sense and gives much better results.</p>\n<p>[/quote]</p>\n<p>How did you average the rankings and transform that into probabilities? Could you explain a little bit more? Thank you!&nbsp;</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "50882",
      "postDate": "07/18/2014 21:12:46",
      "content": "<p>[quote=Iris Ren;50866]</p>\n<p>[quote=cherrybarry;50521]</p>\n<p>For me, the most significant&nbsp;improvement was combining the models, but not with a straight average of probabilities. Instead, for each model, I ordered each test offer by&nbsp;repeatProbability, then reassigned them with evenly distributed probabilities on a scale of 0 to 1, and then performed the average. I figured given the AUC metric, the ordering was more important than the actual probability from any model. This gave an improvement on the public&nbsp;leaderboard from ~0.605 to ~0.611.</p>\n<p>[/quote]</p>\n<p>Thank you for sharing your method. I have struggled on how to ensemble different models. Can you elaborate on how you assigned scores from different models&nbsp;evenly distributed probabilities on a scale of 0 to 1?&nbsp;</p>\n<p>Thank you for your help.&nbsp;</p>\n<p>[/quote]</p>\n<p>I can't speak for cherrybarry, but here is how I would do it:</p>\n<ul>\n<li>Sort the model predictions by repeatProbability in ascending&nbsp;order (first row is the lowest value&nbsp;such as 0 or 0.001, and last row is the highest&nbsp;value such as 0.999 or 1).</li>\n<li>Add a new variable called adjustedProbability. For each record, set adjustedProbability to be equal to it's row number divided by the total number of rows. So for the first row, divide 1 by 151484. For the second row, 2/151484. And so on, with 151484/151484 for&nbsp;the last row.</li>\n</ul>\n<p>You will now have evenly distributed probabilities between 0 and 1. Do that for each model, and then to ensemble, take a straight average of the adjustedProbability: (model 1 + model 2) / 2</p>\n<p>Or, you could weight the models differently: (model1 + 2*model 2 + 3*model 3) / 6</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "1343061",
      "postDate": "06/10/2021 02:08:52",
      "content": "<p>Hi , can you explain what is TCOB? I have been breaking my head over this. <br>\nAlso, can this be done without Python?</p>",
      "rawMarkdown": "Hi , can you explain what is TCOB? I have been breaking my head over this. \nAlso, can this be done without Python?",
      "votes": null
    }
  ],
  "comments": [
    {
      "id": 50503,
      "author_name": "inversion",
      "author_url": "",
      "post_date": "07/15/2014 00:16:45",
      "content": "<p>I'm game. :-)</p>\n<p>An important key was&nbsp;understanding that many CustIDs&nbsp;did not have a years worth of transactions. I only considered 180 days when doing calculations.</p>\n<p>Then I counted the number of visits (i.e., distinct purchase dates) for each CustID for the entire 180 days:</p>\n<ul>\n<ul>\n<li>All transactions</li>\n<li>Visits with transactions where dept = offer dept</li>\n<li>Visits with transactions where category = offer category</li>\n<li>Visits with transactions where company = offer company</li>\n<li>Visits with transactions where brand = offer brand</li>\n<li>Visits with transactions where cat/comp/brand = offer cat/comp/brand (Tcob)</li>\n</ul>\n</ul>\n<p>I scaled the data (using asinh), and split the data by offer department, and then again by those that had a Tcob &gt; 0 and those that had Tcob = 0.</p>\n<p>I used&nbsp;a decision tree classifier to train and test each&nbsp;corresponding dept / Tcob chunk of data.</p>\n<p>For the depts in the test data that did not show up on the training data, I did PCA to find depts in the training that were similar in purchase behavior, and used that dept instead.</p>\n<p>I placed #36. &nbsp;:-)</p>\n<p>Also - I used mostly Excel and Python, and also did a fair amount of PLS exploration to find important attributes.</p>",
      "votes": null,
      "replies": [
        {
          "id": 1343061,
          "author_name": "scottrobertson7772",
          "author_url": "",
          "post_date": "06/10/2021 02:08:52",
          "content": "<p>Hi , can you explain what is TCOB? I have been breaking my head over this. <br>\nAlso, can this be done without Python?</p>",
          "votes": null,
          "replies": []
        }
      ]
    },
    {
      "id": 50505,
      "author_name": "byang1",
      "author_url": "",
      "post_date": "07/15/2014 00:28:03",
      "content": "<p>I think this is a feature-engineering and feature-selection game. I'd like to hear any unusual features generated.</p>\n<p>Also I couldn't get more advanced methods (random forest, gradient boosting) to work better than simple logistic regressions. My best two&nbsp;submissions are blends of logistic regression and random forest models, but it turned out I could get about the same scores without the random forest models.</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50506,
      "author_name": "econoraptor",
      "author_url": "",
      "post_date": "07/15/2014 00:30:07",
      "content": "<p>The most interesting technique I found for this competition was Bayesian Personalized Ranking,&nbsp; which is a collaborative filtering algorithm that optimizes for rank.&nbsp; Unfortunately, I didn't get a chance to properly test it with different regularization coefficients, but it gave a .01 point bump when I ran it using only one department at a time and plugged the results into my regression.&nbsp; I really wanted to try binning by month and making a model based off count-based panel data, but I couldn't find any readily-made packages for such a model able to handle a dataset of this size.</p>\n<p>Another interesting collaborative filtering algorithm I came across was Bayesian Probabilistic Tensor Factorization which allows you to incorporate time (or I suppose any other axis) into the PMF.</p>\n<p>Papers for the collaborative filtering algorithms if anyone is interested:</p>\n<p>http://www.cs.mcgill.ca/~uai2009/papers/UAI2009_0139_48141db02b9f0b02bc7158819ebfa2c7.pdf</p>\n<p>http://www.autonlab.org/autonweb/19394/version/4/part/5/data/225_Xiong.pdf?branch=main&amp;language=en</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50507,
      "author_name": "inversion",
      "author_url": "",
      "post_date": "07/15/2014 00:31:10",
      "content": "<p>I can't stress enough how important it was to treat high-transaction IDs separate from &quot;regular&quot; IDs.&nbsp;</p>\n<p>I shot up&nbsp;150 places on the leader board just by doing that.</p>\n<p>Then, breaking out training/testing by offer department was what made the rest of the difference.</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50508,
      "author_name": "inversion",
      "author_url": "",
      "post_date": "07/15/2014 00:34:36",
      "content": "<p>I would have loved to have considered the data as a time series. That's an obvious step (that I wasn't able to do since I was stuck using a laptop for most of the 2 weeks prior to contest end).</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50509,
      "author_name": "mikeskim",
      "author_url": "",
      "post_date": "07/15/2014 00:41:02",
      "content": "<p>My score (public&nbsp;0.61070, private 0.60618) was from a weighted average of random forest&nbsp;(mtry around 3 to 5, replace=FALSE, around 800 trees), bagged random forest (sample size of around 40-50k, around 400-500 reps), gbm (&quot;bernoulli&quot;, small shrinkage, high interaction depth of around 25, around 11k trees), and bagged lasso (sample 1000 without replacement, 8000 reps).</p>\n<p>I didn't do that much feature transformation or selection other than dummy variables for categorical features. I used mostly Triskelion's features (thanks). I had to do a bit of transformation on the bagged lasso output since all the values were so close together. In R this was: &quot; tt4[,2] = pcauchy((tt4[,2]-min(tt4[,2]))*45) &quot;</p>\n<p>I did all of this on a virtual machine with about 10 GB ram. Sometimes I leverage AWS and just throw ram at the problem, but I didn't do that in this case. What I learned in this competition is that while feature engineering is probably the most important thing, sometimes just parallel bagging and model averaging can do wonders if you have enough time and computational resources.</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50511,
      "author_name": "xueerchen",
      "author_url": "",
      "post_date": "07/15/2014 00:46:49",
      "content": "<p>Hi, everyone. This is our 2nd Kaggle contest literally and we are very very lucky! Many thanks to Triskelion and all others who contribute codes and ideas. All our predictions except one are based on Triskelion's features. As absolute newbies, we find feature engineering most challenging and difficult. Our model averages three Neural networks models and 1 random forests model. For neural networks (logistic regression) model, we found that the features with value 0 ( e.g. repeaters who never buy the offer's brand ) may cause serious overfitting. That's why we come up with three different neural network models to mitigate the side effect.</p>\n<p>1) use all brand, company and category features but the customers who never bought the same brand or company or category as the coupon's product get a discount of all their feature values. (very subjective) 0.59661</p>\n<p>2) use all brand, company and category features but the predictions are only based on neurons that have positive weights along the path. &nbsp;0.59590&nbsp;</p>\n<p>3) use brand, company and category features to train and test separately and average their predictions. &nbsp;0.59607</p>\n<p>We also trained a very basic random forest with 1000 estimators using all features and we get 0.56958. In the end we took a weighted average of the predictions based on public leaderboard score (not good?).</p>\n<p>We really love to be a Kaggler and even being a newbie here can be so much fun! There are a lot to learn here and thank you guys very much to be THE great Sensei here. &nbsp;To be continued.. : )</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50515,
      "author_name": "triskelion",
      "author_url": "",
      "post_date": "07/15/2014 01:47:52",
      "content": "<p>I improved my benchmark a little bit, by:</p>\n<p>- reducing the number of passes to 1,</p>\n<p>- doing quantile regression on the &quot;number of repeat trips&quot; for the labels, instead of binary labels.</p>\n<p>- Somewhat tighter binning for the time-related features (bought_company_a_170, etc.)</p>\n<p>Then I teamed up with&nbsp;Phil Culliton who had made many more effective VW models trained on different and new features. I think he can tell more about those.</p>\n<p>Then we basically ensembled all these models. We ended up with a combination of 10 VW models (each trained on their own features) that was a good pick for private&nbsp;leaderboard. Also private public split was good in general (the best submission was only +4 spots).</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50516,
      "author_name": "songgc",
      "author_url": "",
      "post_date": "07/15/2014 01:56:08",
      "content": "<p>Did you guys make cross-validation work? I had been frustrated with that all the time in the competition...</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50517,
      "author_name": "mikeskim",
      "author_url": "",
      "post_date": "07/15/2014 01:59:07",
      "content": "<p>I just CVed via the public leaderboard. I usually do this when it's forecasting because I assume non-stationary data unless I see evidence of otherwise. However, you got 5th, so it's likely it wasn't the biggest problem for you?</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50518,
      "author_name": "byang1",
      "author_url": "",
      "post_date": "07/15/2014 02:04:56",
      "content": "<p>[quote=Guocong Song;50516]</p>\n<p>Did you guys make cross-validation work? I had been frustrated with that all the time in the competition...</p>\n<p>[/quote]</p>\n<p>The best I could come up with was CV by offer ID. With this approach, there're big differences between folds, but when averaged, it was my best CV method.</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50519,
      "author_name": "paulperry",
      "author_url": "",
      "post_date": "07/15/2014 02:08:46",
      "content": "<p>@inversion : Offer doesn't have a dept, did I miss something?</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50520,
      "author_name": "inversion",
      "author_url": "",
      "post_date": "07/15/2014 02:12:36",
      "content": "<p>The offer department was the first two digits of the offer category. (Or the first digit for a 3-digit category).</p>\n<p>So, e.g, for offer&nbsp;1200578 which had a category of 1703, I analyzed everything for dept 17.</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50521,
      "author_name": "bshang",
      "author_url": "",
      "post_date": "07/15/2014 02:17:29",
      "content": "<p>My model was an average of gbm and logistic regression.</p>\n\n<p>For gbm, I used similar features as Triskelion but condensed them into fewer features. Rather than counting last30, 60, etc. I weighted each transaction that matched&nbsp;offer cat/comp/brand&nbsp;by how close its date was to the offerdate.</p>\n<p>For example, a transaction purchase amount that matched the offer category and was made 5 days before the offer date would be given weight = amount*exp(-5/60). I found 60 days a good decay parameter. Using something like this was the only way I could get gbm to work reasonably (~.605) with params (adaboost, ~1000 trees, depth = 3, shrinkage=~0.01)</p>\n\n<p>For logistic regression, I basically used&nbsp;tks' approach with some minor tweaking but got better results with bagging fraction ~0.5.</p>\n\n<p>For me, the most significant&nbsp;improvement was combining the models, but not with a straight average of probabilities. Instead, for each model, I ordered each test offer by&nbsp;repeatProbability, then reassigned them with evenly distributed probabilities on a scale of 0 to 1, and then performed the average. I figured given the AUC metric, the ordering was more important than the actual probability from any model. This gave an improvement on the public&nbsp;leaderboard from ~0.605 to ~0.611.</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50524,
      "author_name": "econoraptor",
      "author_url": "",
      "post_date": "07/15/2014 02:47:47",
      "content": "<p>[quote=inversion;50507]</p>\n<p>I can't stress enough how important it was to treat high-transaction IDs separate from &quot;regular&quot; IDs.</p>\n<p>I shot up 150 places on the leader board just by doing that.</p>\n<p>Then, breaking out training/testing by offer department was what made the rest of the difference.</p>\n<p>[/quote]</p>\n<p>How did you handle the departments when it came time to make the predictions? I also broke my data up by department, but I found that the test set had quite a few offers for departments that weren't in the train set and vice versa.</p>\n<p>Also, on a related note, when I broke up the data by time I found that there were many months--as much as half-- where the only purchases made by customers in the test set for the companies of those that made offers were the brands associated with the offer. I have the suspicion that the test and train sets might actually have been collected from two different sources and combined into one. At the very least it would indicate that transactions history from the test data might have been mixed in at a later date and not sampled from the same original pool of data.</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50525,
      "author_name": "songgc",
      "author_url": "",
      "post_date": "07/15/2014 02:55:33",
      "content": "<p>[quote=Mike Kim;50517]</p>\n<p>I just CVed via the public leaderboard. I usually do this when it's forecasting because I assume non-stationary data unless I see evidence of otherwise. However, you got 5th, so it's likely it wasn't the biggest problem for you?</p>\n<p>[/quote]</p>\n<p>It was the biggest problem for me. My scores were very fluctuating over time. I generated similar features inversion did, and tried many normalization over offers, which helped lift the score, but the improvement of CV was limited. Since the training time was short, I just kept submitting...</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50527,
      "author_name": "selfishgene",
      "author_url": "",
      "post_date": "07/15/2014 02:56:50",
      "content": "<p>Regarding cross validation:<br>I think the major problem that made life difficult with building a proper validation set might have been caused&nbsp;due to the fact that the test set and train set had different products offered to them (6 products are in train but not in test, 8 products are both in train and test, and 7 more products are in test but not in train). I've used 'product' as the basic unit since several different offers were actually different discounts offered to the same product.<br><br>Anyway, when I tried mimicking these 'product split' ratio's using the 14 products in the train set and tried learning to generalize from a random split of 4 randomly chosen products in train only, 5 randomly chosen products in test only, and 5 remaining products split by time to train and test, I've found that the amounts of 'noise' were huge from fold to fold. for some splits the validation error was in the ranges of 0.55, and for some other splits in the ranges of 0.63 (for my earliest models). I concluded that this is too much noise and that I needed to do about 100 such random splits (folds) and average their results to get a reliable cross validation scheme and decided it would take too much, so instead I tried finding a representative single split. I couldn't find anything really good, but I've found something that was OK, and used that as a general guide to guide me to &quot;the general ballpark&quot;.<br><br><br>Regarding the features we've used:<br>My initial&nbsp;way of thinking about this problem was like a recommender system. <br>The&nbsp;basic assumption I used was&nbsp;that most people are not aware of all the products that are out there (there are about 120,000 products in the&nbsp;data set),&nbsp;but, that at the same time, people can be characterized by the specific products they tend to buy, and similarities between people can be drawn according to each persons 'long term shopping cart', and similarities between products can be drawn according to the 'the population demographic' that buys different products.</p>\n<p>So I constructed the matrix that contains 310K consumers as rows and the 120K products as columns, and filled the (i,j) th element in it to be the amount of times that consumer bought that specific product.<br>this matrix is of course very very sparse. meaning, most of it's elements are 0. <br>As I've said, my basic assumption was that some of these 0 elements account for &quot;that person is not interested in that product&quot;, but that most of these zeros account for &quot;that person has never heard of that product&quot;.</p>\n<p>So I wanted to&nbsp;fill in these zeros by &quot;if that person were to know about this product, will this product be part of his long term shopping cart?&quot;.</p>\n<p>There are several simple ways that I know of that are able to achieve this: consumer kNN (find consumer i's k most similar consumers, and average their j'th column values), product kNN (similar to consumer kNN but with switching the rows and columns), and matrix factorization (construct a low rank matrix approximation to the large matrix by performing SVD or PCA).</p>\n<p>Non of these approaches were feasible running on the entire 310000x120000 matrix, so I've subsampled the products and kept only&nbsp;the most popular products across all population (largest amount of consumer that bought them) and those products that were most similar to the query products (the products that were initially offered with discount).&nbsp;so in the end, I had&nbsp;a matrix of about 310000x2000 as the basic feature set to work with. this proved to be quite good.<br><br>My partner (who I teamed up with toward the end of the competition) took an entirely different approach and managed to squeeze a lot out of&nbsp;Triskelion's features (and some more features of the same type), by training&nbsp;many different types of learners with the same feature set and mixing them together.<br><br>In the end, blending our very different&nbsp;approaches has resulted in quite a large increase in score.</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50528,
      "author_name": "jackhan1",
      "author_url": "",
      "post_date": "07/15/2014 02:59:14",
      "content": "<p>As to the features, besides the basic factor features - brand,category,chain,and company,I also tried to construct additional features from the following business perspectives for forcasting repurchase.</p>\n<p><strong>1.Customer's purchasing behiviours in the past.</strong></p>\n<p>I used RFM method.&nbsp;<a href=\"http://en.wikipedia.org/wiki/RFM_(customer_value)\">RFM</a> stands for<br>Recency - How recently did the customer purchase?<br>Frequency - How often do they purchase?<br>Monetary Value - How much do they spend?</p>\n<p>I mainly leveraged Triskelion's work for these variables construction and I also used Triskelion's original score as my base line.</p>\n<p><strong>2.Brand's quality</strong> - average return rate of a brand</p>\n<p><strong>3.BrandPopularity/Influence</strong></p>\n<p>BrandPopularity1 - brand's average revenue per month<br>BrandPopularity2 - brand's average repeat rate</p>\n<p><strong>4.Price</strong></p>\n<p>Brand's price - average price of the brand<br>Preferred price for a customer - average price of the customer spent in the same category of a brand<br>Offer value - offervalue/brand_value</p>\n<p><strong>5.Competition</strong> - number of brands in the same category</p>\n<p><strong>6.Easy to Get</strong> - number of total brands or revenue in a chain, to measure the chain's popularity or scale.</p>\n<p>However, I found that only the feature of brand's quality can improve the base line (Triskelion's original score) a little bit.&nbsp; </p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50531,
      "author_name": "weiwunyc",
      "author_url": "",
      "post_date": "07/15/2014 03:55:50",
      "content": "<p>I discovered the same very effective mixing/ensembling method as cherrybarry. Since with AUC only the ranking matters, and the predictions from different models have very different scale/ranges, so averaging their rankings instead of the prediction values makes more sense and gives much better results.</p>\n<p>Once I found the fact that mixing results from two very different models can improve the results significantly, even if the results of&nbsp;individual models are not very impressive. I try to add many different models:</p>\n<p>Using a bigger set of features&nbsp;similar to&nbsp;Triskelion's but expanded and also&nbsp;calculated&nbsp;using the full transactions data I tried:</p>\n<p>1. Triskelion's VW model</p>\n<p>The rest of the models using R packages.</p>\n<p>2. R's glmnet model with bagging</p>\n<p>3. randomForest with bagging</p>\n<p>4. Single gbm model</p>\n<p>5. gbm model bagging with very small number of trees</p>\n<p>6. knn3, R's k-nearest neighbor model</p>\n<p>7. NaiveBayes model</p>\n<p>Then using the above mixing/ensemble method to get the final results.</p>\n<p>Once I teamed up with Selfish Gene, since there was not much time left, and we are in different parts of the globe, we just independently worked on our own models and&nbsp;once I submitted my models&nbsp;he will download the&nbsp;my best results and using&nbsp;the above stated mixing method to mix his results with mine. We furthur see meaningful improvements from best of either models.</p>\n<p>I suspect, that if we mix/ensemble the top 10/20 models of this competitions, we may get again some meaningful improvements from any of the single models, as from the shared ideas from this thread, the approaches&nbsp;are very different. Perfect candidates for mixing/ensembling.</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50533,
      "author_name": "vijay2110",
      "author_url": "",
      "post_date": "07/15/2014 04:12:55",
      "content": "",
      "votes": null,
      "replies": []
    },
    {
      "id": 50534,
      "author_name": "vijay2110",
      "author_url": "",
      "post_date": "07/15/2014 04:28:45",
      "content": "<p>Hi,</p>\n<p>I am new to this field, and this was my first competition. I am placed at #249</p>\n<p>I used Logistic Regression (Feature engineering in Java, and trained my model in Octave). I tried to fine tune my solution using Random Forest, but it did not help much.</p>\n<p>I want to share few things which helped me to move up on leader-board rapidly.</p>\n<p>1. Removing noise: There were few customers whose feature values (total purchase amount, total number of transactions) were too big. So I removed that data which 8 times more than mean.</p>\n<p>2. Polynomial degrees of feature values. (square and cube)</p>\n<p>3. After training I found below were high weighted features</p>\n<p>Total purchase amount</p>\n<p>Total number of transactions</p>\n<p>Total quantity purchased</p>\n<p>Total purchased amount by same company-category-brand</p>\n<p>Total number of transactions by same company-category-brand</p>\n<p>Total quantity by same company-category-brand</p>\n<p>Thanks.</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50537,
      "author_name": "shaironen",
      "author_url": "",
      "post_date": "07/15/2014 05:17:40",
      "content": "<p>We started with Triskelion's features and also had the idea of adding recommender based features. We tried item-based collaborative filtering (used mahout) and latent factor models (Koren's work from Netflix prize). Best submissions were item-based.</p>\n<p>By pruning the number of most similar items I tuned the number of actual recommendation values (which are always &gt;=1) vs N/A (no similar items found, converted to 0 ), which is effective to&nbsp; balance between explicit and implicit recommendation (implicit meaning user didn't buy because they didn't like, not&nbsp; just weren't aware). Adding two such features with different thresholds helped.</p>\n<p>We used logistic regression with 10% sub-sampling and bagging 2000 models,&nbsp; using code of tks . I found taking median was better than average (but now realizes from others that should have tried averaging ranks too).. As tks pointed out, need extreme L2 regularization (lambda~2^13). Strong regularization must be needed due to the large variance but&nbsp; I'm&nbsp; puzzled by how big lambda is. Trying elastic net with mix in L1 reduced the optimal lambda but didn't give best result.I'm interested if someone was able to make less regularized&nbsp; logistic regression to work.</p>\n<p>For CV I&nbsp; used K-folds stratified by&nbsp; offer labels and averaged. It seems pretty consistent with progress on LB..</p>\n<p>.</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50544,
      "author_name": "fidelcastillo",
      "author_url": "",
      "post_date": "07/15/2014 07:36:51",
      "content": "<p>Hi. And thank you to everyone to share all this information. I&#8217;m new and I appreciate this.</p>\n<p>The features that I create was basically descriptions features about how customer buy, especially in each department, and features about the offer.</p>\n<p>Them I did diferent random forest, and then I esambled it.</p>\n<p>The random forest was focusing in the repeater variable, but if I'd had&nbsp;more time I would&nbsp;have tried some glm with repeattrips, using the Poisson distribution.</p>\n<p>Did anyone use a glm in that way?</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50547,
      "author_name": "westsider",
      "author_url": "",
      "post_date": "07/15/2014 07:41:45",
      "content": "<p>It is interesting&nbsp;has somebody tried to use Assosiation Rules for this task? As for me it`s classic task for Recommendation System, but I couldn't find no significant rule.</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50549,
      "author_name": "tayshin",
      "author_url": "",
      "post_date": "07/15/2014 08:52:59",
      "content": "<p>I created several&nbsp;new variables and used glmnet with alpha 0 lambda 0.00371. Where the lambda obtained from cv.glmnet from full trainset. It scored&nbsp;0.61093 on public 0.60313 on private</p>\n<p>st_change :OLS cusum test for each customer (to capture structural break)<br>both_contained_offer: is the offer contained in both train and test set?<br>ratio_offer_bought_all: offered product (brand+company+category) / numbers of purchased product<br>ratio_offer_bought_180:offered product (brand+company+category) / numbers of purchased product within 180 days<br>ratio_offer_bought_90:....<br>ratio_offer_bought_60:..<br>ratio_offer_bought_30:...<br>last_date_purchased: offer date - last date that each customer purchased offered product<br>mean_pur_amount: daily purchase / total spent<br>mean_pur_amount_180: daily purchase / total spent within 180days<br>mean_pur_amount_90:...<br>mean_pur_amount_60:...<br>mean_pur_amount_30:...<br>cate_sensitive: numbers of different brand+category / numbers of different brand+category+category<br>cate_sensitive_180:numbers of different brand+category / numbers of different brand+category+category within 180 days<br>cate_sensitive_90<br>cate_sensitive_60<br>cate_sensitive_30<br>cust_cate_sensitive:&nbsp;numbers of different brand / numbers of different brand+category+category<br>cust_cate_sensitive_180<br>cust_cate_sensitive_90<br>cust_cate_sensitive_60<br>cust_cate_sensitive_30<br>cust_company_sensitive:&nbsp;numbers of different company/ numbers of different brand+category+category<br>cust_company_sensitive_180:&nbsp;numbers of different company&nbsp;/ numbers of different brand+category+category within 180days<br>cust_company_sensitive_90<br>cust_company_sensitive_60<br>cust_company_sensitive_30<br>cust_brand_sensitive:&nbsp;numbers of different brand/ numbers of different brand+category+category<br>cust_brand_sensitive_180<br>cust_brand_sensitive_90<br>cust_brand_sensitive_60<br>cust_brand_sensitive_30</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50552,
      "author_name": "domcastro",
      "author_url": "",
      "post_date": "07/15/2014 09:39:11",
      "content": "<p>We added in &quot;general&quot; features. In total had 750 features</p>\n<p>- customer / dept boolean matrix</p>\n<p>- brand / category boolean matrix</p>\n<p>- brand / company counts</p>\n<p>etc</p>\n<p>Training by different subsets and averaging increased the score</p>\n<p>XGBOOST and GBM worked the best. Code coming soon</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50564,
      "author_name": "drk195517",
      "author_url": "",
      "post_date": "07/15/2014 13:02:23",
      "content": "<p>Quick and dirty solution that we implemented in a week with limited computational resources:</p>\n<p>1. Created ~100 features that explain users behavior, from transactions.&nbsp;</p>\n<p>2. Created another ~50-100 features from clustering users, to have some more meaningful features for users with very few transactions. Not sure these helped at all.</p>\n<p>3. Run average sized RF. Also tried logistic and adaboost. None of the 2 performed as good as RF. RF was also preferable cause there was little or no need to preprocess the features and time was limited.</p>\n<p>4. Combined 4-5 methods, with the highest weight put on our best RF. This improved performance just enough to get AUC 0.5997.</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50565,
      "author_name": "kazanova",
      "author_url": "",
      "post_date": "07/15/2014 13:38:12",
      "content": "<p>[quote=Guocong Song;50516]</p>\n<p>Did you guys make cross-validation work? I had been frustrated with that all the time in the competition...</p>\n<p>[/quote]</p>\n<p>Did you try splitting via offer? E.g train on all offers but one and test on that one. That worked fairly well for me with a little bit more tweaking. E.g to say there should be at least X uplift in order to trust it. For me the was was 0.002 (from AUC 0.610 to AUC 0.612).&nbsp;</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50566,
      "author_name": "klapod",
      "author_url": "",
      "post_date": "07/15/2014 13:52:35",
      "content": "<p>For cross validation, I tried to take into account that observations in the test set were for offers on later dates than the training set, and also that many were for different product categories. I ordered the data by offer date, and used the first half for training (75,000 observations). For the cross-validation set, I used the remaining rows of data, but only selected the categories that had not appeared in the first 75,000 rows, i.e. 2202, 2119, 5616, and 6202.</p>\n<p>Of course, this wasn&#8217;t perfect, but it did help in identifying larger jumps. I could also do it fairly quickly as opposed to using K folds.</p>\n<p>For my score (public: 0.61228, private: 0.60575), I used features similar to Triskelion&#8217;s, as well as inversion&#8217;s, and trained a single random forest (500 trees, mtry=2, nodesize=5).</p>\n<p>I&#8217;d be interested to know if anyone had any good feature selection methods. I noticed that my score dropped when adding certain features, and increased when removing some, but I had no systematic way of testing each feature.</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50568,
      "author_name": "udibr1",
      "author_url": "",
      "post_date": "07/15/2014 14:10:09",
      "content": "<p>For me it was the very first kaggle. My secret was lots of hard work (ended doing exactly 400 submissions all by myself.)&nbsp;I found very specific features to this data set, I don't think anyone&nbsp;will gain from them&nbsp;outside the company running the competition.</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50570,
      "author_name": "jiweiliu",
      "author_url": "",
      "post_date": "07/15/2014 14:31:18",
      "content": "<p>[quote=zzspar;50568]</p>\n<p>For me it was the very first kaggle. My secret was lots of hard work (ended doing exactly 400 submissions all by myself.)&nbsp;I found very specific features to this data set, I don't think anyone&nbsp;will gain from them&nbsp;outside the company running the competition.</p>\n<p>[/quote]</p>\n<p>Congratulations! I appreciate it if you could share the methodology to discover golden features, if it's not all about intuitions and prior knowledge. Thank you very much! Again, all by yourself, that's really impressive!</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50571,
      "author_name": "udibr1",
      "author_url": "",
      "post_date": "07/15/2014 14:40:13",
      "content": "<p>CV was the hardest item also for me. In one of my attempts at inventing a CV method I realized I had a bug in the code but on the other hand this CV was very effective on the leader board so I had to dig into the data to find out what was behind the buggy algorithm</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50572,
      "author_name": "davidzwoo",
      "author_url": "",
      "post_date": "07/15/2014 14:58:40",
      "content": "<p>For customers that purchased the same category + company + brand, one feature that seems to have some significance was the discount rate of the coupon. I calculated this based on the median amount per qty.</p>\n<p>Lower discount rate seems to have more repeat ability than high.</p>\n<p>Other working theories I had was:</p>\n<p>1) Brand loyalist to a particular brand may be more likely to try a coupon but less likely to switch brands</p>\n<p>2) Whereas brand shifters, maybe more likely to switch brands after trying a coupon.</p>\n<p>One thing wanted to try was time-series clustering by customers buying patterns. Was wondering if anyone had luck with this? or found variables with a time dimension was useful?</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50579,
      "author_name": "grigorydymov",
      "author_url": "",
      "post_date": "07/15/2014 16:11:25",
      "content": "<p>This was my first Kaggle competition. Big thanks to my teammate turbonerd for introducing me to it and keeping the spirit up! Without him, this would not have happened. Thanks to Kaggle for hosting and excellent competition and to the anonymous data provider for the interesting dataset.</p>\n<p>Here are some lessons learned, helpful or not.</p>\n<p><strong>1)</strong> Spent far too much time worrying about our setup, ending up with a combination of MySQL, python scripts with a task-oriented class structure and csv files. Using SQL limited a bit in what aggregates could be produced (no medians etc), but speeded up the feature engineering process. In hindsight, a clean map-reduce would probably have been better.</p>\n<p><strong>2)</strong> It took some time for to figure out what the problem was. When, finally, cross-validation started to work (somewhat), dividing up train set by unique product (company,category,brand combination), a lot of time and wasted effort had elapsed.</p>\n<p><strong>3)</strong> This competition was a lot about feature engineering, and having no experience with that, it took a lot of time and many mistakes were made.</p>\n<p>Some of the best features turned out to be hierarchical, trained separately on data from transactions. E.g. a logistic regression-based probability of buying the product on offer, given which of the top100 most popular products this user had purchased (also did this with brand, category, company, department).</p>\n<p>Other good ones were simple stuff like which fraction of previous trips the user bought this product on. Other ones tried, besides the ones suggested on forums, fall broadly into these categories: weekday statistics (quantities, amounts, measures purchased on certain days), loyalty to products (how many categories in a department a user bought, how many brands for a company etc &#8211; almost all permutations), prior purchase-based (how many times, how often, ), loyalty to store (which weekdays visited, how many times, time period between first and last visit), market, chain, dept-level aggregates of , basket sizes, relative price of offered product to this users usual level for this department, many of above based on 1, 2, 3 months of data prior to offerdate. In total, 214 features.</p>\n<p>We also tried some association rule learning, but dropped it pretty quickly.</p>\n<p><strong>4)</strong> The main mistake was to not be more systematic, which seems obvious in hindsight. We knew that CV was a problem; that offers were very different (repeating ranging 10-40%); that purchase because of coupon and purchase because of prior habits needed to be modeled separately; but somehow did not spend enough time systematically solving these issues, spending most time on feature engineering. A lot more time should have gone into thinking about good ways to train. The absurdity of life is that after all effort with random forests, ridge regression and many others, vowpal vabbit ended up handily beating all out blended attempts at cool models.<br>Also, more time could have gone into looking and visualizing the data.</p>\n<p><strong>5)</strong> Not doing feature selection probably hurt the final performance a lot, since some features ended up to be highly correlated. This is a lesson for next time and it would be interesting to hear if someone managed to automate feature selection somehow.</p>\n<p>We ended up with a ROC AUC of 0.57485 on the private leaderboard, netting us the 545th place. Hard to say if its good or bad for beginners, at least it was very fun and a learning experience.</p>\n<p>Some of the above will probably seem very stupid after reading this thread :)</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50580,
      "author_name": "auduno",
      "author_url": "",
      "post_date": "07/15/2014 16:11:38",
      "content": "<p>One problem&nbsp;I noticed sometimes when cross-validating was that although the classifier had good AUC on each offer individually, the classifier overall had much much poorer total AUC. I'm thinking that this was because the relative probabilities of the different offers was not aligned somehow, but that's just a guess. Did anyone find a principled way to deal with this? I looked around for some theoretical approach to this, but could not find any.</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50581,
      "author_name": "kazanova",
      "author_url": "",
      "post_date": "07/15/2014 16:15:43",
      "content": "<p>[quote=auduno;50580]</p>\n<p>One problem&nbsp;I noticed sometimes when cross-validating was that although the classifier had good AUC on each offer individually, the classifier overall had much much poorer total AUC. I'm thinking that this was because the relative probabilities of the different offers was not aligned somehow, but that's just a guess. Did anyone find a principled way to deal with this? I looked around for some theoretical approach to this, but could not find any.</p>\n<p>[/quote]</p>\n\n<p>You needed 2 models! One to optimize for individual (offer-specific) &nbsp;AUCs and one for the general AUC :) At least, this is what we did. Also scaling helped in this one.</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50589,
      "author_name": "auduno",
      "author_url": "",
      "post_date": "07/15/2014 16:52:27",
      "content": "<p>[quote=KazAnova;50581]</p>\n<p>You needed 2 models! One to optimize for individual (offer-specific) &nbsp;AUCs and one for the general AUC :) At least, this is what we did. Also scaling helped in this one.</p>\n<p>[/quote]</p>\n<p>Ah, I considered that, but didn't get enough time to try it, unfortunately. Did you blend the two models to get final result, or did you use the second model to adjust the relative predictions of the offer-specific models?</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50590,
      "author_name": "kazanova",
      "author_url": "",
      "post_date": "07/15/2014 16:53:20",
      "content": "<p>[quote=auduno;50589]</p>\n<p>[quote=KazAnova;50581]</p>\n<p>You needed 2 models! One to optimize for individual (offer-specific) &nbsp;AUCs and one for the general AUC :) At least, this is what we did. Also scaling helped in this one.</p>\n<p>[/quote]</p>\n<p>Ah, I considered that, but didn't get enough time to try it, unfortunately. Did you blend the two models to get final result, or did you use the second model to adjust the relative predictions of the offer-specific models?</p>\n<p>[/quote]</p>\n\n<p>Blend!</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50591,
      "author_name": "inversion",
      "author_url": "",
      "post_date": "07/15/2014 16:54:28",
      "content": "<p>[quote=Grigory;50579]</p>\n<p>We ended up with a ROC AUC of 0.57485 on the private leaderboard, netting us the 545th place. Hard to say if its good or bad for beginners, at least it was very fun and a learning experience.</p>\n<p>[/quote]</p>\n<p>It doesn't matter where you place, it matters what you learned. And it sounds like you learned a lot!</p>\n<p>I placed in the <em>bottom</em> 10% my first competition, then top 40%, then top 30%, and now top 5% with this competition.</p>\n<p>I'd say you rocked it for your first time. &nbsp;:-)</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50595,
      "author_name": "inversion",
      "author_url": "",
      "post_date": "07/15/2014 17:05:58",
      "content": "<p>[quote=econoraptor;50524]</p>\n<p>[quote=inversion;50507]</p>\n<p>I can't stress enough how important it was to treat high-transaction IDs separate from &quot;regular&quot; IDs.</p>\n<p>I shot up 150 places on the leader board just by doing that.</p>\n<p>Then, breaking out training/testing by offer department was what made the rest of the difference.</p>\n<p>[/quote]</p>\n<p>How did you handle the departments when it came time to make the predictions? I also broke my data up by department, but I found that the test set had quite a few offers for departments that weren't in the train set and vice versa.</p>\n<p>[/quote]</p>\n<p>For each CustID, I did a pivot (using pandas) of the total amount purchased for each dept. (More accurately, I only counted purchases that were &lt;= 180 days from the date of the offer given to that CustID, filtering out any transactions with a 0 count or negative amount.)</p>\n<p>Then I did a PCA on the table. By inspecting the loading plot, I was able to find a dept in the training data that was similarly correlated to a dept in the test data.</p>\n<p>There were 2 depts in the test set that didn't correlate well to any in the training set. For those, I just trained on all the depts in aggregate.</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50597,
      "author_name": "byang1",
      "author_url": "",
      "post_date": "07/15/2014 17:46:38",
      "content": "<p>[quote=KazAnova;50565]</p>\n\n<p>Did you try splitting via offer? E.g train on all offers but one and test on that one. That worked fairly well for me with a little bit more tweaking. E.g to say there should be at least X uplift in order to trust it. For me the was was 0.002 (from AUC 0.610 to AUC 0.612).&nbsp;</p>\n<p>[/quote]</p>\n<p>Hmm, I did split by offer, but didn't try leave-one-out&nbsp;CV. I should try it see what happens.</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50599,
      "author_name": "songgc",
      "author_url": "",
      "post_date": "07/15/2014 18:06:02",
      "content": "<p>[quote=KazAnova;50565]</p>\n<p>[quote=Guocong Song;50516]</p>\n<p>Did you guys make cross-validation work? I had been frustrated with that all the time in the competition...</p>\n<p>[/quote]</p>\n<p>Did you try splitting via offer? E.g train on all offers but one and test on that one. That worked fairly well for me with a little bit more tweaking. E.g to say there should be at least X uplift in order to trust it. For me the was was 0.002 (from AUC 0.610 to AUC 0.612).&nbsp;</p>\n<p>[/quote]</p>\n\n<p>I did a quick try in which I used one offer data to train models against the rest, but didn't work out. I should do normal splitting... &nbsp;Single offer has too large variance:) &nbsp;</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50608,
      "author_name": "chinga",
      "author_url": "",
      "post_date": "07/15/2014 19:55:34",
      "content": "<p>Hi folks, I'm a recent &quot;graduate&quot; of Andrew Ng's machine learning course. I entered this, my first competition, as a training exercise and have thoroughly enjoyed it.</p>\n<p><br>Like Jack Han, I started with RFM (recency, frequency, monetary). Frequency didn't help, but monetary did, especially when binned. I used total spend over the previous 90 days. <br>I used dummy variables for prod, category and dept in bins of &quot;never bought&quot;, 1-15 days ago, 16-30 ago, 31-70 ago. The bins were chosen based on histograms/box-and-whisker plots in Tableau. This is similar to Triskelion's approach, but I didn't use product quantity, just ones and zeros. For brand, I ended up just using the &quot;never bought&quot; bin. I used logistic regression in vw. My features were generated from HP Vertica using SQL, and I used perf to calculate ROC.</p>\n<p><br>I experimented to no avail with various other features to find a proxy for customers who tend to flit between products in the same category: category spend ratios, category entropy, price paid relative to mean. The customer's ratio of distinct products bought per category relative to the average ratio per category worked well on the training set, but harmed my score on the public test set. Like 'inversion', I noticed higher take up for those with high IDs, but it was late in the day and I wasn't able to exploit it with my best model.</p>\n<p><br>In the end, my best submission (0.60291 public and 0.59738 private) was achieved by adding total number of distinct products as a feature. I found that the difference between my train ROC using vw holdout and public ROC varied between 0.47 and 0.57. Is this what others are seeing too?</p>\n<p><br>I had planned to implement a brand loyalty measure (anyone try Guadagni and Little 1983?) and itemset mining. Sadly the day job needed attending to.</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50661,
      "author_name": "ephrance",
      "author_url": "",
      "post_date": "07/16/2014 05:43:20",
      "content": "<p>Similar to Jack Han, for each customer I computed the following score</p>\n<p><code style=\"padding-left: 30px\"> customer_value_score = total_spend_per_day * trxn_per_trip * (1.0/recency) * lifetime * (1.0/avg_interpurchase_time)</code></p>\n<p>where:</p>\n<p style=\"padding-left: 30px\">trxn_per_trip = number of transactions per trip</p>\n<p style=\"padding-left: 30px\">recency = days between last purchase date relative to last date in data</p>\n<p style=\"padding-left: 30px\">lifetime = time elapsed from first purchase date to last purchase date</p>\n<p style=\"padding-left: 30px\">avg_interpurchase_time = is the average time gap between purchases</p>\n\n<p>Being new to Kaggle competitions, I benefited a great deal from combining Triskelion's features with tks's glmnet code + bagging (thanks to meet thakar and clustifier). Additionally, I added return events (quantity &lt; 0) as features. I used the full 22GB dataset.&nbsp;</p>\n\n<p>A great many thanks to Triskelion, tks, culstifier, meet thakar and everyone else for sharing their ideas, insights, and code.</p>\n<p>Cheers!</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50740,
      "author_name": "auduno",
      "author_url": "",
      "post_date": "07/16/2014 22:37:04",
      "content": "<p>[quote=KazAnova;50581]</p>\n<p>You needed 2 models! One to optimize for individual (offer-specific) &nbsp;AUCs and one for the general AUC :) At least, this is what we did. Also scaling helped in this one.</p>\n<p>[/quote]</p>\n<p>I'm guessing you might share the code eventually, but I'm curious : how did you optimize for individual offer-specific AUCs? Most of the offers in the testset were not in the training set, so did you just optimize for those that were in the training set, or did you use some method similar to inversion's method, i.e. finding some combination of the closest &quot;similar&quot; offers to the ones in testset and optimizing for those?</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50741,
      "author_name": "kazanova",
      "author_url": "",
      "post_date": "07/16/2014 22:43:06",
      "content": "<p>[quote=auduno;50740]</p>\n<p>&nbsp;how did you optimize for individual offer-specific AUCs? Most of the offers in the testset were not in the training set, so did you just optimize for those that were in the training set</p>\n<p>[/quote]</p>\n\n<p>For those in the training set only. When I optimized for individual AUCs, I was ignoring the sample size of the offer and I was just averaging the results of the AUCs of the different offers ( 1-out format), When we were optimizing for the total AUC we were appending the results of each offer's prediction&nbsp;in an array and calculating the total AUC once all results had been appended. I hope that helps.&nbsp;</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50765,
      "author_name": "ricgama",
      "author_url": "",
      "post_date": "07/17/2014 11:25:11",
      "content": "<p>[quote=inversion;50507]</p>\n<p>For each CustID, I did a pivot (using pandas) of the total amount purchased for each dept. (More accurately, I only counted purchases that were &lt;= 180 days from the date of the offer given to that CustID, filtering out any transactions with a 0 count or negative amount.)</p>\n<p>Then I did a PCA on the table. By inspecting the loading plot, I was able to find a dept in the training data that was similarly correlated to a dept in the test data.</p>\n<p>There were 2 depts in the test set that didn't correlate well to any in the training set. For those, I just trained on all the depts in aggregate.</p>\n<p>[/quote]</p>\n<p>Hello,<br>Interesting approach. We have applied a Kolmogorov-Smirnov test and selected only features with similar distributions in de train and test sets.<br> Can you give more details about your PCA procedure?</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50779,
      "author_name": "codingneo",
      "author_url": "",
      "post_date": "07/17/2014 13:52:25",
      "content": "<p>[quote=inversion;50507]</p>\n<p>I can't stress enough how important it was to treat high-transaction IDs separate from &quot;regular&quot; IDs.</p>\n<p>I shot up 150 places on the leader board just by doing that.</p>\n<p>Then, breaking out training/testing by offer department was what made the rest of the difference.</p>\n<p>[/quote]</p>\n<p>I read your previous post about your method. I didn't understand how you treat the high-transactions IDs and low-transactions IDs. Can you explain more on it?</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50786,
      "author_name": "ash208948",
      "author_url": "",
      "post_date": "07/17/2014 15:21:59",
      "content": "<p>[quote=inversion;50507]</p>\n<p>That's a very wise move. I wonder if a clustering algorithm to assign&nbsp;customers to different groups based on similarities in their shopping habits would have been helpful; then each group from the test set and train set would have been treated individually.&nbsp;I guess I will never know &nbsp;;)</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50810,
      "author_name": "inversion",
      "author_url": "",
      "post_date": "07/18/2014 00:17:08",
      "content": "<p>[quote=Yiqun Hu;50779]</p>\n<p>I read your previous post about your method. I didn't understand how you treat the high-transactions IDs and low-transactions IDs. Can you explain more on it?</p>\n<p>[/quote]</p>\n<p>Looking at the customer id data (training set), there were ~1,300 ids that had more than 4,000 total transactions. (The highest had&nbsp;2,647,164 transactions!) As was mentioned in the forum earlier, this was probably a &quot;default&quot; card that is used at check-out, e.g., when a shopper doesn't have a loyalty card the store scans a &quot;default&quot; card&nbsp;at the register.</p>\n<p>If you reverse sort the training data by the number of transactions, you'll see that those ids were <em>almost always</em> repeat shoppers. (See the image below.) The fact that these are repeat buyers is an artifact of including these &quot;default&quot; cards in with normal shoppers.</p>\n<p>I simply removed these high-transaction ids and trained without them. For the test set, any id that had a high transaction count, I manually set it to &quot;1&quot; for the estimated repeater probability. Doing this was a &quot;freebie&quot; improvement in score.</p>\n<p><img src=\"http://i.imgur.com/rH6LMUL.png\" alt=\"Repeaters\" width=\"416\" height=\"762\"></p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50811,
      "author_name": "byang1",
      "author_url": "",
      "post_date": "07/18/2014 00:33:49",
      "content": "<p>[quote=inversion;50810]</p>\n<p>I simply removed these high-transaction ids and trained without them. For the test set, any id that had a high transaction count, I manually set it to &quot;1&quot; for the estimated repeater probability. Doing this was a &quot;freebie&quot; improvement in score.</p>\n<p>[/quote]</p>\n<p>How much improvement did you get from this ?</p>\n<p>Another possible &quot;freebie&quot; is to train the offers that are in both train and test sets separately. However I didn't use&nbsp;this in the end because the improvement was small, and the CV unreliable.</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50814,
      "author_name": "inversion",
      "author_url": "",
      "post_date": "07/18/2014 01:21:20",
      "content": "<p>[quote=B Yang;50811]</p>\n<p>[quote=inversion;50810]</p>\n<p>I simply removed these high-transaction ids and trained without them. For the test set, any id that had a high transaction count, I manually set it to &quot;1&quot; for the estimated repeater probability. Doing this was a &quot;freebie&quot; improvement in score.</p>\n<p>[/quote]</p>\n<p>How much improvement did you get from this ?</p>\n<p>[/quote]</p>\n<p>From 0.59507 to 0.61017</p>\n<p>+150 positions on the leader board or so.</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50816,
      "author_name": "inversion",
      "author_url": "",
      "post_date": "07/18/2014 01:36:58",
      "content": "<p>[quote=RW;50765]</p>\n<p>[quote=inversion;50507]</p>\n<p>For each CustID, I did a pivot (using pandas) of the total amount purchased for each dept. (More accurately, I only counted purchases that were &lt;= 180 days from the date of the offer given to that CustID, filtering out any transactions with a 0 count or negative amount.)</p>\n<p>Then I did a PCA on the table. By inspecting the loading plot, I was able to find a dept in the training data that was similarly correlated to a dept in the test data.</p>\n<p>There were 2 depts in the test set that didn't correlate well to any in the training set. For those, I just trained on all the depts in aggregate.</p>\n<p>[/quote]</p>\n<p>Hello,<br>Interesting approach. We have applied a Kolmogorov-Smirnov test and selected only features with similar distributions in de train and test sets.<br> Can you give more details about your PCA procedure?</p>\n<p>[/quote]</p>\n<p>Sure. My data table looked like this. (Rows = CustIDs, Columns = Depts, Values = sum of customer transactions for each dept [truncated at 180 days from offer date and ignoring negative transaction amounts]) The amounts were transformed with arcsinh for scaling.</p>\n<p><img src=\"http://i.imgur.com/Ld5cXdw.png\" alt=\"Dept Pivot Table.\" width=\"449\" height=\"204\"></p>\n<p>I then did a 2-component PCA on the table. (I don't have an image of the loading plot handy, otherwise I'd show it. I used 3 different computers . . . so my files are all over the place. If I stumble upon it I'll post it later.)<br><br>The loading plot showed a position for each department.&nbsp;</p>\n<p>For departments that were in the test set but not in the train set, I looked at the loading plot to find a department that was close to that point that was also in the training set.</p>\n<p>For instance, I trained on Dept 44 to test for Dept 7. For Dept 45 and 51, I used Dept 55 for training.</p>\n<p>Departments 72 and 91 didn't covary well with any departments in the training set, so I used the entire training set to predict those departments.</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50861,
      "author_name": "npetitclerc",
      "author_url": "",
      "post_date": "07/18/2014 16:43:47",
      "content": "<p>Like many mention before the CV problem with he public leader board came from the very strong &quot;Offer ID&quot; bias (some offers were much more successful then others). The way I dealt with it was to find a &quot;repeat ratio&quot; for each &quot;Offer ID&quot; and use that as a feature. I also did the same for all the offers info (Market, dept, brand, etc..). These were all quite strong features for me. This method had the obvious issue that some offers were not in the training data (or had very low statistics), but that's the best I could come up with.</p>\n<p>The other features I didn't see people talk about, but that I though were clever, was a measure of how faithful a customer was to products in general. For that I when through all the products a customer ever bought and found how many times he bought it again. From that data I found the usual statistics (min/max, mean. median, standard deviation, etc...), and more importantly a &quot;repeater ratio&quot;, which is basically how many purchases they made divided by the number of different products they bought.&nbsp;I liked that feature the most because:</p>\n<p>1 - It makes sense - people that are faithful to their products (or don't bother looking for new ones) are more likely to become faithful to a &nbsp;new product they try. &nbsp; &nbsp;</p>\n<p>2 - It turned out to be quite a strong feature.</p>\n<p>My best model was using Scikit-learn with AdaBoost (n_estimators=200) with Random Forest (n_estimators=200, max_depth=2) for base_estimator.</p>\n<p>PS. If someone is good with Neural Networks, I would be very curious to see how my set of features would do with that. It was my next step, but I never had a chance to try it.</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50866,
      "author_name": "irisren",
      "author_url": "",
      "post_date": "07/18/2014 17:46:23",
      "content": "<p>[quote=cherrybarry;50521]</p>\n<p>For me, the most significant&nbsp;improvement was combining the models, but not with a straight average of probabilities. Instead, for each model, I ordered each test offer by&nbsp;repeatProbability, then reassigned them with evenly distributed probabilities on a scale of 0 to 1, and then performed the average. I figured given the AUC metric, the ordering was more important than the actual probability from any model. This gave an improvement on the public&nbsp;leaderboard from ~0.605 to ~0.611.</p>\n<p>[/quote]</p>\n\n<p>Thank you for sharing your method. I have struggled on how to ensemble different models. Can you elaborate on how you assigned scores from different models&nbsp;evenly distributed probabilities on a scale of 0 to 1?&nbsp;</p>\n<p>Thank you for your help.&nbsp;</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50867,
      "author_name": "irisren",
      "author_url": "",
      "post_date": "07/18/2014 17:50:26",
      "content": "<p>[quote=Wei Wu;50531]</p>\n<p>I discovered the same very effective mixing/ensembling method as cherrybarry. Since with AUC only the ranking matters, and the predictions from different models have very different scale/ranges, so averaging their rankings instead of the prediction values makes more sense and gives much better results.</p>\n<p>[/quote]</p>\n<p>How did you average the rankings and transform that into probabilities? Could you explain a little bit more? Thank you!&nbsp;</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 50882,
      "author_name": "justmarkham",
      "author_url": "",
      "post_date": "07/18/2014 21:12:46",
      "content": "<p>[quote=Iris Ren;50866]</p>\n<p>[quote=cherrybarry;50521]</p>\n<p>For me, the most significant&nbsp;improvement was combining the models, but not with a straight average of probabilities. Instead, for each model, I ordered each test offer by&nbsp;repeatProbability, then reassigned them with evenly distributed probabilities on a scale of 0 to 1, and then performed the average. I figured given the AUC metric, the ordering was more important than the actual probability from any model. This gave an improvement on the public&nbsp;leaderboard from ~0.605 to ~0.611.</p>\n<p>[/quote]</p>\n<p>Thank you for sharing your method. I have struggled on how to ensemble different models. Can you elaborate on how you assigned scores from different models&nbsp;evenly distributed probabilities on a scale of 0 to 1?&nbsp;</p>\n<p>Thank you for your help.&nbsp;</p>\n<p>[/quote]</p>\n<p>I can't speak for cherrybarry, but here is how I would do it:</p>\n<ul>\n<li>Sort the model predictions by repeatProbability in ascending&nbsp;order (first row is the lowest value&nbsp;such as 0 or 0.001, and last row is the highest&nbsp;value such as 0.999 or 1).</li>\n<li>Add a new variable called adjustedProbability. For each record, set adjustedProbability to be equal to it's row number divided by the total number of rows. So for the first row, divide 1 by 151484. For the second row, 2/151484. And so on, with 151484/151484 for&nbsp;the last row.</li>\n</ul>\n<p>You will now have evenly distributed probabilities between 0 and 1. Do that for each model, and then to ensemble, take a straight average of the adjustedProbability: (model 1 + model 2) / 2</p>\n<p>Or, you could weight the models differently: (model1 + 2*model 2 + 3*model 3) / 6</p>",
      "votes": null,
      "replies": []
    }
  ],
  "raw_markdown_by_id": {
    "50501": "",
    "50503": "",
    "50505": "",
    "50506": "",
    "50507": "",
    "50508": "",
    "50509": "",
    "50511": "",
    "50515": "",
    "50516": "",
    "50517": "",
    "50518": "",
    "50519": "",
    "50520": "",
    "50521": "",
    "50524": "",
    "50525": "",
    "50527": "",
    "50528": "",
    "50531": "",
    "50533": "",
    "50534": "",
    "50537": "",
    "50544": "",
    "50547": "",
    "50549": "",
    "50552": "",
    "50564": "",
    "50565": "",
    "50566": "",
    "50568": "",
    "50570": "",
    "50571": "",
    "50572": "",
    "50579": "",
    "50580": "",
    "50581": "",
    "50589": "",
    "50590": "",
    "50591": "",
    "50595": "",
    "50597": "",
    "50599": "",
    "50608": "",
    "50661": "",
    "50740": "",
    "50741": "",
    "50765": "",
    "50779": "",
    "50786": "",
    "50810": "",
    "50811": "",
    "50814": "",
    "50816": "",
    "50861": "",
    "50866": "",
    "50867": "",
    "50882": "",
    "1343061": "Hi , can you explain what is TCOB? I have been breaking my head over this. \nAlso, can this be done without Python?"
  },
  "source": "meta"
}