Updates to gaming churn prediction (#112)

* Updates to gaming churn prediction

* Ran linter

Co-authored-by: ivanmkc <ivans.mailbox@gmail.com>
This commit is contained in:
Aaron Dietz
2021-10-22 19:53:06 -04:00
committed by GitHub
co-authored by ivanmkc
parent 263a03f89c
commit 4c9e03107b
@@ -15,25 +15,25 @@
"id": "81facaeb11b6"
},
"source": [
"## Table Of Contents\n",
"## Table of contents\n",
"\n",
"* [Overview](#section-1)\n",
"* [Dataset](#section-2)\n",
"* [Objective](#section-3)\n",
"* [Costs](#section-4)\n",
"* [Create a BigQuery dataset](#section-5)\n",
"* [Explore Data](#section-6)\n",
"* [Explore data](#section-6)\n",
"* [Preparing the training data](#section-7)\n",
"\t* [Identifying the label for each user](#section-7-subsection-1)\n",
" * [Extracting demographic data for each user](#section-7-subsection-2)\n",
"\t* [Extracting behavioral data for each user](#section-7-subsection-3)\n",
"\t* [Combining the label, demographic and behavioral data together as training data](#section-7-subsection-4)\n",
"\n",
"* [Training the propensity model with BigQuery ML](#section-8)\n",
"* [Model Evaluation](#section-9)\n",
"* [Model evaluation](#section-9)\n",
"\t* [Confusion matrix: predicted vs actual values](#section-9-subsection-1)\n",
"\t* [ROC Curve](#section-9-subsection-2)\n",
"* [Model prediction](#section-10) \n",
"* [Export predictions table to Google Cloud Storage](#section-11)\n",
"* [Export predictions table to Cloud Storage](#section-11)\n",
"* [Clean up](#section-12)"
]
},
@@ -46,7 +46,9 @@
"## Overview\n",
"<a name=\"section-1\"></a>\n",
"\n",
"This notebook shows you how you can train, evaluate, and deploy a propensity model in BigQuery ML to predict user retention on a mobile game, based on app measurement data from Google Analytics 4.\n"
"This tutorial shows you how to train, evaluate, and deploy a propensity model in BigQuery ML to predict user retention on a mobile game, based on app measurement data from Google Analytics 4.\n",
"\n",
"*Note: This notebook file was designed to run in a [Vertex AI Workbench managed notebooks](https://cloud.google.com/vertex-ai/docs/workbench/managed/create-instance) instance using the `Python (Local)` kernel. Some components of this notebook may not work in other notebook environments.*"
]
},
{
@@ -58,11 +60,11 @@
"## Dataset\n",
"<a name=\"section-2\"></a>\n",
"\n",
"This notebook uses [this public BigQuery dataset](https://console.cloud.google.com/bigquery?p=firebase-public-project&d=analytics_153293282&t=events_20181003&page=table), contains raw event data from a real mobile gaming app called Flood It! ([Android app](https://play.google.com/store/apps/details?id=com.labpixies.flood), [iOS app](https://itunes.apple.com/us/app/flood-it!/id476943146?mt=8)). The [data schema](https://support.google.com/analytics/answer/7029846) originates from Google Analytics for Firebase, but is the same schema as [Google Analytics 4](https://support.google.com/analytics/answer/9358801); this notebook applies to use cases that use either Google Analytics for Firebase or Google Analytics 4 data.\n",
"This notebook uses [this public BigQuery dataset](https://console.cloud.google.com/bigquery?p=firebase-public-project&d=analytics_153293282&t=events_20181003&page=table), which contains raw event data from a real mobile gaming app called Flood It! ([Android app](https://play.google.com/store/apps/details?id=com.labpixies.flood), [iOS app](https://itunes.apple.com/us/app/flood-it!/id476943146?mt=8)). The [data schema](https://support.google.com/analytics/answer/7029846) originates from Google Analytics for Firebase, but is the same schema as [Google Analytics 4](https://support.google.com/analytics/answer/9358801); the techniques in this notebook can be applied to either Google Analytics for Firebase or Google Analytics 4 data.\n",
"\n",
"Google Analytics 4 (GA4) uses an [event-based](https://support.google.com/analytics/answer/9322688) measurement model. Events provide insight on what is happening in an app or on a website, such as user actions, system events, or errors. Every row in the dataset is an event, with various characteristics relevant to that event stored in a nested format within the row. While Google Analytics logs many types of events already by default, developers can also customize the types of events they also wish to log.\n",
"\n",
"Note that as you cannot simply use the raw event data to train a machine learning model, in this notebook, you will also learn the important steps of how to pre-process the raw data into an appropriate format to use as training data for classification models."
"Note that as you cannot simply use the raw event data to train a machine learning model, this notebook shows you some important steps of how to pre-process the raw data into an appropriate format to use as training data for classification models."
]
},
{
@@ -71,14 +73,16 @@
"id": "sH0CZGku0BPp"
},
"source": [
"## Objective and Problem Statement\n",
"## Objective\n",
"<a name=\"section-3\"></a>\n",
"By the end of this notebook, you will know how to:\n",
"* Explore the export of Google Analytics 4 data on BigQuery\n",
"* Prepare the training data using demographic, behavioral data, and the label (churn/not-churn)\n",
"* Train a XGBoost model using BigQuery ML\n",
"* Evaluate model using BigQuery ML\n",
"* Make predictions on which users will churn using BigQuery ML\n"
"\n",
"In this notebook, you will:\n",
"\n",
"* Explore an export of Google Analytics 4 data on BigQuery.\n",
"* Prepare the training data using demographic, behavioral data, and labels (churn/not-churn).\n",
"* Train an XGBoost model using BigQuery ML.\n",
"* Evaluate a model using BigQuery ML.\n",
"* Make predictions on which users will churn using BigQuery ML."
]
},
{
@@ -88,7 +92,20 @@
},
"source": [
"## Costs\n",
"<a name=\"section-4\"></a>\n"
"<a name=\"section-4\"></a>\n",
"\n",
"This tutorial uses the following billable components of Google Cloud:\n",
"\n",
"* Vertex AI\n",
"* BigQuery\n",
"* Cloud Storage\n",
"\n",
"Learn about [Vertex AI\n",
"pricing](https://cloud.google.com/vertex-ai/pricing), [BigQuery\n",
"pricing](https://cloud.google.com/bigquery/pricing) and [Cloud Storage\n",
"pricing](https://cloud.google.com/storage/pricing) and use the [Pricing\n",
"Calculator](https://cloud.google.com/products/calculator/)\n",
"to generate a cost estimate based on your projected usage."
]
},
{
@@ -176,9 +193,6 @@
"\n",
"**The following steps are required, regardless of your notebook environment.**\n",
"\n",
"\n",
"{TODO: Adjust wording in the first paragraph to fit your use case - explain how your tutorial uses the Cloud Storage bucket. The example below shows how Vertex AI uses the bucket for training.}\n",
"\n",
"When you submit a training job using the Cloud SDK, you upload a Python package\n",
"containing your training code to a Cloud Storage bucket. Vertex AI runs\n",
"the code from this package. In this tutorial, Vertex AI also saves the\n",
@@ -296,7 +310,7 @@
"id": "X9TLkb8f0tCE"
},
"source": [
"In this notebook, you will need to create a dataset in your project called `bqmlga4`. To create it, run the following cell:"
"In this notebook, you must create a dataset in your project called `bqmlga4`. To create it, run the following cell:"
]
},
{
@@ -306,7 +320,7 @@
},
"source": [
"#@bigquery\n",
"-- create a dataset in Bigquery\n",
"-- create a dataset in BigQuery\n",
"\n",
"CREATE SCHEMA bqmlga4\n",
"OPTIONS(\n",
@@ -320,7 +334,7 @@
"id": "dcd477550f3f"
},
"source": [
"## Explore Data\n",
"## Explore data\n",
"<a name=\"section-6\"></a>\n"
]
},
@@ -357,7 +371,7 @@
"id": "PYBMN963Qydl"
},
"source": [
"It may be helpful to take a look at the overall schema used in Google Analytics 4. As mentioned earlier, Google Analytics 4 uses an event based measurement model and each row in this dataset is an event. [Click here](https://support.google.com/analytics/answer/7029846) to view the complete schema and details about each column. As you can see above, certain columns are nested records and contain detailed information:\n"
"It may be helpful to take a look at the overall schema used in Google Analytics 4. As mentioned earlier, Google Analytics 4 uses an event-based measurement model and each row in this dataset is an event. [View the complete schema and details about each column](https://support.google.com/analytics/answer/7029846). As you can see above, specific columns are nested records and contain detailed information:"
]
},
{
@@ -373,10 +387,8 @@
"* `geo`\n",
"* `traffic_source`\n",
"* `user_properties`\n",
"* `items`*\n",
"* `web_info`*\n",
"\n",
"_* present by default in GA4 datasets_"
"* `items` (present by default in GA4 datasets)\n",
"* `web_info` (present by default in GA4 datasets)"
]
},
{
@@ -385,7 +397,7 @@
"id": "dLUv-7xNRhAj"
},
"source": [
"As we can see below, there are 15K users and 5.7M events in this dataset:"
"The query results below show that there are 15K users and 5.7M events in this dataset:"
]
},
{
@@ -450,10 +462,10 @@
},
"source": [
"Characteristics of the training data:\n",
"- each row is a separate unique user ID\n",
"- feature(s) for **demographic data**\n",
"- feature(s) for **behavioral data**\n",
"- the actual **label** that you want to train the model to predict (e.g., 1 = churned, 0 = returned)\n",
"- Each row is a separate unique user ID\n",
"- Feature(s) for **demographic data**\n",
"- Feature(s) for **behavioral data**\n",
"- The actual **label** that you want to train the model to predict (for example, 1 = churned, 0 = returned)\n",
"\n",
"You can train a model with only demographic data or behavioral data, but having a combination of both will likely help you create a more predictive model. For this reason, in this section, you will learn how to pre-process the raw data to follow this training data format."
]
@@ -464,12 +476,12 @@
"id": "ICpTsrfg2-Cw"
},
"source": [
"The following sections will walk you through preparing the demographic data, behavioral data, and the label before joining them all together as the training data.\n",
"The following sections will walk you through preparing the demographic data, behavioral data, and the label before joining them all together as the complete training dataset. The steps are:\n",
"\n",
"1. Identifying the label for each user (churned or returned)\n",
"1. Extracting demographic data for each user\n",
"1. Extracting behavioral data for each user\n",
"1. Combining the label, demographic and behavioral data together as training data"
"1. Identify the label for each user (churned or returned)\n",
"1. Extract demographic data for each user\n",
"1. Extract behavioral data for each user\n",
"1. Combine the label, demographic data, and behavioral data together as training data"
]
},
{
@@ -478,8 +490,8 @@
"id": "ZYHefnNx21lO"
},
"source": [
"#### Step 1: Identifying the label for each user\n",
"<a name=\"section-7-subsection-1\"></a>\n"
"#### Step 1: Identify the label for each user\n",
"<a name=\"section-7-subsection-1\"></a>"
]
},
{
@@ -497,16 +509,16 @@
"id": "lgqxD30Hl6FM"
},
"source": [
"There are many ways to define user churn, but for the purposes of this notebook, you will predict 1-day churn as users who do not come back and use the app again after 24 hr of the user's first engagement. \n",
"There are many ways to define user churn, but for the purposes of this notebook, you will predict 1-day churn as users who do not come back and use the app again after 24 hours of the user's first engagement. \n",
"\n",
"In other words, after 24 hr of a user's first engagement with the app:\n",
"In other words, after 24 hours of a user's first engagement with the app:\n",
"- if the user _shows no event data thereafter_, the user is considered **churned**. \n",
"- if the user _does have at least one event datapoint thereafter_, then the user is considered **returned**\n",
"\n",
"You may also want to remove users who were unlikely to have ever returned anyway after spending just a few minutes with the app, which is sometimes referred to as \"bouncing\". For example, we can say want to build our model only on users who spent at least 10 minutes with the app (users who didn't bounce).\n",
"You may also want to remove users who were unlikely to have ever returned anyway after spending just a few minutes with the app, which is sometimes referred to as \"bouncing\". For example, you may want to build the model only on users who spent at least 10 minutes with the app (users who did not bounce).\n",
"\n",
"So your updated definition of a **churned user** for this notebook is:\n",
"> \"any user who spent at least 10 minutes on the app, but after 24 hour from when they first engaged with the app, never used the app again\"\n"
"> \"any user who spent at least 10 minutes on the app, but after 24 hours from when they first engaged with the app, never used the app again\"\n"
]
},
{
@@ -596,7 +608,7 @@
"id": "FOoqPb2J2Q5f"
},
"source": [
"For the `churned` column, `churned=0` if the user performs an action after 24 hours since their first touch, otherwise if their last action was only within the first 24 hours, then `churned=1`.\n"
"For the `churned` column, `churned = 0` if the user performs an action after 24 hours since their first touch, otherwise if their last action was only within the first 24 hours, then `churned = 1`.\n"
]
},
{
@@ -605,7 +617,7 @@
"id": "sC3sIc0C2a4Z"
},
"source": [
"For the `bounced` column, `bounced=1` if the user's last action was within the first ten minutes since their first touch with the app, otherwise `bounced=0`. We can use this column to filter our training data later on, by conditionally querying for users where `bounced = 0`."
"For the `bounced` column, `bounced = 1` if the user's last action was within the first ten minutes since their first touch with the app, otherwise `bounced = 0`. You can use this column to filter the training data later on by conditionally querying for users where `bounced = 0`."
]
},
{
@@ -663,7 +675,7 @@
"id": "08a5324dac82"
},
"source": [
"There are 23% churners in the data which is not bad for training a churn prediction model. If the class-imablance seems to be high, oversampling or undersampling techniques can be considered to balance the class distribution."
"There are 23% churners in the data which is not bad for training a churn prediction model. If the class imbalance seems to be high, oversampling or undersampling techniques can be considered to balance the class distribution."
]
},
{
@@ -672,7 +684,7 @@
"id": "daSQViux_XWR"
},
"source": [
"#### Step 2. Extracting demographic data for each user\n",
"#### Step 2: Extract demographic data for each user\n",
"<a name=\"section-7-subsection-2\"></a>\n"
]
},
@@ -682,7 +694,7 @@
"id": "7417ae7aa9c4"
},
"source": [
"This section is focused on extracting the demographic information for each user. Different demographic information about the user is available in the dataset already, including `app_info`, `device`, `ecommerce`, `event_params`, `geo`. Demographic features can help the model predict whether users on certain devices or countries are more likely to churn.\n",
"This section is focused on extracting the demographic information for each user. Different demographic information about the user is available in the dataset already, including `app_info`, `device`, `ecommerce`, `event_params`, and `geo`. Demographic features can help the model predict whether users on certain devices or countries are more likely to churn.\n",
"\n",
"For this notebook, you can start just with `geo.country`, `device.operating_system`, and `device.language`. If you are using your own dataset and have joinable first-party data, this section is a good opportunity to add any additional attributes for each user that may not be readily available in Google Analytics 4.\n",
"\n",
@@ -739,8 +751,8 @@
"id": "17ffc440f6ba"
},
"source": [
"#### Step 3. Extracting behavioral data for each user\n",
"<a name=\"section-7-subsection-3\"></a>\n"
"#### Step 3: Extract behavioral data for each user\n",
"<a name=\"section-7-subsection-3\"></a>"
]
},
{
@@ -751,9 +763,9 @@
"source": [
"Behavioral data in the raw event data spans across multiple events -- and thus rows -- per user. The goal of this section is to aggregate and extract behavioral data for each user, resulting in one row of behavioral data per unique user.\n",
"\n",
"But what kind of behavioral data will you need to prepare? Since the end goal of this notebook is to predict, based on a user's activity within the first 24 hrs since app installation, whether that user will churn or return thereafter, then you will want to use behavioral data from the first 24 hrs in your training data. Later on, we can also extract some extra time-related features from `user_first_engagement`, such as the month or day of the first engagement.\n",
"But what kind of behavioral data will you need to prepare? Since the end goal of this notebook is to predict, based on a user's activity within the first 24 hours since app installation, whether that user will churn or return thereafter, then you will want to use behavioral data from the first 24 hours in your training data. Later on, you can also extract some extra time-related features from `user_first_engagement`, such as the month or day of the first engagement.\n",
"\n",
"Google Analytics automatically collects [certain events](https://support.google.com/analytics/answer/6317485) that you can use to analyze behavior. In addition, there are certain recommended [events for games](https://support.google.com/analytics/answer/6317494). \n",
"Google Analytics automatically collects [specific events](https://support.google.com/analytics/answer/6317485) that you can use to analyze behavior. In addition, there are recommended [events for games](https://support.google.com/analytics/answer/6317494). \n",
"\n",
"\n",
"As a first step, you can explore all the unique events that exist in this dataset, based on `event_name`:"
@@ -782,7 +794,7 @@
"id": "074a03fae065"
},
"source": [
"For this notebook, to predict whether a user will churn or return, you can start by counting the number of times a user engages in the following event types:\n",
"For this tutorial, to predict whether a user will churn or return, you can start by counting the number of times a user engages in the following event types:\n",
"\n",
"* `user_engagement`\n",
"* `level_start_quickplay`\n",
@@ -794,7 +806,7 @@
"* `ad_reward`\n",
"* `challenge_a_friend`\n",
"* `completed_5_levels`\n",
"* `use_extra_steps`\n"
"* `use_extra_steps`"
]
},
{
@@ -803,9 +815,9 @@
"id": "6d89bc9dfccc"
},
"source": [
"In SQL, you can aggregate the behavioral data by calculating the total number of times when each of the above `event_names` occurred in the data set per user.\n",
"In SQL, you can aggregate the behavioral data by calculating the total number of times when each of the above `event_names` occurred in the dataset per user.\n",
"\n",
"If you are using your own dataset, you may have different event types that you can aggregate and extract. Your app may be sending very different `event_names` to Google Analytics so be sure to use events most suitable to your scenario."
"If you are using your own dataset, you may have different event types that you can aggregate and extract. Your app may be sending very different `event_names` to Google Analytics so be sure to use events suitable to your scenario."
]
},
{
@@ -861,8 +873,8 @@
"id": "89f8c6c44b9c"
},
"source": [
"#### Step 4: Combining the label, demographic and behavioral data together as training data\n",
"<a name=\"section-7-subsection-4\"></a>\n"
"#### Step 4: Combine the label, demographic data, and behavioral data together as training data\n",
"<a name=\"section-7-subsection-4\"></a>"
]
},
{
@@ -871,7 +883,7 @@
"id": "ed161899b055"
},
"source": [
"In this section, you can now combine these three intermediary views (label, demographic, and behavioral data) into the final training data. Here you can also specify `bounced = 0`, in order to limit the training data only to users who did not \"bounce\" within the first 10 minutes of using the app."
"In this section, you can now combine these three intermediary views (label, demographic data, and behavioral data) into the final training dataset. Here you can also specify `bounced = 0`, in order to limit the training data only to users who did not \"bounce\" within the first 10 minutes of using the app."
]
},
{
@@ -962,7 +974,7 @@
"id": "121ca5d0d531"
},
"source": [
"Check percentage of null values "
"Check the percentage of null values."
]
},
{
@@ -1005,7 +1017,7 @@
"id": "fe89ff9223d7"
},
"source": [
"We will use [XGBoost](https://cloud.google.com/bigquery-ml/docs/reference/standard-sql/bigqueryml-syntax-create-boosted-tree) model here. In this notebook, the model predicts whether the user will churn (1) or return (0) after 24 hours of the user's first engagement with the app.\n"
"You will use an [XGBoost](https://cloud.google.com/bigquery-ml/docs/reference/standard-sql/bigqueryml-syntax-create-boosted-tree) model here. In this notebook, the model predicts whether the user will churn (1) or return (0) after 24 hours of the user's first engagement with the app.\n"
]
},
{
@@ -1023,10 +1035,9 @@
"id": "1bfabaccff00"
},
"source": [
"The following code trains an XGBoost model. This may take several minutes to train.\n",
"The following code trains an XGBoost model. This may take several minutes.\n",
"\n",
"For more information on the default hyperparameters used, you can read the documentation: \n",
"[CREATE MODEL statement for Boosted Tree models using XGBoost](https://cloud.google.com/bigquery-ml/docs/reference/standard-sql/bigqueryml-syntax-create-boosted-tree)"
"For more information on the default hyperparameters used, see [The CREATE MODEL statement for boosted tree models using XGBoost](https://cloud.google.com/bigquery-ml/docs/reference/standard-sql/bigqueryml-syntax-create-boosted-tree)."
]
},
{
@@ -1084,7 +1095,7 @@
"id": "6a189c676815"
},
"source": [
"## Model Evaluation\n",
"## Model evaluation\n",
"<a name=\"section-9\"></a>\n"
]
},
@@ -1096,7 +1107,7 @@
"source": [
"To evaluate the model, you can run [`ML.EVALUATE`](https://cloud.google.com/bigquery-ml/docs/reference/standard-sql/bigqueryml-syntax-evaluate) on a model that has finished training to inspect some of the metrics.\n",
"\n",
"The metrics are based on the test sample data that was automatically split during model creation ([documentation](https://cloud.google.com/bigquery-ml/docs/reference/standard-sql/bigqueryml-syntax-create#data_split_method))."
"The metrics are based on the test sample data that was automatically split during model creation ([see the CREATE MODEL documentation for more information](https://cloud.google.com/bigquery-ml/docs/reference/standard-sql/bigqueryml-syntax-create#data_split_method))."
]
},
{
@@ -1118,11 +1129,12 @@
"id": "56ab69bf8857"
},
"source": [
"`ML.EVALUATE` generates the `precision`, `recall`, `accuracy` and `f1_score` using the default classification threshold of 0.5, which can be modified by using the optional [`THRESHOLD`](https://cloud.google.com/bigquery-ml/docs/reference/standard-sql/bigqueryml-syntax-evaluate#eval_threshold) parameter.\n",
"`ML.EVALUATE` generates the `precision`, `recall`, `accuracy`, and `f1_score` using the default classification threshold of 0.5, which can be modified by using the optional [`THRESHOLD`](https://cloud.google.com/bigquery-ml/docs/reference/standard-sql/bigqueryml-syntax-evaluate#eval_threshold) parameter.\n",
"\n",
"Generally speaking, you can use the `log_loss` and `roc_auc` metrics to compare model performance.\n",
"\n",
"The `log_loss` ranges between 0 and 1.0, and the closer the `log_loss` is the zero, the closer the predicted labels were to the actual labels.\n",
"The `log_loss` ranges between 0 and 1.0, and the closer the `log_loss` is to zero, the closer the predicted labels were to the actual labels.\n",
"\n",
"The `roc_auc` ranges between 0 and 1.0, and the closer the `roc_auc` is to 1.0, the better the model is at distinguishing between the classes.\n",
"\n",
"For more information on these metrics, you can read through the definitions on [precision and recall](https://developers.google.com/machine-learning/crash-course/classification/precision-and-recall), [accuracy](https://developers.google.com/machine-learning/crash-course/classification/accuracy), [f1-score](https://en.wikipedia.org/wiki/F-score), [log_loss](https://en.wikipedia.org/wiki/Loss_functions_for_classification#Logistic_loss) and [roc_auc](https://developers.google.com/machine-learning/crash-course/classification/roc-and-auc)."
@@ -1153,7 +1165,7 @@
"|Actual_0| True Negatives | False Positives|\n",
"|Actual_1| False Negatives | True Positives|\n",
"\n",
"For more information on confusion matrices, you can read through a detailed explanation [here](https://developers.google.com/machine-learning/crash-course/classification/true-false-positive-negative)."
"For more information on confusion matrices, see [Classification: True vs. False and Positive vs. Negative](https://developers.google.com/machine-learning/crash-course/classification/true-false-positive-negative)."
]
},
{
@@ -1207,7 +1219,7 @@
"id": "431ffebc5667"
},
"source": [
"You can run [`ML.PREDICT`](https://cloud.google.com/bigquery-ml/docs/reference/standard-sql/bigqueryml-syntax-predict) to make predictions on the propensity to churn. The following code returns all the information from `ML.PREDICT`."
"You can run [`ML.PREDICT`](https://cloud.google.com/bigquery-ml/docs/reference/standard-sql/bigqueryml-syntax-predict) to make predictions on the propensity to churn. The following code returns all of the information from `ML.PREDICT`."
]
},
{
@@ -1244,7 +1256,7 @@
"id": "fccf138adcfa"
},
"source": [
"For propensity modeling, the most important output is the probability of a behavior occuring. The following query returns the probability that the user will return after 24 hrs. The higher the probability and closer it is to 1, the more likely the user is predicted to churn, and the closer it is to 0, the more likely the user is predicted to return."
"For propensity modeling, the most important output is the probability of a behavior occuring. The following query returns the probability that the user will return after 24 hours. The higher the probability and closer it is to 1, the more likely the user is predicted to churn, and the closer it is to 0, the more likely the user is predicted to return."
]
},
{
@@ -1291,8 +1303,8 @@
"id": "1af4216bbb3d"
},
"source": [
"## Export predictions table to Google Cloud Storage\n",
"<a name=\"section-11\"></a>\n"
"## Export the predictions table to Cloud Storage\n",
"<a name=\"section-11\"></a>"
]
},
{
@@ -1301,7 +1313,7 @@
"id": "2839b839f440"
},
"source": [
"There are several ways to export the predictions table to Google Cloud Storage (GCS), so that you can use them in a separate service. Perhaps the easiest way is to export directly to GCS using SQL ([documentation](https://cloud.google.com/bigquery/docs/reference/standard-sql/other-statements#export_data_statement))."
"There are several ways to export the predictions table to Cloud Storage, so that you can use the information in a separate service. Perhaps the easiest way is to export directly to Cloud Storage using SQL. [Learn more about the EXPORT DATA statement](https://cloud.google.com/bigquery/docs/reference/standard-sql/other-statements#export_data_statement)."
]
},
{
@@ -1331,11 +1343,10 @@
"## Clean up\n",
"<a name=\"section-12\"></a>\n",
"\n",
"\n",
"To clean up all Google Cloud resources used in this project, you can [delete the Google Cloud\n",
"project](https://cloud.google.com/resource-manager/docs/creating-managing-projects#shutting_down_projects) you used for the tutorial.\n",
"\n",
"Otherwise, you can delete the individual resources you created in this tutorial(The following code deletes entire dataset).\n"
"Otherwise, you can delete the individual resources you created in this tutorial. The following code deletes the entire dataset."
]
},
{