{
  "id": 82746,
  "title": "36th place solution",
  "url": "/competitions/ga-customer-revenue-prediction/discussion/82746",
  "author_name": "CoreyJamesLevinson",
  "post_date": "2019-03-04T01:51:45.964000",
  "votes": 14,
  "comment_count": 0,
  "views": 0,
  "content": "<h1>Just show me the code!</h1>\n\n<ol>\n<li>Initial data analysis: <a href=\"https://www.kaggle.com/returnofsputnik/data-analysis-using-r\">https://www.kaggle.com/returnofsputnik/data-analysis-using-r</a></li>\n<li>Model: <a href=\"https://www.kaggle.com/returnofsputnik/gstore-r-only-test-data\">https://www.kaggle.com/returnofsputnik/gstore-r-only-test-data</a></li>\n</ol>\n\n<h1>Abusing the leak before the reset</h1>\n\n<p>The first thing I did when I saw the Google Analytics Demo Account was posted online was to try to familiarize myself with the environment. I was searching around trying to understand it, and then I clicked the User Explorer tab. I found out that the Client ID for each user actually had the visitID of the first session of the visitor. And I found that if I click on this user, I can map each visit to how much he spent based on the number of pageviews he made in that session. So, I simply exported all of this information, and was changing my submission based on what this user export said! This is how I was able to skyrocket to #1 on LB before the reset, and it spawned the \"Insight or Dodgy?\" discussion that led to this competition's reset.</p>\n\n<h1>Construction of solution</h1>\n\n<h2>Validation Set</h2>\n\n<p>First we must realize that the test set was going to be graded on December 1 2018 to January 31 2019. Therefore I reserved December 1 2017 to January 31 2018 as my validation dataset, instead of using the standard May 1 2018 to October 15 2018 that was issued as the \"test set\". I did this because I thought this period was holiday/Christmas period, and therefore I thought the behavior of the customers during this period would be significantly different from the behavior of the customers during other periods.</p>\n\n<h2>Data Preprocessing</h2>\n\n<p>First, I convert all columns with 2 unique values into binary. I then impute some NAs based on what they should logically be. I updated some values, that for anyone who \"bounced\" from the website, their sessionQuality was set to 1 (the lowest possible) and their timeOnSite was set to 1 (the lowest possible).</p>\n\n<p>For everyone who didn't bounce, and there was no logical imputation for NA, I imputed with the median. I created new binary columns representing if the column was originally NA or not.</p>\n\n<h2>Feature Engineering</h2>\n\n<p>I did a lot of feature engineering in this competition:</p>\n\n<ol>\n<li>Time until final visit</li>\n<li>Time of last visit (max visit)</li>\n<li>Time of first visit (min visit)</li>\n<li>Difference between time of last and first visits</li>\n<li>Difference between current visit and first/last visits</li>\n<li>Ratio of 5 and 4</li>\n<li>Do the same for visitId (I do this because visitId doesn't always go up by 1 for each visit, so maybe a gap in visitId signified something)</li>\n<li>Take log1p(abs(x)) of these feature engineered to homogenize values</li>\n<li>Take the length of the gclId </li>\n<li>Obtain the last 3 characters of the gclId (this can be a new category)</li>\n<li>Consolidate browsers into fewer categories based on research. Include a new category called \"nonhuman\" for spiders and scrapers</li>\n<li>Consolidate operatingSystem into fewer categories</li>\n<li>Get the timezones for each country, being more specific when countries have multiple timezones by looking into the city</li>\n<li>Obtain the \"local\" visitStartTime by converting the UTC visit start time into the local time</li>\n<li>Obtain hour, day of year, weekday, week, month, and year values from the local visit time.</li>\n<li>Append GDP data to all countries</li>\n<li>Append binary column to say if English is the country's official language</li>\n<li>Using Bing Maps API I was able to get the longitude and latitude of every city. Append the longitude and latitude as features</li>\n<li>Compute Haversine distances from San Francisco given the coordinates</li>\n<li>Compute Bearing distances from San Francisco given the coordinates</li>\n<li>Consolidate adwordsClickInfoSlot</li>\n<li>Replace unseen countries with similar countries (e.g. Samoa replaced with American Samoa, Micronesia replaced with Vanuatu, etc.)</li>\n<li>Consolidate trafficSource links (e.g. anything that has \"amazon\" in it, just let it be \"amazon.com\"; anything that has \"kik\" in it, let it be \"kik.com\". etc.)</li>\n<li>Binary column if trafficSource has the word \"google\" in it</li>\n<li>Binary column if trafficSource has the word \".com\" in it</li>\n<li>Binary column if referralPath has the word \"google\" in it</li>\n<li>Binary column if the referralPath has the word \"youtube\" in it</li>\n<li>Binary column if the referralPath has the word \"intl\" in it</li>\n<li>Binary column if the referralPath has the word \"html\" in it</li>\n</ol>\n\n<h2>Aggregation to user-based level</h2>\n\n<p>Recall this is at a visit-based level, but we need to make user-based predictions. Therefore I had to aggregate all these features by taking maxes, mins, sums, means, standard deviations, heads, tails and modes. The aggregations I chose were based on what I thought would be important. I also made some aggregations based on time, e.g. I took the mean of the customer's lifetime and the mean from the last 6 months, because I saw that features like these can improve the model from the previous Home Credit competition.</p>\n\n<p>I took logs of some aggregated features if I found their distribution was better. This was determined using kernel density plots.</p>\n\n<h2>Validation Modeling</h2>\n\n<p>There were two parts to my solution:\n1. First, make a model to predict if the buyer will make a purchase in the future\n2. A regression that predicts how much they will spend in the future</p>\n\n<p>First, I tuned my parameters using the validation set. I predicted 0 or 1 did you make a purchase or not. Performance was looking good.</p>\n\n<h2>Prediction Modeling</h2>\n\n<p>Once I was satisfied with my validation, I retrained the model on the entire dataset using 4 StratifiedKFold. This is one of my errors--I should have used TimeSplitFold instead.</p>\n\n<p>I generated binary OOFs to feed to the regression, and I achieved an AUC of 0.95255 and Log Loss of 0.0020877.</p>\n\n<p>Add these predictions to a LightGBM fitted to minimize MSE. This got my mean absolute error to 0.01147 and my root mean square error to 0.320785.</p>\n\n<p>Run this procedure 4 times using 4 different seeds and average the results. Then you obtain my submission!</p>\n\n<p>Things I tried that didn't work:</p>\n\n<ol>\n<li>Tons of ratios between the aggregate features, based on the 6 month aggregate versus the lifetime aggregate.</li>\n<li>I had this idea in my head that perfecting the CV on my validation set wasn't a good idea, because I would be \"overfitting\" the validation set instead of allowing it to generalize to a test set. I should have looked into observing the difference between my training losses and validation losses to see how well the models were generalizing, and based on this make my decision.</li>\n</ol>\n\n<p>Things that I know to do for next time:</p>\n\n<ol>\n<li>Obviously, the assumption of seasonality for the test period was false based on EDA. I should have explored this before making the assumption, and if I did, I would have made a bunch of windows to train on like many other top competitors did. This would have added model strength</li>\n<li>I should have tried multiplying the probability of a purchase by the regression, instead of simply feeding that as a feature to LightGBM. In fact, the #1 submission in this competition and the #1 in the recently ended Elo Merchant competition both used this technique of multiplying the regression by probability.</li>\n<li>I should have looked into reducing the dimensionality of my featureset. I doubt every feature was useful, and because there were so many features I think this harmed the ability of LightGBM to perform well.</li>\n</ol>",
  "messages": [
    {
      "id": 483017,
      "postDate": "2019-03-04T01:51:45.963Z",
      "content": "<h1>Just show me the code!</h1>\n\n<ol>\n<li>Initial data analysis: <a href=\"https://www.kaggle.com/returnofsputnik/data-analysis-using-r\">https://www.kaggle.com/returnofsputnik/data-analysis-using-r</a></li>\n<li>Model: <a href=\"https://www.kaggle.com/returnofsputnik/gstore-r-only-test-data\">https://www.kaggle.com/returnofsputnik/gstore-r-only-test-data</a></li>\n</ol>\n\n<h1>Abusing the leak before the reset</h1>\n\n<p>The first thing I did when I saw the Google Analytics Demo Account was posted online was to try to familiarize myself with the environment. I was searching around trying to understand it, and then I clicked the User Explorer tab. I found out that the Client ID for each user actually had the visitID of the first session of the visitor. And I found that if I click on this user, I can map each visit to how much he spent based on the number of pageviews he made in that session. So, I simply exported all of this information, and was changing my submission based on what this user export said! This is how I was able to skyrocket to #1 on LB before the reset, and it spawned the \"Insight or Dodgy?\" discussion that led to this competition's reset.</p>\n\n<h1>Construction of solution</h1>\n\n<h2>Validation Set</h2>\n\n<p>First we must realize that the test set was going to be graded on December 1 2018 to January 31 2019. Therefore I reserved December 1 2017 to January 31 2018 as my validation dataset, instead of using the standard May 1 2018 to October 15 2018 that was issued as the \"test set\". I did this because I thought this period was holiday/Christmas period, and therefore I thought the behavior of the customers during this period would be significantly different from the behavior of the customers during other periods.</p>\n\n<h2>Data Preprocessing</h2>\n\n<p>First, I convert all columns with 2 unique values into binary. I then impute some NAs based on what they should logically be. I updated some values, that for anyone who \"bounced\" from the website, their sessionQuality was set to 1 (the lowest possible) and their timeOnSite was set to 1 (the lowest possible).</p>\n\n<p>For everyone who didn't bounce, and there was no logical imputation for NA, I imputed with the median. I created new binary columns representing if the column was originally NA or not.</p>\n\n<h2>Feature Engineering</h2>\n\n<p>I did a lot of feature engineering in this competition:</p>\n\n<ol>\n<li>Time until final visit</li>\n<li>Time of last visit (max visit)</li>\n<li>Time of first visit (min visit)</li>\n<li>Difference between time of last and first visits</li>\n<li>Difference between current visit and first/last visits</li>\n<li>Ratio of 5 and 4</li>\n<li>Do the same for visitId (I do this because visitId doesn't always go up by 1 for each visit, so maybe a gap in visitId signified something)</li>\n<li>Take log1p(abs(x)) of these feature engineered to homogenize values</li>\n<li>Take the length of the gclId </li>\n<li>Obtain the last 3 characters of the gclId (this can be a new category)</li>\n<li>Consolidate browsers into fewer categories based on research. Include a new category called \"nonhuman\" for spiders and scrapers</li>\n<li>Consolidate operatingSystem into fewer categories</li>\n<li>Get the timezones for each country, being more specific when countries have multiple timezones by looking into the city</li>\n<li>Obtain the \"local\" visitStartTime by converting the UTC visit start time into the local time</li>\n<li>Obtain hour, day of year, weekday, week, month, and year values from the local visit time.</li>\n<li>Append GDP data to all countries</li>\n<li>Append binary column to say if English is the country's official language</li>\n<li>Using Bing Maps API I was able to get the longitude and latitude of every city. Append the longitude and latitude as features</li>\n<li>Compute Haversine distances from San Francisco given the coordinates</li>\n<li>Compute Bearing distances from San Francisco given the coordinates</li>\n<li>Consolidate adwordsClickInfoSlot</li>\n<li>Replace unseen countries with similar countries (e.g. Samoa replaced with American Samoa, Micronesia replaced with Vanuatu, etc.)</li>\n<li>Consolidate trafficSource links (e.g. anything that has \"amazon\" in it, just let it be \"amazon.com\"; anything that has \"kik\" in it, let it be \"kik.com\". etc.)</li>\n<li>Binary column if trafficSource has the word \"google\" in it</li>\n<li>Binary column if trafficSource has the word \".com\" in it</li>\n<li>Binary column if referralPath has the word \"google\" in it</li>\n<li>Binary column if the referralPath has the word \"youtube\" in it</li>\n<li>Binary column if the referralPath has the word \"intl\" in it</li>\n<li>Binary column if the referralPath has the word \"html\" in it</li>\n</ol>\n\n<h2>Aggregation to user-based level</h2>\n\n<p>Recall this is at a visit-based level, but we need to make user-based predictions. Therefore I had to aggregate all these features by taking maxes, mins, sums, means, standard deviations, heads, tails and modes. The aggregations I chose were based on what I thought would be important. I also made some aggregations based on time, e.g. I took the mean of the customer's lifetime and the mean from the last 6 months, because I saw that features like these can improve the model from the previous Home Credit competition.</p>\n\n<p>I took logs of some aggregated features if I found their distribution was better. This was determined using kernel density plots.</p>\n\n<h2>Validation Modeling</h2>\n\n<p>There were two parts to my solution:\n1. First, make a model to predict if the buyer will make a purchase in the future\n2. A regression that predicts how much they will spend in the future</p>\n\n<p>First, I tuned my parameters using the validation set. I predicted 0 or 1 did you make a purchase or not. Performance was looking good.</p>\n\n<h2>Prediction Modeling</h2>\n\n<p>Once I was satisfied with my validation, I retrained the model on the entire dataset using 4 StratifiedKFold. This is one of my errors--I should have used TimeSplitFold instead.</p>\n\n<p>I generated binary OOFs to feed to the regression, and I achieved an AUC of 0.95255 and Log Loss of 0.0020877.</p>\n\n<p>Add these predictions to a LightGBM fitted to minimize MSE. This got my mean absolute error to 0.01147 and my root mean square error to 0.320785.</p>\n\n<p>Run this procedure 4 times using 4 different seeds and average the results. Then you obtain my submission!</p>\n\n<p>Things I tried that didn't work:</p>\n\n<ol>\n<li>Tons of ratios between the aggregate features, based on the 6 month aggregate versus the lifetime aggregate.</li>\n<li>I had this idea in my head that perfecting the CV on my validation set wasn't a good idea, because I would be \"overfitting\" the validation set instead of allowing it to generalize to a test set. I should have looked into observing the difference between my training losses and validation losses to see how well the models were generalizing, and based on this make my decision.</li>\n</ol>\n\n<p>Things that I know to do for next time:</p>\n\n<ol>\n<li>Obviously, the assumption of seasonality for the test period was false based on EDA. I should have explored this before making the assumption, and if I did, I would have made a bunch of windows to train on like many other top competitors did. This would have added model strength</li>\n<li>I should have tried multiplying the probability of a purchase by the regression, instead of simply feeding that as a feature to LightGBM. In fact, the #1 submission in this competition and the #1 in the recently ended Elo Merchant competition both used this technique of multiplying the regression by probability.</li>\n<li>I should have looked into reducing the dimensionality of my featureset. I doubt every feature was useful, and because there were so many features I think this harmed the ability of LightGBM to perform well.</li>\n</ol>",
      "rawMarkdown": "# Just show me the code!\n\n1. Initial data analysis: https://www.kaggle.com/returnofsputnik/data-analysis-using-r\n2. Model: https://www.kaggle.com/returnofsputnik/gstore-r-only-test-data\n\n# Abusing the leak before the reset\n\nThe first thing I did when I saw the Google Analytics Demo Account was posted online was to try to familiarize myself with the environment. I was searching around trying to understand it, and then I clicked the User Explorer tab. I found out that the Client ID for each user actually had the visitID of the first session of the visitor. And I found that if I click on this user, I can map each visit to how much he spent based on the number of pageviews he made in that session. So, I simply exported all of this information, and was changing my submission based on what this user export said! This is how I was able to skyrocket to #1 on LB before the reset, and it spawned the \"Insight or Dodgy?\" discussion that led to this competition's reset.\n\n# Construction of solution\n\n## Validation Set\n\nFirst we must realize that the test set was going to be graded on December 1 2018 to January 31 2019. Therefore I reserved December 1 2017 to January 31 2018 as my validation dataset, instead of using the standard May 1 2018 to October 15 2018 that was issued as the \"test set\". I did this because I thought this period was holiday/Christmas period, and therefore I thought the behavior of the customers during this period would be significantly different from the behavior of the customers during other periods.\n\n## Data Preprocessing\n\nFirst, I convert all columns with 2 unique values into binary. I then impute some NAs based on what they should logically be. I updated some values, that for anyone who \"bounced\" from the website, their sessionQuality was set to 1 (the lowest possible) and their timeOnSite was set to 1 (the lowest possible).\n\nFor everyone who didn't bounce, and there was no logical imputation for NA, I imputed with the median. I created new binary columns representing if the column was originally NA or not.\n\n## Feature Engineering\n\nI did a lot of feature engineering in this competition:\n\n1. Time until final visit\n2. Time of last visit (max visit)\n3. Time of first visit (min visit)\n4. Difference between time of last and first visits\n5. Difference between current visit and first/last visits\n6. Ratio of 5 and 4\n7. Do the same for visitId (I do this because visitId doesn't always go up by 1 for each visit, so maybe a gap in visitId signified something)\n8. Take log1p(abs(x)) of these feature engineered to homogenize values\n9. Take the length of the gclId \n10. Obtain the last 3 characters of the gclId (this can be a new category)\n12. Consolidate browsers into fewer categories based on research. Include a new category called \"nonhuman\" for spiders and scrapers\n13. Consolidate operatingSystem into fewer categories\n14. Get the timezones for each country, being more specific when countries have multiple timezones by looking into the city\n15. Obtain the \"local\" visitStartTime by converting the UTC visit start time into the local time\n16. Obtain hour, day of year, weekday, week, month, and year values from the local visit time.\n17. Append GDP data to all countries\n18. Append binary column to say if English is the country's official language\n19. Using Bing Maps API I was able to get the longitude and latitude of every city. Append the longitude and latitude as features\n20. Compute Haversine distances from San Francisco given the coordinates\n21. Compute Bearing distances from San Francisco given the coordinates\n22. Consolidate adwordsClickInfoSlot\n23. Replace unseen countries with similar countries (e.g. Samoa replaced with American Samoa, Micronesia replaced with Vanuatu, etc.)\n24. Consolidate trafficSource links (e.g. anything that has \"amazon\" in it, just let it be \"amazon.com\"; anything that has \"kik\" in it, let it be \"kik.com\". etc.)\n25. Binary column if trafficSource has the word \"google\" in it\n26. Binary column if trafficSource has the word \".com\" in it\n27. Binary column if referralPath has the word \"google\" in it\n28. Binary column if the referralPath has the word \"youtube\" in it\n29. Binary column if the referralPath has the word \"intl\" in it\n30. Binary column if the referralPath has the word \"html\" in it\n\n## Aggregation to user-based level\n\nRecall this is at a visit-based level, but we need to make user-based predictions. Therefore I had to aggregate all these features by taking maxes, mins, sums, means, standard deviations, heads, tails and modes. The aggregations I chose were based on what I thought would be important. I also made some aggregations based on time, e.g. I took the mean of the customer's lifetime and the mean from the last 6 months, because I saw that features like these can improve the model from the previous Home Credit competition.\n\nI took logs of some aggregated features if I found their distribution was better. This was determined using kernel density plots.\n\n## Validation Modeling\n\nThere were two parts to my solution:\n1. First, make a model to predict if the buyer will make a purchase in the future\n2. A regression that predicts how much they will spend in the future\n\nFirst, I tuned my parameters using the validation set. I predicted 0 or 1 did you make a purchase or not. Performance was looking good.\n\n## Prediction Modeling\n\nOnce I was satisfied with my validation, I retrained the model on the entire dataset using 4 StratifiedKFold. This is one of my errors--I should have used TimeSplitFold instead.\n\nI generated binary OOFs to feed to the regression, and I achieved an AUC of 0.95255 and Log Loss of 0.0020877.\n\nAdd these predictions to a LightGBM fitted to minimize MSE. This got my mean absolute error to 0.01147 and my root mean square error to 0.320785.\n\nRun this procedure 4 times using 4 different seeds and average the results. Then you obtain my submission!\n\nThings I tried that didn't work:\n\n1. Tons of ratios between the aggregate features, based on the 6 month aggregate versus the lifetime aggregate.\n2. I had this idea in my head that perfecting the CV on my validation set wasn't a good idea, because I would be \"overfitting\" the validation set instead of allowing it to generalize to a test set. I should have looked into observing the difference between my training losses and validation losses to see how well the models were generalizing, and based on this make my decision.\n\nThings that I know to do for next time:\n\n1. Obviously, the assumption of seasonality for the test period was false based on EDA. I should have explored this before making the assumption, and if I did, I would have made a bunch of windows to train on like many other top competitors did. This would have added model strength\n2. I should have tried multiplying the probability of a purchase by the regression, instead of simply feeding that as a feature to LightGBM. In fact, the #1 submission in this competition and the #1 in the recently ended Elo Merchant competition both used this technique of multiplying the regression by probability.\n3. I should have looked into reducing the dimensionality of my featureset. I doubt every feature was useful, and because there were so many features I think this harmed the ability of LightGBM to perform well.",
      "votes": 14
    }
  ],
  "comments": [],
  "raw_markdown_by_id": {
    "483017": "# Just show me the code!\n\n1. Initial data analysis: https://www.kaggle.com/returnofsputnik/data-analysis-using-r\n2. Model: https://www.kaggle.com/returnofsputnik/gstore-r-only-test-data\n\n# Abusing the leak before the reset\n\nThe first thing I did when I saw the Google Analytics Demo Account was posted online was to try to familiarize myself with the environment. I was searching around trying to understand it, and then I clicked the User Explorer tab. I found out that the Client ID for each user actually had the visitID of the first session of the visitor. And I found that if I click on this user, I can map each visit to how much he spent based on the number of pageviews he made in that session. So, I simply exported all of this information, and was changing my submission based on what this user export said! This is how I was able to skyrocket to #1 on LB before the reset, and it spawned the \"Insight or Dodgy?\" discussion that led to this competition's reset.\n\n# Construction of solution\n\n## Validation Set\n\nFirst we must realize that the test set was going to be graded on December 1 2018 to January 31 2019. Therefore I reserved December 1 2017 to January 31 2018 as my validation dataset, instead of using the standard May 1 2018 to October 15 2018 that was issued as the \"test set\". I did this because I thought this period was holiday/Christmas period, and therefore I thought the behavior of the customers during this period would be significantly different from the behavior of the customers during other periods.\n\n## Data Preprocessing\n\nFirst, I convert all columns with 2 unique values into binary. I then impute some NAs based on what they should logically be. I updated some values, that for anyone who \"bounced\" from the website, their sessionQuality was set to 1 (the lowest possible) and their timeOnSite was set to 1 (the lowest possible).\n\nFor everyone who didn't bounce, and there was no logical imputation for NA, I imputed with the median. I created new binary columns representing if the column was originally NA or not.\n\n## Feature Engineering\n\nI did a lot of feature engineering in this competition:\n\n1. Time until final visit\n2. Time of last visit (max visit)\n3. Time of first visit (min visit)\n4. Difference between time of last and first visits\n5. Difference between current visit and first/last visits\n6. Ratio of 5 and 4\n7. Do the same for visitId (I do this because visitId doesn't always go up by 1 for each visit, so maybe a gap in visitId signified something)\n8. Take log1p(abs(x)) of these feature engineered to homogenize values\n9. Take the length of the gclId \n10. Obtain the last 3 characters of the gclId (this can be a new category)\n12. Consolidate browsers into fewer categories based on research. Include a new category called \"nonhuman\" for spiders and scrapers\n13. Consolidate operatingSystem into fewer categories\n14. Get the timezones for each country, being more specific when countries have multiple timezones by looking into the city\n15. Obtain the \"local\" visitStartTime by converting the UTC visit start time into the local time\n16. Obtain hour, day of year, weekday, week, month, and year values from the local visit time.\n17. Append GDP data to all countries\n18. Append binary column to say if English is the country's official language\n19. Using Bing Maps API I was able to get the longitude and latitude of every city. Append the longitude and latitude as features\n20. Compute Haversine distances from San Francisco given the coordinates\n21. Compute Bearing distances from San Francisco given the coordinates\n22. Consolidate adwordsClickInfoSlot\n23. Replace unseen countries with similar countries (e.g. Samoa replaced with American Samoa, Micronesia replaced with Vanuatu, etc.)\n24. Consolidate trafficSource links (e.g. anything that has \"amazon\" in it, just let it be \"amazon.com\"; anything that has \"kik\" in it, let it be \"kik.com\". etc.)\n25. Binary column if trafficSource has the word \"google\" in it\n26. Binary column if trafficSource has the word \".com\" in it\n27. Binary column if referralPath has the word \"google\" in it\n28. Binary column if the referralPath has the word \"youtube\" in it\n29. Binary column if the referralPath has the word \"intl\" in it\n30. Binary column if the referralPath has the word \"html\" in it\n\n## Aggregation to user-based level\n\nRecall this is at a visit-based level, but we need to make user-based predictions. Therefore I had to aggregate all these features by taking maxes, mins, sums, means, standard deviations, heads, tails and modes. The aggregations I chose were based on what I thought would be important. I also made some aggregations based on time, e.g. I took the mean of the customer's lifetime and the mean from the last 6 months, because I saw that features like these can improve the model from the previous Home Credit competition.\n\nI took logs of some aggregated features if I found their distribution was better. This was determined using kernel density plots.\n\n## Validation Modeling\n\nThere were two parts to my solution:\n1. First, make a model to predict if the buyer will make a purchase in the future\n2. A regression that predicts how much they will spend in the future\n\nFirst, I tuned my parameters using the validation set. I predicted 0 or 1 did you make a purchase or not. Performance was looking good.\n\n## Prediction Modeling\n\nOnce I was satisfied with my validation, I retrained the model on the entire dataset using 4 StratifiedKFold. This is one of my errors--I should have used TimeSplitFold instead.\n\nI generated binary OOFs to feed to the regression, and I achieved an AUC of 0.95255 and Log Loss of 0.0020877.\n\nAdd these predictions to a LightGBM fitted to minimize MSE. This got my mean absolute error to 0.01147 and my root mean square error to 0.320785.\n\nRun this procedure 4 times using 4 different seeds and average the results. Then you obtain my submission!\n\nThings I tried that didn't work:\n\n1. Tons of ratios between the aggregate features, based on the 6 month aggregate versus the lifetime aggregate.\n2. I had this idea in my head that perfecting the CV on my validation set wasn't a good idea, because I would be \"overfitting\" the validation set instead of allowing it to generalize to a test set. I should have looked into observing the difference between my training losses and validation losses to see how well the models were generalizing, and based on this make my decision.\n\nThings that I know to do for next time:\n\n1. Obviously, the assumption of seasonality for the test period was false based on EDA. I should have explored this before making the assumption, and if I did, I would have made a bunch of windows to train on like many other top competitors did. This would have added model strength\n2. I should have tried multiplying the probability of a purchase by the regression, instead of simply feeding that as a feature to LightGBM. In fact, the #1 submission in this competition and the #1 in the recently ended Elo Merchant competition both used this technique of multiplying the regression by probability.\n3. I should have looked into reducing the dimensionality of my featureset. I doubt every feature was useful, and because there were so many features I think this harmed the ability of LightGBM to perform well."
  },
  "complete": true,
  "source": "existing_discussion",
  "competition_id": 10038,
  "competition_slug": "ga-customer-revenue-prediction",
  "team_id": 2096219,
  "solution_url": "/competitions/ga-customer-revenue-prediction/writeups/coreylevinson-r-only-36th-place-solution"
}