diff --git a/linear_regression.ipynb b/linear_regression.ipynb
index fc072c3..379cb87 100644
--- a/linear_regression.ipynb
+++ b/linear_regression.ipynb
@@ -1,768 +1,528 @@
{
- "nbformat": 4,
- "nbformat_minor": 0,
- "metadata": {
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "2tZ3RLnlkrkg"
+ },
+ "source": [
+ "# Intro to Linear Regression with cuML\n",
+ "Corresponding notebook to [*Beginner’s Guide to Linear Regression in Python with cuML*](http://bit.ly/cuml_lin_reg_friend) story on Medium\n",
+ "\n",
+ "Linear Regression is a simple machine learning model where the response `y` is modelled by a linear combination of the predictors in `X`. The `LinearRegression` function implemented in the `cuML` library allows users to change the `fit_intercept`, `normalize`, and `algorithm` parameters. \n",
+ "\n",
+ "Here is a brief on RAPIDS' Linear Regression parameters:\n",
+ "\n",
+ "- `algorithm`: 'eig' or 'svd' (default = 'eig')\n",
+ " - `Eig` uses a eigendecomposition of the covariance matrix, and is much faster\n",
+ " - `SVD` is slower, but guaranteed to be stable\n",
+ "- `fit_intercept`: boolean (default = True)\n",
+ " - If `True`, `LinearRegresssion` tries to correct for the global mean of `y`\n",
+ " - If `False`, the model expects that you have centered the data.\n",
+ "- `normalize`: boolean (default = False)\n",
+ " - If True, the predictors in X will be normalized by dividing by it’s L2 norm\n",
+ " - If False, no scaling will be done\n",
+ "\n",
+ "Methods that can be used with `LinearRegression` are:\n",
+ "\n",
+ "- `fit`: Fit the model with `X` and `y`\n",
+ "- `get_params`: Sklearn style return parameter state\n",
+ "- `predict`: Predicts the `y` for `X`\n",
+ "- `set_params`: Sklearn style set parameter state to dictionary of params\n",
+ "\n",
+ "`cuML`'s `LinearRegression` expects expects either `cuDF` DataFrame or `NumPy` matrix inputs"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "N20le3_KlP3O"
+ },
+ "source": [
+ "## Load data\n",
+ "- for this demo, we will be utilizing the Boston housing dataset from `sklearn`\n",
+ " - start by loading in the set and printing a map of the contents"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
"colab": {
- "name": "LOCAL_intro_lin_reg_cuml",
- "provenance": [],
- "collapsed_sections": []
+ "base_uri": "https://localhost:8080/",
+ "height": 34
},
- "kernelspec": {
- "name": "python3",
- "display_name": "Python 3"
- },
- "accelerator": "GPU"
+ "colab_type": "code",
+ "id": "RFE-nxxlTajg",
+ "outputId": "04f89e88-61a3-4dd2-9088-123b410e508c"
+ },
+ "outputs": [],
+ "source": [
+ "from sklearn.datasets import load_boston\n",
+ "\n",
+ "# load Boston dataset\n",
+ "boston = load_boston()\n",
+ "\n",
+ "# let's see what's inside\n",
+ "print(boston.keys())"
+ ]
},
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "2tZ3RLnlkrkg",
- "colab_type": "text"
- },
- "source": [
- "# Intro to Linear Regression with cuML\n",
- "Corresponding notebook to [*Beginner’s Guide to Linear Regression in Python with cuML*](http://bit.ly/cuml_lin_reg_friend) story on Medium\n",
- "\n",
- "Linear Regression is a simple machine learning model where the response `y` is modelled by a linear combination of the predictors in `X`. The `LinearRegression` function implemented in the `cuML` library allows users to change the `fit_intercept`, `normalize`, and `algorithm` parameters. \n",
- "\n",
- "Here is a brief on RAPIDS' Linear Regression parameters:\n",
- "\n",
- "- `algorithm`: 'eig' or 'svd' (default = 'eig')\n",
- " - `Eig` uses a eigendecomposition of the covariance matrix, and is much faster\n",
- " - `SVD` is slower, but guaranteed to be stable\n",
- "- `fit_intercept`: boolean (default = True)\n",
- " - If `True`, `LinearRegresssion` tries to correct for the global mean of `y`\n",
- " - If `False`, the model expects that you have centered the data.\n",
- "- `normalize`: boolean (default = False)\n",
- " - If True, the predictors in X will be normalized by dividing by it’s L2 norm\n",
- " - If False, no scaling will be done\n",
- "\n",
- "Methods that can be used with `LinearRegression` are:\n",
- "\n",
- "- `fit`: Fit the model with `X` and `y`\n",
- "- `get_params`: Sklearn style return parameter state\n",
- "- `predict`: Predicts the `y` for `X`\n",
- "- `set_params`: Sklearn style set parameter state to dictionary of params\n",
- "\n",
- "`cuML`'s `LinearRegression` expects expects either `cuDF` DataFrame or `NumPy` matrix inputs\n",
- "\n"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "-tG6ezqKh1Z0",
- "colab_type": "text"
- },
- "source": [
- "Note: `CuPy` is not installed by default with RAPIDS `Conda` or `Docker` packages, but is needed for visualizing results in this notebook.\n",
- "- install with `pip` via the cell below "
- ]
- },
- {
- "cell_type": "code",
- "metadata": {
- "id": "pxBcXor_0-Jd",
- "colab_type": "code",
- "colab": {}
- },
- "source": [
- "# install cupy\n",
- "!pip install cupy"
- ],
- "execution_count": 0,
- "outputs": []
- },
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "N20le3_KlP3O",
- "colab_type": "text"
- },
- "source": [
- "## Load data\n",
- "- for this demo, we will be utilizing the Boston housing dataset from `sklearn`\n",
- " - start by loading in the set and printing a map of the contents"
- ]
- },
- {
- "cell_type": "code",
- "metadata": {
- "id": "RFE-nxxlTajg",
- "colab_type": "code",
- "outputId": "04f89e88-61a3-4dd2-9088-123b410e508c",
- "colab": {
- "base_uri": "https://localhost:8080/",
- "height": 34
- }
- },
- "source": [
- "from sklearn.datasets import load_boston\n",
- "\n",
- "# load Boston dataset\n",
- "boston = load_boston()\n",
- "\n",
- "# let's see what's inside\n",
- "print(boston.keys())"
- ],
- "execution_count": 0,
- "outputs": [
- {
- "output_type": "stream",
- "text": [
- "dict_keys(['data', 'target', 'feature_names', 'DESCR', 'filename'])\n"
- ],
- "name": "stdout"
- }
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "wmcO8dxO0uOB",
- "colab_type": "text"
- },
- "source": [
- "#### Boston house prices dataset\n",
- "- a description of the dataset is provided in `DESCR`\n",
- " - let's explore "
- ]
- },
- {
- "cell_type": "code",
- "metadata": {
- "id": "c3kLHAsP-Al2",
- "colab_type": "code",
- "outputId": "02518c3c-7767-42a7-b6f4-6756ace741cc",
- "colab": {
- "base_uri": "https://localhost:8080/",
- "height": 923
- }
- },
- "source": [
- "# what do we know about this dataset?\n",
- "print(boston.DESCR)"
- ],
- "execution_count": 0,
- "outputs": [
- {
- "output_type": "stream",
- "text": [
- ".. _boston_dataset:\n",
- "\n",
- "Boston house prices dataset\n",
- "---------------------------\n",
- "\n",
- "**Data Set Characteristics:** \n",
- "\n",
- " :Number of Instances: 506 \n",
- "\n",
- " :Number of Attributes: 13 numeric/categorical predictive. Median Value (attribute 14) is usually the target.\n",
- "\n",
- " :Attribute Information (in order):\n",
- " - CRIM per capita crime rate by town\n",
- " - ZN proportion of residential land zoned for lots over 25,000 sq.ft.\n",
- " - INDUS proportion of non-retail business acres per town\n",
- " - CHAS Charles River dummy variable (= 1 if tract bounds river; 0 otherwise)\n",
- " - NOX nitric oxides concentration (parts per 10 million)\n",
- " - RM average number of rooms per dwelling\n",
- " - AGE proportion of owner-occupied units built prior to 1940\n",
- " - DIS weighted distances to five Boston employment centres\n",
- " - RAD index of accessibility to radial highways\n",
- " - TAX full-value property-tax rate per $10,000\n",
- " - PTRATIO pupil-teacher ratio by town\n",
- " - B 1000(Bk - 0.63)^2 where Bk is the proportion of blacks by town\n",
- " - LSTAT % lower status of the population\n",
- " - MEDV Median value of owner-occupied homes in $1000's\n",
- "\n",
- " :Missing Attribute Values: None\n",
- "\n",
- " :Creator: Harrison, D. and Rubinfeld, D.L.\n",
- "\n",
- "This is a copy of UCI ML housing dataset.\n",
- "https://archive.ics.uci.edu/ml/machine-learning-databases/housing/\n",
- "\n",
- "\n",
- "This dataset was taken from the StatLib library which is maintained at Carnegie Mellon University.\n",
- "\n",
- "The Boston house-price data of Harrison, D. and Rubinfeld, D.L. 'Hedonic\n",
- "prices and the demand for clean air', J. Environ. Economics & Management,\n",
- "vol.5, 81-102, 1978. Used in Belsley, Kuh & Welsch, 'Regression diagnostics\n",
- "...', Wiley, 1980. N.B. Various transformations are used in the table on\n",
- "pages 244-261 of the latter.\n",
- "\n",
- "The Boston house-price data has been used in many machine learning papers that address regression\n",
- "problems. \n",
- " \n",
- ".. topic:: References\n",
- "\n",
- " - Belsley, Kuh & Welsch, 'Regression diagnostics: Identifying Influential Data and Sources of Collinearity', Wiley, 1980. 244-261.\n",
- " - Quinlan,R. (1993). Combining Instance-Based and Model-Based Learning. In Proceedings on the Tenth International Conference of Machine Learning, 236-243, University of Massachusetts, Amherst. Morgan Kaufmann.\n",
- "\n"
- ],
- "name": "stdout"
- }
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "wI_sB78vE297",
- "colab_type": "text"
- },
- "source": [
- "### Build Dataframe\n",
- "- Import `cuDF` and input the data into a DataFrame \n",
- " - Then add a `PRICE` column equal to the `target` key"
- ]
- },
- {
- "cell_type": "code",
- "metadata": {
- "id": "xiMmIZ8O5scJ",
- "colab_type": "code",
- "outputId": "fd09db1f-fb41-4494-bb8b-eab6e18c258f",
- "colab": {
- "base_uri": "https://localhost:8080/",
- "height": 206
- }
- },
- "source": [
- "import cudf\n",
- "\n",
- "# build dataframe from data key\n",
- "bos = cudf.DataFrame(list(boston.data))\n",
- "# set column names to feature_names\n",
- "bos.columns = boston.feature_names\n",
- "\n",
- "# add PRICE column from target\n",
- "bos['PRICE'] = boston.target\n",
- "\n",
- "# let's see what we're working with\n",
- "bos.head()"
- ],
- "execution_count": 0,
- "outputs": [
- {
- "output_type": "execute_result",
- "data": {
- "text/html": [
- "
\n",
- "\n",
- "
\n",
- " \n",
- "
\n",
- "
\n",
- "
CRIM
\n",
- "
ZN
\n",
- "
INDUS
\n",
- "
CHAS
\n",
- "
NOX
\n",
- "
RM
\n",
- "
AGE
\n",
- "
DIS
\n",
- "
RAD
\n",
- "
TAX
\n",
- "
PTRATIO
\n",
- "
B
\n",
- "
LSTAT
\n",
- "
PRICE
\n",
- "
\n",
- " \n",
- " \n",
- "
\n",
- "
0
\n",
- "
0.00632
\n",
- "
18.0
\n",
- "
2.31
\n",
- "
0.0
\n",
- "
0.538
\n",
- "
6.575
\n",
- "
65.2
\n",
- "
4.0900
\n",
- "
1.0
\n",
- "
296.0
\n",
- "
15.3
\n",
- "
396.90
\n",
- "
4.98
\n",
- "
24.0
\n",
- "
\n",
- "
\n",
- "
1
\n",
- "
0.02731
\n",
- "
0.0
\n",
- "
7.07
\n",
- "
0.0
\n",
- "
0.469
\n",
- "
6.421
\n",
- "
78.9
\n",
- "
4.9671
\n",
- "
2.0
\n",
- "
242.0
\n",
- "
17.8
\n",
- "
396.90
\n",
- "
9.14
\n",
- "
21.6
\n",
- "
\n",
- "
\n",
- "
2
\n",
- "
0.02729
\n",
- "
0.0
\n",
- "
7.07
\n",
- "
0.0
\n",
- "
0.469
\n",
- "
7.185
\n",
- "
61.1
\n",
- "
4.9671
\n",
- "
2.0
\n",
- "
242.0
\n",
- "
17.8
\n",
- "
392.83
\n",
- "
4.03
\n",
- "
34.7
\n",
- "
\n",
- "
\n",
- "
3
\n",
- "
0.03237
\n",
- "
0.0
\n",
- "
2.18
\n",
- "
0.0
\n",
- "
0.458
\n",
- "
6.998
\n",
- "
45.8
\n",
- "
6.0622
\n",
- "
3.0
\n",
- "
222.0
\n",
- "
18.7
\n",
- "
394.63
\n",
- "
2.94
\n",
- "
33.4
\n",
- "
\n",
- "
\n",
- "
4
\n",
- "
0.06905
\n",
- "
0.0
\n",
- "
2.18
\n",
- "
0.0
\n",
- "
0.458
\n",
- "
7.147
\n",
- "
54.2
\n",
- "
6.0622
\n",
- "
3.0
\n",
- "
222.0
\n",
- "
18.7
\n",
- "
396.90
\n",
- "
5.33
\n",
- "
36.2
\n",
- "
\n",
- " \n",
- "
\n",
- "
"
- ],
- "text/plain": [
- " CRIM ZN INDUS CHAS NOX ... TAX PTRATIO B LSTAT PRICE\n",
- "0 0.00632 18.0 2.31 0.0 0.538 ... 296.0 15.3 396.90 4.98 24.0\n",
- "1 0.02731 0.0 7.07 0.0 0.469 ... 242.0 17.8 396.90 9.14 21.6\n",
- "2 0.02729 0.0 7.07 0.0 0.469 ... 242.0 17.8 392.83 4.03 34.7\n",
- "3 0.03237 0.0 2.18 0.0 0.458 ... 222.0 18.7 394.63 2.94 33.4\n",
- "4 0.06905 0.0 2.18 0.0 0.458 ... 222.0 18.7 396.90 5.33 36.2\n",
- "\n",
- "[5 rows x 14 columns]"
- ]
- },
- "metadata": {
- "tags": []
- },
- "execution_count": 5
- }
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "r2qrTxo4ljZp",
- "colab_type": "text"
- },
- "source": [
- "### Split Train from Test\n",
- "- For basic Linear Regression, we will predict `PRICE` (Median value of owner-occupied homes) based on `TAX` (full-value property-tax rate per $10,000)\n",
- " - Go ahead and trim data to just these columns"
- ]
- },
- {
- "cell_type": "code",
- "metadata": {
- "id": "spaDB10E3okF",
- "colab_type": "code",
- "colab": {}
- },
- "source": [
- "# simple linear regression X and Y\n",
- "X = bos['TAX']\n",
- "Y = bos['PRICE']"
- ],
- "execution_count": 0,
- "outputs": []
- },
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "4TKLv8FjIBuI",
- "colab_type": "text"
- },
- "source": [
- "We can now set training and testing sets for our model\n",
- "- Use `cuML`'s `train_test_split` to do this\n",
- " - Train on 70% of data\n",
- " - Test on 30% of data"
- ]
- },
- {
- "cell_type": "code",
- "metadata": {
- "id": "1DC6FHsNIKH_",
- "colab_type": "code",
- "outputId": "4c932268-7a82-4ac3-c7b9-9966ffc2b12e",
- "colab": {
- "base_uri": "https://localhost:8080/",
- "height": 86
- }
- },
- "source": [
- "from cuml.preprocessing.model_selection import train_test_split\n",
- "\n",
- "# train/test split (70:30)\n",
- "sX_train, sX_test, sY_train, sY_test = train_test_split(X, Y, train_size = 0.7)\n",
- "\n",
- "# see what it looks like\n",
- "print(sX_train.shape)\n",
- "print(sX_test.shape)\n",
- "print(sY_train.shape)\n",
- "print(sY_test.shape)"
- ],
- "execution_count": 0,
- "outputs": [
- {
- "output_type": "stream",
- "text": [
- "(354,)\n",
- "(152,)\n",
- "(354,)\n",
- "(152,)\n"
- ],
- "name": "stdout"
- }
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "ZLVg44gAmJG7",
- "colab_type": "text"
- },
- "source": [
- "### Predict Values\n",
- "1. fit the model with `TAX` (*X_train*) and corresponding `PRICE` (*y_train*) values \n",
- " - so it can build an understanding of their relationship \n",
- "2. predict `PRICE` (*y_test*) for a test set of `TAX` (*X_test*) values\n",
- " - and compare `PRICE` predictions to actual median house (*y_test*) values\n",
- " - use `sklearn`'s `mean_squared_error` to do this"
- ]
- },
- {
- "cell_type": "code",
- "metadata": {
- "id": "ZGMPloJxGtK3",
- "colab_type": "code",
- "outputId": "664b54fe-16d5-4140-a657-3dc782574da9",
- "colab": {
- "base_uri": "https://localhost:8080/",
- "height": 34
- }
- },
- "source": [
- "from cuml import LinearRegression\n",
- "from sklearn.metrics import mean_squared_error\n",
- "\n",
- "# call Linear Regression model\n",
- "slr = LinearRegression()\n",
- "\n",
- "# train the model\n",
- "slr.fit(sX_train, sY_train)\n",
- "\n",
- "# make predictions for test X values\n",
- "sY_pred = slr.predict(sX_test)\n",
- "\n",
- "# calculate error\n",
- "mse = mean_squared_error(sY_test, sY_pred)\n",
- "print(mse)"
- ],
- "execution_count": 0,
- "outputs": [
- {
- "output_type": "stream",
- "text": [
- "54.32312606491228\n"
- ],
- "name": "stdout"
- }
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "T7BXjkPSGwqd",
- "colab_type": "text"
- },
- "source": [
- "3. visualize prediction accuracy with `matplotlib`"
- ]
- },
- {
- "cell_type": "code",
- "metadata": {
- "id": "pp9RNPt_Iemk",
- "colab_type": "code",
- "outputId": "22a22472-50ad-4bb3-d104-35e9e100b8b6",
- "colab": {
- "base_uri": "https://localhost:8080/",
- "height": 305
- }
- },
- "source": [
- "import cupy\n",
- "import matplotlib.pyplot as plt\n",
- "\n",
- "# scatter actual and predicted results\n",
- "plt.scatter(sY_test, sY_pred)\n",
- "\n",
- "# label graph\n",
- "plt.xlabel(\"Actual Prices: $Y_i$\")\n",
- "plt.ylabel(\"Predicted prices: $\\hat{Y}_i$\")\n",
- "plt.title(\"Prices vs Predicted prices: $Y_i$ vs $\\hat{Y}_i$\")\n",
- "\n",
- "plt.show()"
- ],
- "execution_count": 0,
- "outputs": [
- {
- "output_type": "display_data",
- "data": {
- "image/png": "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\ni6cKUGWQlQAAAABJRU5ErkJggg==\n",
- "text/plain": [
- ""
- ]
- },
- "metadata": {
- "tags": []
- }
- }
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "8MqX73B4s5tv",
- "colab_type": "text"
- },
- "source": [
- "## Multiple Linear Regression \n",
- "- Our mean squared error for Simple Linear Regression looks kinda high..\n",
- " - Let's try Multiple Linear Regression (predicting based on multiple variables rather than just `TAX`) and see if that produces more accurate predictions\n",
- "\n",
- "1. Set X to contain all values that are not `PRICE` from the unsplit data\n",
- " - i.e. `CRIM`, `ZN`, `INDUS`, `CHAS`, `NOX`, `RM`, `AGE`, `DIS`, `RAD`, `TAX`, `PTRATIO`, `B`, `LSTAT`\n",
- " - Y to still represent just 1 target value (`PRICE`)\n",
- " - also from the unsplit data\n"
- ]
- },
- {
- "cell_type": "code",
- "metadata": {
- "id": "ZtQK5-f4M0Vg",
- "colab_type": "code",
- "colab": {}
- },
- "source": [
- "# set X to all variables except price\n",
- "mX = bos.drop('PRICE', axis=1)\n",
- "# and, like in the simple Linear Regression, set Y to price\n",
- "mY = bos['PRICE']"
- ],
- "execution_count": 0,
- "outputs": []
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "wmcO8dxO0uOB"
+ },
+ "source": [
+ "#### Boston house prices dataset\n",
+ "- a description of the dataset is provided in `DESCR`\n",
+ " - let's explore "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 923
},
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "RTYG4-UwNDsK",
- "colab_type": "text"
- },
- "source": [
- "2. Split the data into `multi_X_train`, `multi_X_test`, `Y_train`, and `Y_test`\n",
- " - Use `cuML`'s `train_test_split`\n",
- " - And the same 70:30 train:test ratio"
- ]
+ "colab_type": "code",
+ "id": "c3kLHAsP-Al2",
+ "outputId": "02518c3c-7767-42a7-b6f4-6756ace741cc"
+ },
+ "outputs": [],
+ "source": [
+ "# what do we know about this dataset?\n",
+ "print(boston.DESCR)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "wI_sB78vE297"
+ },
+ "source": [
+ "### Build Dataframe\n",
+ "- Import `cuDF` and input the data into a DataFrame \n",
+ " - Then add a `PRICE` column equal to the `target` key"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 206
},
- {
- "cell_type": "code",
- "metadata": {
- "id": "EsKxK8u_F7t8",
- "colab_type": "code",
- "outputId": "673a1a44-4d2f-4a45-8333-8f29782eaf65",
- "colab": {
- "base_uri": "https://localhost:8080/",
- "height": 86
- }
- },
- "source": [
- "# train/test split (70:30)\n",
- "mX_train, mX_test, mY_train, mY_test = train_test_split(mX, mY, train_size = 0.7)\n",
- "\n",
- "# see what it looks like\n",
- "print(mX_train.shape)\n",
- "print(mX_test.shape)\n",
- "print(mY_train.shape)\n",
- "print(mY_test.shape)"
- ],
- "execution_count": 0,
- "outputs": [
- {
- "output_type": "stream",
- "text": [
- "(354, 13)\n",
- "(152, 13)\n",
- "(354,)\n",
- "(152,)\n"
- ],
- "name": "stdout"
- }
- ]
+ "colab_type": "code",
+ "id": "xiMmIZ8O5scJ",
+ "outputId": "fd09db1f-fb41-4494-bb8b-eab6e18c258f"
+ },
+ "outputs": [],
+ "source": [
+ "import cudf\n",
+ "\n",
+ "# build dataframe from data key\n",
+ "bos = cudf.DataFrame(list(boston.data))\n",
+ "# set column names to feature_names\n",
+ "bos.columns = boston.feature_names\n",
+ "\n",
+ "# add PRICE column from target\n",
+ "bos['PRICE'] = boston.target\n",
+ "\n",
+ "# let's see what we're working with\n",
+ "bos.head()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "r2qrTxo4ljZp"
+ },
+ "source": [
+ "### Split Train from Test\n",
+ "- For basic Linear Regression, we will predict `PRICE` (Median value of owner-occupied homes) based on `TAX` (full-value property-tax rate per $10,000)\n",
+ " - Go ahead and trim data to just these columns"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "colab": {},
+ "colab_type": "code",
+ "id": "spaDB10E3okF"
+ },
+ "outputs": [],
+ "source": [
+ "# simple linear regression X and Y\n",
+ "X = bos['TAX']\n",
+ "Y = bos['PRICE']"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "4TKLv8FjIBuI"
+ },
+ "source": [
+ "We can now set training and testing sets for our model\n",
+ "- Use `cuML`'s `train_test_split` to do this\n",
+ " - Train on 70% of data\n",
+ " - Test on 30% of data"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 86
},
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "_Y40R17LGHsI",
- "colab_type": "text"
- },
- "source": [
- "3. fit the model with `multi_X_train` and corresponding `PRICE` (*y_train*) values \n",
- " - so it can build an understanding of their relationships \n",
- "4. predict `PRICE` (*y_test*) for the test set of independent (*multi_X_test*) values\n",
- " - and compare `PRICE` predictions to actual median house (*y_test*) values\n",
- " - use `sklearn`'s `mean_squared_error` to do this"
- ]
+ "colab_type": "code",
+ "id": "1DC6FHsNIKH_",
+ "outputId": "4c932268-7a82-4ac3-c7b9-9966ffc2b12e"
+ },
+ "outputs": [],
+ "source": [
+ "from cuml.preprocessing.model_selection import train_test_split\n",
+ "\n",
+ "# train/test split (70:30)\n",
+ "sX_train, sX_test, sY_train, sY_test = train_test_split(X, Y, train_size=0.7)\n",
+ "\n",
+ "# see what it looks like\n",
+ "print(sX_train.shape)\n",
+ "print(sX_test.shape)\n",
+ "print(sY_train.shape)\n",
+ "print(sY_test.shape)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "ZLVg44gAmJG7"
+ },
+ "source": [
+ "### Predict Values\n",
+ "1. fit the model with `TAX` (*X_train*) and corresponding `PRICE` (*y_train*) values \n",
+ " - so it can build an understanding of their relationship \n",
+ "2. predict `PRICE` (*y_test*) for a test set of `TAX` (*X_test*) values\n",
+ " - and compare `PRICE` predictions to actual median house (*y_test*) values\n",
+ " - use `sklearn`'s `mean_squared_error` to do this"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from cuml import LinearRegression\n",
+ "\n",
+ "# call Linear Regression model\n",
+ "slr = LinearRegression()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# train the model\n",
+ "slr.fit(sX_train, sY_train)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# make predictions for test X values\n",
+ "sY_pred = slr.predict(sX_test)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from cuml.metrics import mean_squared_error\n",
+ "\n",
+ "# calculate error\n",
+ "mse = mean_squared_error(sY_test, sY_pred)\n",
+ "\n",
+ "print(f'Mean Squared Error: {mse}')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "T7BXjkPSGwqd"
+ },
+ "source": [
+ "3. visualize prediction accuracy with `matplotlib`"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 305
},
- {
- "cell_type": "code",
- "metadata": {
- "id": "N7qm1HuVO-1k",
- "colab_type": "code",
- "outputId": "7e291cec-e602-4ad9-a5b3-b70d7261f63d",
- "colab": {
- "base_uri": "https://localhost:8080/",
- "height": 34
- }
- },
- "source": [
- "# call Linear Regression model\n",
- "mlr = LinearRegression()\n",
- "\n",
- "# train the model for multiple regression\n",
- "mlr.fit(mX_train, mY_train)\n",
- "\n",
- "# make predictions for test X values\n",
- "mY_pred = mlr.predict(mX_test)\n",
- "\n",
- "# calculate error\n",
- "mmse = mean_squared_error(mY_test, mY_pred)\n",
- "print(mmse)"
- ],
- "execution_count": 0,
- "outputs": [
- {
- "output_type": "stream",
- "text": [
- "16.691811854229723\n"
- ],
- "name": "stdout"
- }
- ]
+ "colab_type": "code",
+ "id": "pp9RNPt_Iemk",
+ "outputId": "22a22472-50ad-4bb3-d104-35e9e100b8b6"
+ },
+ "outputs": [],
+ "source": [
+ "import matplotlib.pyplot as plt\n",
+ "\n",
+ "# scatter actual and predicted results\n",
+ "plt.scatter(sY_test.tolist(), sY_pred.tolist())\n",
+ "\n",
+ "# label graph\n",
+ "plt.xlabel(\"Actual Prices: $Y_i$\")\n",
+ "plt.ylabel(\"Predicted prices: $\\hat{Y}_i$\")\n",
+ "plt.title(\"Prices vs Predicted prices: $Y_i$ vs $\\hat{Y}_i$\")\n",
+ "\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "8MqX73B4s5tv"
+ },
+ "source": [
+ "## Multiple Linear Regression \n",
+ "- Our mean squared error for Simple Linear Regression looks kinda high..\n",
+ " - Let's try Multiple Linear Regression (predicting based on multiple variables rather than just `TAX`) and see if that produces more accurate predictions\n",
+ "\n",
+ "1. Set X to contain all values that are not `PRICE` from the unsplit data\n",
+ " - i.e. `CRIM`, `ZN`, `INDUS`, `CHAS`, `NOX`, `RM`, `AGE`, `DIS`, `RAD`, `TAX`, `PTRATIO`, `B`, `LSTAT`\n",
+ " - Y to still represent just 1 target value (`PRICE`)\n",
+ " - also from the unsplit data\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "colab": {},
+ "colab_type": "code",
+ "id": "ZtQK5-f4M0Vg"
+ },
+ "outputs": [],
+ "source": [
+ "# set X to all variables except price\n",
+ "mX = bos.drop('PRICE', axis=1)\n",
+ "# and, like in the simple Linear Regression, set Y to price\n",
+ "mY = bos['PRICE']"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "RTYG4-UwNDsK"
+ },
+ "source": [
+ "2. Split the data into `multi_X_train`, `multi_X_test`, `Y_train`, and `Y_test`\n",
+ " - Use `cuML`'s `train_test_split`\n",
+ " - And the same 70:30 train:test ratio"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 86
},
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "jTdmleXCM_Xb",
- "colab_type": "text"
- },
- "source": [
- "5. visualize with `matplotlib`"
- ]
+ "colab_type": "code",
+ "id": "EsKxK8u_F7t8",
+ "outputId": "673a1a44-4d2f-4a45-8333-8f29782eaf65"
+ },
+ "outputs": [],
+ "source": [
+ "# train/test split (70:30)\n",
+ "mX_train, mX_test, mY_train, mY_test = train_test_split(mX, mY, train_size=0.7)\n",
+ "\n",
+ "# see what it looks like\n",
+ "print(mX_train.shape)\n",
+ "print(mX_test.shape)\n",
+ "print(mY_train.shape)\n",
+ "print(mY_test.shape)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "_Y40R17LGHsI"
+ },
+ "source": [
+ "3. fit the model with `multi_X_train` and corresponding `PRICE` (*y_train*) values \n",
+ " - so it can build an understanding of their relationships \n",
+ "4. predict `PRICE` (*y_test*) for the test set of independent (*multi_X_test*) values\n",
+ " - and compare `PRICE` predictions to actual median house (*y_test*) values\n",
+ " - use `sklearn`'s `mean_squared_error` to do this"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 34
},
- {
- "cell_type": "code",
- "metadata": {
- "id": "Q83NFMK1JKvL",
- "colab_type": "code",
- "outputId": "569cfa77-a66e-4b1b-9d70-ae4ef8e7936e",
- "colab": {
- "base_uri": "https://localhost:8080/",
- "height": 305
- }
- },
- "source": [
- "# scatter actual and predicted results\n",
- "plt.scatter(mY_test, mY_pred)\n",
- "\n",
- "# label graph\n",
- "plt.xlabel(\"Actual Prices: $Y_i$\")\n",
- "plt.ylabel(\"Predicted prices: $\\hat{Y}_i$\")\n",
- "plt.title(\"Prices vs Predicted prices: $Y_i$ vs $\\hat{Y}_i$\")\n",
- "\n",
- "plt.show()"
- ],
- "execution_count": 0,
- "outputs": [
- {
- "output_type": "display_data",
- "data": {
- "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYoAAAEgCAYAAACq+TSYAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4zLCBo\ndHRwOi8vbWF0cGxvdGxpYi5vcmcvnQurowAAIABJREFUeJzt3X20HXV97/H3J4cTOCBygkYqAYxP\nCyQiCeJTQ7skSqMimiKKXLXc1tbV1q4K0tRwLy1I5RJXqlivWsuqtqBYAwKRVitYE66KRZuYQIhA\nfUDQg0JUjoIc4CT53j/27GRnZ8/sPbNnP39ea5119syeM/Pbc86Z78zv4ftTRGBmZpZmTq8LYGZm\n/c2BwszMMjlQmJlZJgcKMzPL5EBhZmaZHCjMzCyTA4WZmWVyoDCzoSTpNZJe0+tyDAN5wJ2ZDRtJ\nTwVuShZPiYif97I8g86BwsyGjqSPAtcDY8DrIuKdPS7SQHOgMDOzTG6jMDOzTA4UI07SNkkv73U5\n+oWkf5b0vuR1V85N7TFL2p9/p1YqB4ohI+mHkmYkPSLpgeQi9KS07SNiUUTc3MUitiXv52tHq+cm\nKdMrO1GGInr5O5U0T9LD9YFK0qckXSdJw3jsYedAMZxOi4gnAScAJwIX1G8gab+ul6o8w/75CumH\nzxwRDwGXA+dU10n6K+B5wFujg42ivTz2sHOgGGIRMQX8O/B82H3n+x5JtwO/lrRf7d2wpCOTO6/t\nkn4u6SPVfUk6XNK1yXv3SPrzmvfeI2kquZu7W9Ir6suSbPO5unV/J+nDre6j4OdLLXfyM0skfTs5\n7lrggJr39npSaHR+JH0KOAr41+Qp5y9bOF+px2wkKcf5kr4j6SFJ/yTpgIzP3LTczcpY9HeS+CCw\nXNKzJL0ReAeVnkePZnzGsv4+ch/bWhAR/hqiL+CHwCuT10cC24C/qXlvS7J+onZ7Kt0IbwMuAw6i\ncvE6KdlmDrAJ+GtgLvAs4AfAcuBo4EfA4cm2C4FnNyjXM4BHgYOT5THgJ8BLW91H3s+XVe5k+7nA\nvcC5wDhwBjALvK/BsbLOz+7tWjhfmcfM+Mx3JJ/rUOCWujI2/J1mlbuFc5P6OwE+Bnysyd/hJ4Ev\nAduBE1r4uy3l76PIsf3VwnWl1wXwV8m/0MpF4hFgOrkgfazuAvIHDbZ/JfCy5B9rvwb7fAlwX926\n84F/Ap4DPJjsY7xJ2b4O/F7y+hTg+8nrPPto+fNllTt5/dvA/STdxJN136BxoMg6P7u3a+F8ZR4z\n4zP/cc3ya2rOXervNKvcLZybln8nKWV+PhDAm+rW/xnw3E79fRQ9tr+yv3pep2kdsSIi/iPlvR+l\nrD8SuDcidjR47xnA4ZKma9aNAV+LiO9JOge4CFgk6Ubg3RFxf4P9fAY4C7gS+B/JMjn3kefzpZY7\neX04MBXJVSRxb8p+s85Pvazj5jlmrdrPdW+yn0bv1Usrd+a5KfA7qTcXeBy4rnZlRHyk8eZAeX8f\nRY5tGdxGMXrSGvR+BByV0iD6I+CeiJis+To4Il4DEBGfiYiTqFx8Anh/yjGuAV4u6Qjgd0kuBDn3\n0Uzt58ssN5WqjQV1vWGOStlv1vmpP6dZx81zzFpH1m1fe5HMaqRNK3ezc9Pu7+R44I76ACXp5oyf\nKevvo8ixLYMDhVV9i8pFbLWkgyQdIGlpzXsPJw2KE5LGJD1f0oskHS1pmaT9gceAGWBXowNExHbg\nZipVMPdExJ0AefZR4DM1LHfy/n8CO4A/lzQu6XTgxRn7Sjs/D1Cp42/luHmOWeudko6QdCjwv4G1\nOc5Bo3JnnpsSfieLqbSd7KZK/qUH036gxL+P3Me2bA4UBkBE7AROo1IffB/wY+DMmvdeS+Uf8B7g\nZ8A/AocA+wOrk3U/BZ5Gpa47zWeo1DV/pmZd3n3k+Uxp5SYingBOB/4n8Asqn/e6jH01PD/ApcAF\nkqYl/UXWcfMcs85nqCS5+wHwfaClAXpp5W52bsj4nUj6uKSPNzn08dRdrIEXAFub/FwZfx9Fj20p\nnOvJrM9J+iHwhxntMgMhaWf4YUSsG6VjDwM/UZhZtxwH3D6Cxx547vVkZl0REW8fxWMPA1c9mZlZ\nJlc9mZlZJgcKMzPLNBRtFE996lNj4cKFvS6GmdlA2bRp088iYn6z7YYiUCxcuJCNGzf2uhhmZgNF\nUivpY1z1ZGZm2RwozMwskwOFmZllcqAwM7NMDhRmZpZpKHo9mZn1g3Wbp1hz493cPz3D4ZMTrFx+\nNCuWLOjIfso6ViscKMzMSrBu8xTnX7eVmdmdAExNz3D+dZXM5nku4K3sp6xjtarnVU/JhCmbJf1b\nsvxMSd+U9D1JayXN7XUZzcyaWXPj3bsv3FUzsztZc+Pdpe+nrGO1queBAngXcGfN8vuByyLiOcBD\ngLM+mlnfu396Jtf6dvZT1rFa1dNAkcyNeyqVmbVI5hFeBnwu2eQKYEVvSmdm1rrDJydyrW9nP2Ud\nq1W9fqL4EPCX7Jn/9inAdM2k6D8GGla4SXqHpI2SNm7fvr3zJTUzy7By+dFMjI/ttW5ifIyVy48u\nfT9lHatVPQsUkl4LPBgRm4r8fERcHhEnRsSJ8+c3zWllZtZRK5Ys4NLTj2PB5AQCFkxOcOnpx+Vu\nXG5lP2Udq1U9m7hI0qXA24AdwAHAk4HrgeXAb0TEDkkvAy6KiOVZ+zrxxBPDSQHNzPKRtCkiTmy2\nXc+eKCLi/Ig4IiIWAm8G1kfEW4ANwBnJZmcDn+9REc3MjN63UTTyHuDdkr5Hpc3iEz0uj5nZSOuL\nAXcRcTNwc/L6B8CLe1keMzPboy8ChZlZv+tmyox+40BhZtZEt1Nm9Jt+bKMwM+sr3U6Z0W8cKMzM\nmuh2yox+40BhZtZEt1Nm9Bu3UZhZYaPSwLty+dF7tVFAZ1NmtMLzUZhZ3xulBt7q5+mXoNjtc+9A\nYTbEOnnXmdXAO2yBAioX4H75XN0+926jMBtS1bvOqekZgj13nes2T5Wy/7SG3KnpGZauXl/acWxf\nIzUfhZl1Tqe7dGY15JYdlGxvozYfhZllWLd5iqWr1/PMVV/IfZfe7I6/yD5rNZoTodYojTPotm7P\nR+E2CrM+1W6D5eGTE0w1CBZK9lVkn7VqG3gbHQdGZ5xBt3W7cb1n81GUyfNR2DBaunp9wwvwgskJ\nblm1rOnP1wcaqASJRv/xre6zU2W13uj7+SjMLFu7DZaNZkFLuy1s986/21Uh1l2uejLrU2lVR3ka\nLGu7dK7bPMW5a7c0DBbtNoL22ziDfjEsAxIdKMz6VNmjgdfceHfDIKHkWO3qp3EG/WCYBiQ6UJj1\nqbLv0tOql4LsC1e7d8XDcled1zANSHSgMOtjZd6lp1VlLciodlq3eYqV19zG7K7Ks8jU9Awrr7lt\nd9maGaa76ryGKeOsG7PNRkSRBueLbti2O0hUze4KLrphW0vHHOV5HIYp46yfKMyGQCvVO0WqsqZn\nZnOtrzdMd9V5dTrjrLPHmlnLGlXvnLt2C+es3cKCugtItxucy+i5Nag62RPM2WPNLJdG1TvVyqJ2\nLyDzDhznoUf3fXqYd+D47tdZd7b9OI9DN3UqMDt7rJnl0qwap502gQtPW8T4mPZaNz4mLjxtEdA8\nQ22jQX+Xnn7c0Ddkd1q3q/T8RGE24NKqd2oVvYA0qz5Ju7M97+o9PaM8vqJ83a7Sc6AwG3CNqnfq\ntXMBybrQpwWgnREj0w22F7pdpedAYdZj7fZeqc/iWp/4r5MXkKynmUEdXDYInD22AGePtUHVKMPr\nxPhYW/X43ew22aj8tQTcs/rUjhzb2tdq9lg/UZj1ULMBaUUu+N1sE6ge57yrb2Nng5vOUegGOwoc\nKMx6KGsWurR+8tBfWVqrxx7lbrDDzoHCrIcOmRhvOMpZ0PBJ46IbtvH4jl19lzvJacaHmwOFjZR+\ny2QqNV6f1nLYKKj0S6Oxu8EOLwcKGxn9mMl0usGo5yJGIXeS9Y5HZtvIyJPJdN3mKZauXs8zV32B\npavX7x5pXLa0xt55B443zPRamzqjlf2YlcFPFDbUaquaWp0vuptPHmkDp6opMuqrycCNxtZ9PQsU\nkg4Avgrsn5TjcxFxoaRnAp8FngJsAt4WEU/0qpw2uJr18a+qvxvvZsK1Zo3AacfL286ybvMUF92w\nbXcbx7wDx7nwtEVuU7CW9PKJ4nFgWUQ8Imkc+LqkfwfeDVwWEZ+V9HHg7cDf97CcNqAaXfDrNbob\n73bCtbyNwHm3r5+lDuChR2dZ+bnWZ6qz0dazNoqoeCRZHE++AlgGfC5ZfwWwogfFsyGQdWEXlbvq\n/febw7lrt+zVDjFMM5NBJWDWz1IHMLszRmKmOWtfTxuzJY1J2gI8CHwZ+D4wHRE7kk1+DPh2xwpJ\nu7AvmJzgsjMX89jsLqZnZvdJj11kytB+lhUw3VvKWtHTQBEROyNiMXAE8GLgmFZ/VtI7JG2UtHH7\n9u0dK6MNrqwLfrN2iGGaQyHrSWhQn5Ksu/qi11NETEvaALwMmJS0X/JUcQTQsF9iRFwOXA6VpIBd\nK6wNlAPG5+wOCJMT41z0ukoD7rlrtzTcvnqHPUyDx1YuP3qfNgqoTEA0qE9J1l09e6KQNF/SZPJ6\nAjgFuBPYAJyRbHY28PnelNAGWbXHU+00no/v2LX7ddqddEBHx01Uy9aNMRpVK5YsYM0bj2dyYs8Y\njHkHjrPmjOOHJhhaZ/UszbikF1BprB6jErCujoiLJT2LSvfYQ4HNwFsj4vGsfTnNuNVbunp9w3kS\nFkxOcMuqZU27zrab6jtNJ9KKmxXV92nGI+J2YEmD9T+g0l5hVlizLq71k/3U69S4iW6O0TAri1N4\n2FBqpYvriiULuGXVMlLy8nWkR1C3x2iYlcGBwoZSsy6ute0Ec1JSuHaiR9CwjdGw0dB21ZOki5P9\nbAG2RMR/t10qs0SetOD1277hhQvYcNf2fX62vp2g0cxsnRo3kZbbyb2PrJ/lChSS3hoRn65dFxF/\nLekwYDHwu5KeExF/VGYhbTTlSc7XaNtrN001bCROS+0xJrEroq15KpoFNk/wY4Mo7xPF2yS9CHh3\nROz+T4uIB4Abky+zUuRp+E3b9ryr981nlNYesCuCe1afWri8rQa2YRqjYaMhs41C0iJJV9WsejUw\nA6yXNL+jJbORl6fhN23bnRGcf91WLli3teNtEnnmuzAbJM2eKP6DymhpACJiF7BK0unA1yR9kErb\nxB0R8Wjnimmj6PDJiYZdVxtd0NPmnobKxfqqW+/bPR9Fp9ok3KPJhlWzXk+/A1xSu0LSa4E/BJ4A\nTgD+FviRpO91pIQ2svIk50ube7oqa1ipgDe8sP3qIPdosmGV+UQREVuBt1SXJd0DfIfKfBFfrt1W\n0hEdKaGNrOqF+73/um13Ko7992t8b9PO3NMBbLirklgyTy+reu7RZMMqb2P2qyPirkZvRMSPSyiP\n2T4em92To2l6ZnZ3AzHs6T00R2pYpQSVJ4ZmiWrun55pewpU92iyYdWzXE9lcq6n4ZWWs2lyYpzH\nd+xqOoPd5MQ4iw4/mFu+/4vM7RYk1UONjjUm8YE3OYGeDZ++z/Vko6VolU5aQ3Baw3X9WAhg95Sf\nWU4+Zj5X3Xpfw/eqPaeg8fgNP0HYsHMKD+u4apXO1PTMPrPJNZO3Ibg6FuKWVcsAOO/q25jd2fyp\necNd2zOP1aibazufy2yQOFBYx7UzviCt59O8A8cbbl+92Fcv4mntFvWmpmcaVjvVqn+68bgJGxWF\nq54k/UZE/DRt2ayqnfEFaQ3EQGYPo7Q0He2of+LI+7lcTWWDqp02ik8Ap2YsmwH5Bs41kpXyIu3C\nW/Ygt/E5+04bmvW56oPCycfM59pNU4V7VJn1UuGqp4g4NWvZrKpR9RHArx/f0VZ9fnU+icvOXAzA\nOWu38Ozzv8jCjDQdhTXYXVq12MnHzN+n7eKqW+9zNZUNrEKBQtIbJR2cvL5A0nWS9pmtzgwqF/RL\nTz9un3aF6ZlZzlm7hSUX31Q4YNQ2KMOe9BxpaTo+dObi1ImKsszujH0u6tXPtWByAlHpYnvp6cex\n4a7t+wSFtJYSp/ewQVD0ieKvIuJhSScBr6RS7fTx8oplw2bFkgUcOLdxTedDj84W7i3UrC1iTNrr\nIr5iyYLCKTUaXdSrTzXVnlYrlizIdfF3eg8bBEUDRfU/81Tg8oj4AjC3nCLZsMq6gBathml2Ud4Z\nwWVnLt59EYf0qrBm6i/qtbPkLV29fnegS7v41z/JOL2HDYqijdlTkv6BStLA90vaH3e1tSbSGn+r\nWrkTr28kzsoaW1XfaFzfk2rywHEeeWwHs7vSu9LWX9Sz0n2k5XxKm3HPrN8VDRRvAl4F/G1ETEt6\nOrCyvGLZMGp0Aa2VdideDQ5T0zN75W1qNu6hqtFkR7U9qZauXr876WCtrBnvssZQVAf7uSusDYui\ngWIGOAg4C7gYGAemyyqUDafqhfKiG7bt8xSQVg1Tf+deNDNZ1tNKkRnvmo2h8Cx2NkyKBoqPAbuA\nZVQCxcPAtcCLSiqXDZhWB5NVL6BZ29e+l5UVNo9DJhqP5Ib0KrE5Eus2TzX8HO2ODTEbJEUDxUsi\n4gRJmwEi4iFJbsweUUXSc6fdcdfvq4wgAfDrJ3akXvTTqsSykgF67gkbJUUboGcljZHUBCTzZ+/K\n/hEbVmXmPOpE6g1oPA6iqjoeYqzBIL20z5E2hsLVTTaMij5RfBi4HniapEuAM4ALSiuVDZQy54ru\n5AC0rH2vWLKAc9duyfVzboewUVEoUETEVZI2Aa+g0j18RUTcWWrJbGCUWV/frAttO5qVx+0OZo21\nk+vproj4aER8xEFitKXlPCpSX9/qYDhRmb1uTov5OFopT5mfw2yYFM31dIWkyZrleZI+WV6xbJDk\nra9PG9Fcv680CyYnuOzMxTy+YxcZY+Rytx+43cGssUJzZkvaHBFLmq3rFs+ZPTguWLeVq269b6/x\nEBPjYw0vyPU9oGq3rQ7AS7NgcmL3wDcza6zVObOLVj3NkTSv5mCH4vm3rYkL1m3l03VBAio9i85Z\nu4UL1m3dva46lmJmdufu3khztGfbZu0YJx8zv+zim42sohf3DwD/KemaZPmNwCXlFMmG0brNU3z6\n1vsyt6m+f+IzDm04liKrmqnehru2Fyuome2jaK+nK5NeTycnq06PiO+UVywrW6+n4Wx1TMVVt97H\nv3zzR20PtPM8D2blKVxdFBHbgG0llsU6pMjI6bK1euEOyhmNnbdLa68DqVk/y9VGIenryfeHJf2q\n5uthSb/Kua8jJW2Q9B1J2yS9K1l/qKQvS/pu8n1es31ZtjJHThc1eWB6rqVOyNOltXaWvOrUpUUn\nUjIbRrkCRUScJEnAooh4cs3XwRHx5JzH3gGcFxHHAi8F3inpWGAV8JWIeC7wlWTZ2lDmyOki1m2e\n4pHHdnTlWADzDhzP9TRQZiDN6vprNqhyVz1FREj6AnBcOweOiJ8AP0lePyzpTmAB8Hrg5clmVwA3\nA+9p51ijLm3E8SET4yxdvb7j1S1rbrw7c1KgMo2PiQtPW5TrZ8oKpP1QxWfWCUW7x35bUmkpxSUt\nBJYA3wQOS4IIwE+Bw1J+5h2SNkrauH27e7hkaTTieHyO+PUTO/aqbll5zW0sufimUu+G122eKjUl\nx9gcMZ4yHPuguWMcNHc/zl27JVf509oz8rZzpD2ZnHf1bX6ysIFWNFC8BLhV0vcl3S5pq6Tbi+xI\n0pOozGVxTkTs1c4RldGADW9FI+LyiDgxIk6cP9995rM0GnH8pAP2Y3bn3qd2dlfw0KOzpdXTV++w\ny7RzVzB3vzl7fZYPnbmYD525mF0B0zP5y19W6o60J5BqunIHCxtURXs9LS/j4JLGqQSJqyLiumT1\nA5KeHhE/SaZYfbCMY426+kynz1z1haY/Uz+FaLOeQfXvP/rEjo6kDP/1Ezu55Hf3PvbS1etT2xla\nSd0B7U9dmpXQsNWymPWjooHiAeBPgZOo3PF/Hfj7PDtIGsU/AdwZER+seesG4GxgdfL98wXLaBla\nzdJavUtuVv/e6P0sotITqtFc1a2ov+i2285QRsrwZnOCe2yHDaqiVU9XAouA/wt8BDgW+FTOfSwF\n3gYsk7Ql+XoNlQBxiqTvAq9Mlq1kraa4qNbTN6t/zzvhUACPze5iXsFus/UX3bLaGdqRNQFSt8ti\nVqaiTxTPT7q1Vm2QlGtkdkR8ncqNZSOvKFgua1ErKS5q6+mb1b8XqWKamd3J/vvNYWJ8LPfP1190\n+2Vq0upTST+Uxaws7fR6eml1QdJLAKdvHSBZ1SCNUmxn3Q3XJu7L65czs03TitfvudFFt59ShPdT\nWczKUDTN+J3A0UA1y9tRwN1UBtFFRLygtBK2oNtpxoch3cPS1esbtiOMSXzgTce3lPK7Xv2TwfiY\nIMgcQ1GbDjwtrfgbXriADXdtH+jzbdaPWk0zXrTq6VUFf27gDcugqrSG12pVEuz9eaqvz7v6toa5\nmBYkF/D6AArsnjtCsM88FCcfM3+vQX8OCmb9p9ATRb/p5hNF2p34IE6Us27zVOaFv9HnyZpMqNkF\nvf5J7ORj5nPtpqlC+zKz9nV64qKR1eu8Sc3kyTW0YskCdqXcKKR9nqL1742q6zbctb3nyQrNrDnP\nSpdT2viDfuj6WKRarMjnyTvmIK1cHm9gNhj8RJFTWekeOqFIFtQyP0/a00xauTzewGww5HqikPTu\nrPfrRlgPpbLSPXRCkWqxsj7PBeu2clXNfNi1TzNZYzDqe0r1S9A1sz3yVj0dnHw/GngRlXQbAKcB\n3yqrUP2ujHQPnVC0Wqzdz7Nu89ReQaKq+jSTVq60nlL9eG7NRlmuQBER7wWQ9FXghIh4OFm+CGie\nZc46qlejk9fceHfjFL9UniYuO3Nxarn6Neia2R5FG7MPA56oWX6ClHkjrHt6VS2WVbV1+OREX1fX\nmVlzRQPFlcC3JF2fLK+gMhud9Vgv7tDTqpbEnrmr/eRgNrgK9XqKiEuA3wceSr5+PyL+T5kFs8HR\nqOeUgLe89KiGqUA8p7TZYCn0RJHMJXEscEhEXCzpKEkvjoiRadC2PVqtWhqW9Cdmo6ZoUsC/B3YB\nyyLieZLmATdFRGnzaOfR7aSAvVAd2Tw1PcOYxM6I3b2G2r3IdivJ4TClPzEbBp1OCviSiDhB0maA\niHhI0tyC+7Im6u/Eq7mZyrgjX7d5ipXX3LY7w+vU9Awrr7mtrX2m6ff0J2bWWNGR2bOSxkiSgUqa\nT+UJwzoga/a4dnMjXXTDtn3SgM/uCi66YVvhfabph1nozCy/ok8UHwauB54m6RLgDOCvSivVkMtb\n1dPsjjvvHXnt8dMqHqdnis1lnSVrnMcwzPFhNqwKBYqIuErSJipTlgpYERF3llqyIVVm4r7a91s9\n9kU3bCs9CLR6kU9r9AbcyG3Wx4r2enp/RLwHuKvBOsuQlbgv7aKYNskQpI+8bmXuhyzzDhxvabu8\nga/ReIqlq9fnPidm1j1Fq55OAeqDwqsbrBtJWXfY7Sbuq+/1dPIx81lz492cu3ZL5h16o1xMacbH\nxIWnLWpp2yKBr54buc36W97ssX8C/CnwbEm317x1MPCNMgs2qJrdYZeZuC/tWAeMz9nn4t0sSIxJ\n7IrI3T5QxkW+n+f4MLP8vZ4+QyVT7OeT79WvF0bEW0ou20BqNidEmfM/pB3roUfztUFMjI/xgTcd\nzz2rT+WWVctyVfeU0ZOpn+f4MLOcgSIifhkRP6SSBPCXEXFvRNwLhKRPdqKAg6bZHXazqUTzpLgo\no2rmoLntzVFdxkW+6PSqZtYdRdsoXhAR09WFZMDdkpLKNNBaqUZJS5CXt2E47ViTE+P8+okdzO5s\n3ioxeeDcti7IZWWGddJAs/5VdMDdnCRtBwCSDsXzbwPt3WHnnco07VgXvW4RB81t7deR56kk7Wln\nxZIF3LJqWaGqKzPrf0Uv7h8A/lPSNcnyG4FLyinSYGvnDjtvw3DWsc5du6Wl8uYZg+GxDmajqeiA\nuyuTAXcnJ6tOj4jvlFeswVa0GqVI75+0YzUbpAf52hLK6AZrZoOpaNUTEbEtIj6SfA18kOiHeRLK\n7P2zcvnRjM9R6vt5G4w91sFsdOUdR/H1iDhJ0sPs3TVfQETEk0stXZf0S7VKmVOGVn+mNmXHvAPH\nufC0RV172jGz4VBoPop+0+58FKMwT0K7SffqgylUnnbcjdVscHVkPgpJ7856PyI+mGd//WLYq1XK\neGIq82nHzAZL3sbsg5PvRwMvAm5Ilk8DBnYa1GGvVimrIdpjHcxGU96R2e+NiPcCRwAnRMR5EXEe\n8ELgqE4UsBuGPYXEsD8xmVlnFe31dBiVNB5VTyTrcpH0SUkPSrqjZt2hkr4s6bvJ93lZ+yjDsKeQ\n8MxyZtaOogPurgS+Jen6ZHkFcEWB/fwz8JFkf1WrgK9ExGpJq5LljqcvH+ZqlayZ5czMmik64O4S\nSf8O/Fay6vcjYnOB/XxV0sK61a8HXp68vgK4Gc9z0RY3RJtZO4rOcCfgWOCQiLhY0lGSXhwRZTRo\nHxYRP0le/5QCVVq2r24+MXn+a7PhUrSN4mPAy4CzkuWHgY+WUqIaURnk0XCgh6R3SNooaeP27dvL\nPrQVVO2KOzU9Q7CnK24vRrqbWTmKBoqXRMQ7gcegkmYcmFtSmR6Q9HSA5PuDjTaKiMsj4sSIOHH+\n/PklHdralTcDrpn1v6KBYlbSGMndvqT5wK6SynQDcHby+mwqs+nZgHBXXLPhU7TX04eB64GnSboE\nOAO4IO9OJP0LlYbrp0r6MXAhsBq4WtLbgXuBNxUs41Dq9/r/YR+8aDaKcgeKpCH7q8Am4BVUEgKu\niIg78+4rIs5KeesVefc1CvoleWEWd8U1Gz65A0VEhKQvRsRxwF0dKFPf69VdfZ5UHL0qo7vimg2f\nolVP35b0ooj4r1JLMwB6eVffav1/r588hnnwotkoKtzrCbhV0vcl3S5pq6TbyyxYv+plr55WU3G4\n55GZlanoE8XyUksxQHrZq6fV+n/3PDKzMuWdj+IA4I+B5wBbgU9ExI5OFKxf9bJXT6v1/+55ZGZl\nyvtEcQUwC3wNeDWVNB7vKrtu6ZQDAAAJq0lEQVRQ/azVu/pONSa3Uv/vnkdmVqa8geLYpLcTkj7B\nAE9WVFQrd/X90JjcrIxmZq3KNWe2pG9HxAlpy73S7pzZZRuFObjNbPB1ZM5s4HhJv6oeA5hIlkVl\niMWTc+6vZzo5zsCNyWY2THIFiogYa75V/+t01ZAbk81smBQdRzHQOj3OYNjn4Daz0VJ0HMVAK6tq\nKK36yo3JZjZMRjJQlFE11Kz6ymkszGxYjGTVUxlVQ06TYWajYiSfKMqoGnLPJjMbFSMZKKD9DKfu\n2WRmo2Ikq57K4J5NZjYqRvaJol3u2WRmo8KBog3u2WRmo8BVT2ZmlsmBwszMMjlQmJlZJrdRlKiT\nGWnNzHrFgaIkvZ6syMysU1z1VBKn9DCzYeVAURKn9DCzYeVAUZK01B1O6WFmg86BoiRO6WFmw8qN\n2SVxSg8zG1YOFCVySg8zG0auejIzs0wOFGZmlsmBwszMMjlQmJlZJgcKMzPL1JeBQtKrJN0t6XuS\nVvW6PGZmo6zvAoWkMeCjwKuBY4GzJB3b21KZmY2uvgsUwIuB70XEDyLiCeCzwOt7XCYzs5HVj4Fi\nAfCjmuUfJ+v2IukdkjZK2rh9+/auFc7MbNT0Y6BoSURcHhEnRsSJ8+fP73VxzMyGVj8GiingyJrl\nI5J1ZmbWA/0YKP4LeK6kZ0qaC7wZuKHHZTIzG1l9lxQwInZI+jPgRmAM+GREbOtxsczMRlbfBQqA\niPgi8MVel8PMzPqz6snMzPqIA4WZmWVyoDAzs0wOFGZmlsmBwszMMjlQmJlZJgcKMzPL5EBhZmaZ\nHCjMzCyTA4WZmWVyoDAzs0wOFGZmlqkvkwL2s3Wbp1hz493cPz3D4ZMTrFx+NCuW7DMBn5nZ0HCg\nyGHd5inOv24rM7M7AZianuH867YCOFiY2dBy1VMOa268e3eQqJqZ3cmaG+/uUYnMzDrPgSKH+6dn\ncq03MxsGDhQ5HD45kWu9mdkwcKDIYeXyo5kYH9tr3cT4GCuXH92jEpmZdZ4bs3OoNli715OZjRIH\nipxWLFngwGBmI8VVT2ZmlsmBwszMMjlQmJlZJgcKMzPL5EBhZmaZFBG9LkPbJG0H7u11Odr0VOBn\nvS5EH/H52MPnYm8+H3tr53w8IyLmN9toKALFMJC0MSJO7HU5+oXPxx4+F3vz+dhbN86Hq57MzCyT\nA4WZmWVyoOgfl/e6AH3G52MPn4u9+XzsrePnw20UZmaWyU8UZmaWyYHCzMwyOVD0gKRPSnpQ0h01\n6w6V9GVJ302+z+tlGbtF0pGSNkj6jqRtkt6VrB/V83GApG9Jui05H+9N1j9T0jclfU/SWklze13W\nbpE0JmmzpH9Llkf5XPxQ0lZJWyRtTNZ1/H/FgaI3/hl4Vd26VcBXIuK5wFeS5VGwAzgvIo4FXgq8\nU9KxjO75eBxYFhHHA4uBV0l6KfB+4LKIeA7wEPD2Hpax294F3FmzPMrnAuDkiFhcM3ai4/8rDhQ9\nEBFfBX5Rt/r1wBXJ6yuAFV0tVI9ExE8i4tvJ64epXBAWMLrnIyLikWRxPPkKYBnwuWT9yJwPSUcA\npwL/mCyLET0XGTr+v+JA0T8Oi4ifJK9/ChzWy8L0gqSFwBLgm4zw+UiqWrYADwJfBr4PTEfEjmST\nH1MJpqPgQ8BfAruS5acwuucCKjcNN0naJOkdybqO/694hrs+FBEhaaT6LUt6EnAtcE5E/Kpy41gx\naucjInYCiyVNAtcDx/S4SD0h6bXAgxGxSdLLe12ePnFSRExJehrwZUl31b7Zqf8VP1H0jwckPR0g\n+f5gj8vTNZLGqQSJqyLiumT1yJ6PqoiYBjYALwMmJVVv7I4ApnpWsO5ZCrxO0g+Bz1Kpcvo7RvNc\nABARU8n3B6ncRLyYLvyvOFD0jxuAs5PXZwOf72FZuiapc/4EcGdEfLDmrVE9H/OTJwkkTQCnUGm3\n2QCckWw2EucjIs6PiCMiYiHwZmB9RLyFETwXAJIOknRw9TXwO8AddOF/xSOze0DSvwAvp5Ie+AHg\nQmAdcDVwFJWU6W+KiPoG76Ej6STga8BW9tRD/y8q7RSjeD5eQKVBcozKjdzVEXGxpGdRuas+FNgM\nvDUiHu9dSbsrqXr6i4h47aiei+RzX58s7gd8JiIukfQUOvy/4kBhZmaZXPVkZmaZHCjMzCyTA4WZ\nmWVyoDAzs0wOFGZmlsmBwszMMjlQ2NCQtEJSSMpMeSFpUtKftnmsR1LW70xSQN8h6RpJB6Zs9412\njt8qSc9LUlPPSZbHJN0k6fe6cXwbDg4UNkzOAr6efM8yCbQVKDLMJCmgnw88Afxx7ZuqmBMRv9mh\n4+8lIu6kMrL7tcmqS4C7I+LKbhzfhoMDhQ2FJKngSVTmJnhzzfrfk3R7MhHQp5LVq4FnJ3f+ayQt\nrJtE6i8kXZS8Xpdk6txWk62zVV8DnpPs/25JV1JJuXBk7RNJShmR9NZkEqMtkv4heRo4SNIXkm3v\nkHRmC+W4DPgTSW+gkj/p3Tk/h404Z4+1YfF64EsR8d+Sfi7phcBjwAXAb0bEzyQdmmy7Cnh+RCyG\n3enN0/xBRPwiybv0X5KujYifNytMkrTu1cCXklXPBc6OiFuT96vbLWpURknPA84ElkbErKSPAW8B\nfg3cHxGnJtsdknz/IvCHEXF/fVki4iZJHwAuBX47Imabld+slp8obFicRSX/D8n3s6hkG70mIn4G\nUDD/zZ9Lug24FTiSygU/y0Qyl8RG4D4qCQ8B7q0GiTppZXwF8EIqwWlLsvwsKjmxTpH0fkm/FRG/\nTH7uNY2CRI1vAB+MiJ9WV0j6myafxQzwE4UNgeQufBlwXJKLf4zKBC9rWtzFDva+aTog2e/LgVcC\nL4uIRyXdXH0vw0z1SaWmfFB5EshDwBURcf4+b0gnAK8B3ifpKxFxcQv7Oxb4p5p9/AaV2fPMmvIT\nhQ2DM4BPRcQzImJhRBwJ3APcDrwxya5JTdXTw8DBNT//APA0SU+RtD97Gn4PAR5KgsQxVOb0Ltv6\nlDJ+BTgjmaAGSYdKeoakw4FHI+LTVALhCS0eZxGV9pGqxcCWMj6ADT8HChsGZ7En/XLVtVQatS8B\n/l9SffRBgKSN4ZakMXhNUmd/MfAtKlOPVmcN+xKwn6Q7qTSAN6o6aktEbEsp43eotF3cJOn2pFxP\nB44DvpVUR10IvA8qbRRJENmHpCOpTB9a26XXgcJa5jTjZiNI0ieAP4qIXU03tpHnQGFmZplc9WRm\nZpkcKMzMLJMDhZmZZXKgMDOzTA4UZmaWyYHCzMwyOVCYmVkmBwozM8vkQGFmZpn+P0oQ58T6BoBj\nAAAAAElFTkSuQmCC\n",
- "text/plain": [
- ""
- ]
- },
- "metadata": {
- "tags": []
- }
- }
- ]
+ "colab_type": "code",
+ "id": "N7qm1HuVO-1k",
+ "outputId": "7e291cec-e602-4ad9-a5b3-b70d7261f63d"
+ },
+ "outputs": [],
+ "source": [
+ "# call Linear Regression model\n",
+ "mlr = LinearRegression()\n",
+ "\n",
+ "# train the model for multiple regression\n",
+ "mlr.fit(mX_train, mY_train)\n",
+ "\n",
+ "# make predictions for test X values\n",
+ "mY_pred = mlr.predict(mX_test)\n",
+ "\n",
+ "# calculate error\n",
+ "mlr_mse = mean_squared_error(mY_test, mY_pred)\n",
+ "\n",
+ "print(f'Mean Squared Error: {mlr_mse}')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "jTdmleXCM_Xb"
+ },
+ "source": [
+ "5. visualize with `matplotlib`"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 305
},
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "2X1RA6sgtZQ6",
- "colab_type": "text"
- },
- "source": [
- "## Conclusion\n",
- "- looks like the multiple regression we ran does provide more accurate predictions than the simple linear regression\n",
- " - this will not always be the case, so always be sure to check and confirm if the extra computing is worth it\n",
- "\n",
- "Anyways, that's how you implement both Simple and Multiple Linear Regression with `cuML`. Go forth and do great things. Thanks for stopping by!"
- ]
- }
- ]
+ "colab_type": "code",
+ "id": "Q83NFMK1JKvL",
+ "outputId": "569cfa77-a66e-4b1b-9d70-ae4ef8e7936e"
+ },
+ "outputs": [],
+ "source": [
+ "# scatter actual and predicted results\n",
+ "plt.scatter(mY_test.to_pandas(), mY_pred.to_pandas())\n",
+ "\n",
+ "# label graph\n",
+ "plt.xlabel(\"Actual Prices: $Y_i$\")\n",
+ "plt.ylabel(\"Predicted prices: $\\hat{Y}_i$\")\n",
+ "plt.title(\"Prices vs Predicted prices: $Y_i$ vs $\\hat{Y}_i$\")\n",
+ "\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "2X1RA6sgtZQ6"
+ },
+ "source": [
+ "## Conclusion\n",
+ "- looks like the multiple regression we ran does provide more accurate predictions than the simple linear regression\n",
+ " - this will not always be the case, so always be sure to check and confirm if the extra computing is worth it\n",
+ "\n",
+ "Anyways, that's how you implement both Simple and Multiple Linear Regression with `cuML`. Go forth and do great things. Thanks for stopping by!"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Continued Learning \n",
+ "Here are some resources to help fill in any gaps and provide a more complete picture.\n",
+ "\n",
+ "#### **StatQuest: Linear Models Pt.1 - Linear Regression**\n",
+ "- Watch on YouTube: [https://youtu.be/4b5d3muPQmA](https://youtu.be/nk2CQITm_eo)\n",
+ "- Channel: StatQuest with Josh Starmer ([Subscribe](https://www.youtube.com/channel/UCtYLUTtgS3k1Fg4y5tAhLbw?sub_confirmation=1))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from IPython.display import YouTubeVideo\n",
+ "YouTubeVideo('nk2CQITm_eo', width=(1280*0.69), height=(720*0.69))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "#### **Linear regression**\n",
+ "Wikipedia: [wikipedia.org/wiki/Linear_regression](https://en.wikipedia.org/wiki/Linear_regression)\n",
+ "\n",
+ "---\n",
+ "#### [**Back to GitHub**](https://github.com/gumdropsteve/cuml_linear_regression)"
+ ]
+ }
+ ],
+ "metadata": {
+ "accelerator": "GPU",
+ "colab": {
+ "collapsed_sections": [],
+ "name": "LOCAL_intro_lin_reg_cuml",
+ "provenance": []
+ },
+ "kernelspec": {
+ "display_name": "RAPIDS Stable",
+ "language": "python",
+ "name": "rapids-stable"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.7.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
}