5

使用机器学习数据集构建销售预测Web应用程序

 3 years ago
source link: https://panchuang.net/2020/10/19/%e4%bd%bf%e7%94%a8%e6%9c%ba%e5%99%a8%e5%ad%a6%e4%b9%a0%e6%95%b0%e6%8d%ae%e9%9b%86%e6%9e%84%e5%bb%ba%e9%94%80%e5%94%ae%e9%a2%84%e6%b5%8bweb%e5%ba%94%e7%94%a8%e7%a8%8b%e5%ba%8f/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

作者|Saurabh Mhatre
编译|Flin
来源|analyticsvidhya

互联网上有很多资源可以找到关于机器学习数据集的见解和训练模型,但是关于如何使用这些模型构建实际应用程序的文章很少。

因此,今天我们将通过首先使用hackathon中的数据集来训练视频游戏销售预测模型,然后使用经过训练的模型来创建一个基本应用程序,根据用户输入为我们提供销售预测来学习此过程。

本文分为多个部分,你可以一个接一个地学习,而不必一口气完成它。从我第一次选择数据集以来,我花了整整一周的时间来完成应用程序。因此,请花时间专注于学习构建应用程序的各个方面,而不是只注意最终产品。

第1部分:生成模型

我们将使用在Machine Hack网站上运行的视频游戏销售预测hackathon中的数据集。首先,在MachineHack上创建一个帐户,然后在此链接上注册hackathon。

注册后,转到数据标签并下载zip文件,该文件将包含三个文件,即训练,测试和样品提交。

下一步将在Google Colab Notebook中介绍,你可以从以下链接打开和克隆该Notebook:

或者如果你想在本地或其他平台上下载并运行该Notebook,请从以下GitHub链接下载该Notebook:Jupyter Notebook链接

Notebook电脑的第一部分简要介绍了问题陈述。通过运行下面显示的下一个代码单元,上传我们收到的文件

from google.colab import files
uploaded = files.upload()
for fn in uploaded.keys():
  print('User uploaded file "{name}" with length {length} bytes'.format(
      name=fn, length=len(uploaded[fn])))

在下一个代码单元中,我们导入所需的python包。它们中的大多数已预先安装在Google Colab中,因此无需安装它们中的任何一个。

因为我们无法在hackathon结束后提交测试数据进行评估,因此本文其余部分仅将数据用于Train.csv。请记住,Train.csv的行数少于通常用于正确训练模型的行数。但是,出于学习目的,我们可以使用行数较少的数据集。

现在让我们深入研究解决此机器学习问题…

步骤1识别目标和独立特征

首先,让我们将Train.csv导入pandas数据框中,然后运行df.head()以查看数据集中的列。

从数据框中,我们可以看到目标列是SalesInMillions,其余列是独立特征

步骤2清理资料集

首先,我们通过运行input.isnull().sum()命令检查null值。

input.isnull().sum()
#Output:
ID                 0
CONSOLE            0
YEAR               0
CATEGORY           0
PUBLISHER          0
RATING             0
CRITICS_POINTS     0
USER_POINTS        0
SalesInMillions    0
dtype: int64

我们可以看到数据集中没有空值。接下来,我们可以通过运行以下命令删除不必要的列ID,因为它在目标销售中不起作用:input = input.drop(columns=['ID'])

接下来,我们可以使用train_test_split命令将数据框分为训练和测试数据集:

train, test = train_test_split(input, test_size=0.2, random_state=42, shuffle=True)

步骤3探索性数据分析

描述性统计信息

使用df.shape命令我们可以找到数据集中的总行数,并且可以使用命令df.nunique()在每个列中查找唯一值。

CONSOLE              17
YEAR                 23
CATEGORY             12
PUBLISHER           184
RATING                6
CRITICS_POINTS     1499
USER_POINTS        1877
SalesInMillions    2804

在EDA部分中,我们使用pandas profilingmatplotlib包生成各种列的图形,并观察它们与目标列的关系。

从EDA获得的一些见解是:

PS3平台的销售额最高。之后是Xbox360:

动作类别的销售额最高,难题类别的销售额最低

2007年到2011年的销售额最高:

通常,我们在EDA之后进行特征工程或特征选择步骤。但是,我们的功能较少,着重于实际使用模型。因此,我们正在朝着下一步迈进。但是,请记住,USER_POINTSCRITICS_POINTS列可用于派生其他功能。

步骤4建立模型

由于我们具有许多分类功能,因此我们将对数据集使用catboost回归模型。由于catboost可以直接作用于分类特征,因此跳过了对分类特征进行标签编码的步骤。

首先,我们使用pip install命令安装catboost软件包。

然后,我们创建一个分类特征列表,将其传递给模型,然后将模型拟合到训练数据集上:

import catboost as cat
cat_feat = ['CONSOLE','CATEGORY', 'PUBLISHER', 'RATING']
features = list(set(train.columns)-set(['SalesInMillions']))
target = 'SalesInMillions'
model = cat.CatBoostRegressor(random_state=100,cat_features=cat_feat,verbose=0)
model.fit(train[features],train[target])

步骤5检查模型的准确性

首先,我们根据测试数据集创建真实的预测:

y_true= pd.DataFrame(data=test[target], columns=['SalesInMillions'])
test_temp = test.drop(columns=[target])

接下来,我们在测试数据集上运行训练良好的模型以获取模型预测并检查模型准确性

y_pred = model.predict(test_temp[features])
from sklearn.metrics import mean_squared_error
from math import sqrt

rmse = sqrt(mean_squared_error(y_true, y_pred))
print(rmse)
#Output: 1.5555409360901584

我们的RMSE值为1.5,这相当不错。有关在出现回归问题时准确性指标的更多信息,可以参考本文。

如果你想进一步改善模型或尝试组合各种模型,可以在本文中参考本次hackathon获胜者的方法:

步骤6将模型保存到pickle文件中

现在,我们可以将模型保存到pickle文件中,然后将其保存在本地:

import pickle
filename = 'finalized_model.sav'
pickle.dump(model, open(filename, 'wb'))

保存pickle文件后,你可以从Google Colab Notebook文件部分的左侧边栏中下载并保存在本地

额外提示

  • 添加更多数据

我们可以通过向模型添加更多数据来改善模型预测。我们可以使用一些在Kaggle上的相关的数据集。Kaggle:https://www.kaggle.com/gregorut/videogamesales

  • 提高模型效率

我们可以使用组合模型的堆栈来进一步提高模型效率。

如果你已完成此步骤,请轻拍一下自己的背,因为我们刚刚完成了项目的第一个主要部分。休息一会儿,拉伸一下,然后开始本文的下一部分。

第2部分:根据模型创建后端API

我们将使用Python Flask创建后端API。

因此,首先在本地创建一个名为server的文件夹。另外,如果还没有,请在你的计算机上安装Python和pip软件包管理器。

接下来,我们需要在文件夹中创建一个虚拟环境。我在Linux上使用python3,因此我创建虚拟环境的命令为:python3 -m venv server

你可以在本文中查看适用于你的OS和Python版本的命令:Python venv:https://packaging.python.org/guides/installing-using-pip-and-virtual-environments/

接下来,我们将通过运行以下命令激活虚拟环境: source server/bin/activate

完成后,我们需要安装Flask pip软件包: pip install -U Flask

接下来,使用你喜欢的文本编辑器在服务器文件夹中创建一个名为“app.py”的文件,并添加以下代码以创建基本的API:

from flask import Flask, jsonify, make_response, request, abort
app = Flask(__name__)
@app.route("/")
def hello():
  return "Hello World!"
if __name__ == "__main__":
  app.run()

现在打开终端并运行python3 app.py以启动服务器。这将主要在5000端口上启动服务器。为了测试API,请在浏览器中打开此链接:http://localhost:5000/

你应该在浏览器中打印出Hello World。如果不是,则在启动API时检查API是否在其他端口上运行或在终端上打印错误。

我们将调用POST API,因此最好在继续进行之前安装Postman工具。使用此工具将向服务器发送POST请求。

接下来,我们需要使用以下命令安装catboost,pandas和Flask-Cors pip软件包:

pip install catboost pandas Flask-Cors

接下来,将我们在第1部分末尾下载的经过训练的模型的pickle文件(finalized_model.sav)复制到服务器文件夹中。

现在,使用以下代码更新 app.py:

from flask import Flask, jsonify, make_response, request, abort
import pandas as pd
import catboost
import pickle
from flask_cors import CORS,cross_origin
model = pickle.load(open( "finalized_model.sav", "rb"))
app = Flask(__name__)
app.config['CORS_HEADERS'] = 'Content-Type'
cors = CORS(app)
@app.errorhandler(404)

def not_found(error):
    return make_response(jsonify({'error': 'Not found'}), 404)

@app.route("/")
def hello():
  return "Hello World!"

@app.route("/get_prediction", methods=['POST','OPTIONS'])
@cross_origin()
def get_prediction():
    if not request.json:
        abort(400)
    df = pd.DataFrame(request.json, index=[0])
    cols=["CONSOLE","RATING","CRITICS_POINTS","CATEGORY","YEAR","PUBLISHER","USER_POINTS"]
    df = df[cols]
    return jsonify({'result': model.predict(df)[0]}), 201

if __name__ == "__main__":
  app.run()

在第6行中,我们将训练后的模型导入到我们的python文件中。

在第10行,我们初始化CORS模块以允许来自客户端API调用的请求。

在第11行,我们定义了一个错误处理程序,如果从服务器访问了任何未处理的异常或未定义的路径,它将发送错误响应。

对我们来说,主要的兴趣点是从第19行定义的get_prediction POST API。get_prediction方法是我们从客户端获取数据并提供响应的销售预测。

在第24行,我们将来自API请求的数据转换为pandas数据框。现在,我们的模型期望列以特定顺序提供正确的响应。因此,在第25行中,我们指定列顺序。在接下来的步骤中,以所需顺序重新排列列。

在第27行,model.predict用于从模型中获取预测,并将其作为响应传递给客户端。在这一步,我们准备好在本地使用该API。我们可以通过发送POST-API调用来测试Postman客户端中的API,如截图所示:

你可以在上述请求的正文部分中添加一个JSON示例,可以在代码Github-gist中找到。

确保在主体和主体类型中选择raw和JSON选项(如屏幕截图所示),并在请求类型中选择POST。

如果在此步骤之前一切正常,那么恭喜你,你现在有了一个后端API,该API可根据输入参数根据经过训练的模型进行预测。

额外提示

  • 模块化代码

在后端设计中不建议在单个文件中编写API,我们可以将路径和模型导入分隔到不同的文件夹中,以使代码更具模块化。如果将来引入其他API,这也将使我们能够以可管理的方式扩展代码。

在这一点上,我们可以再次休息一下,确保收藏了本文,以便轻松地重新开始本项目的下一部分。

第3部分:将后端API部署到Heroku

到目前为止,我们的API在本地工作,但我们需要将其部署在远程服务器上,以供其他地方使用。为此,我们将使用Heroku作为我们的API托管平台。

我主要参考了来自stackabuse 的文章,将其部署到Heroku。我们将简要介绍这些步骤,但是如果你卡在了其中某个步骤,请在此处参阅原始文章:

首先,我们使用terminal命令安装gunicorn:

pip install gunicorn

接下来,运行下面的命令将所有已安装的pip包,存储到require.txt文件:

pip freeze > requirements.txt

你可以参考此处上传的requirements.txt文件以供参考:

接下来,Procfile使用以下代码在服务器文件夹中创建一个名称为Procfile的文件:

web: gunicorn app:app

现在,在Heroku网站上注册,在该网站上创建一个应用,然后按照原始文章中的说明安装Heroku CLI 。

接下来,通过运行以下命令从本地终端登录Heroku: heroku login -i

使用以下命令添加你的Heroku应用git参考:

heroku git:remote -a {your-project-name}

现在,使用以下命令将代码推送到Heroku:

git push heroku master

在运行上述命令的最后,你将在终端输出中获得API URL,现在我们可以使用该URL从客户端进行调用。此时,我们还可以从PostMan应用程序发送API请求,以查看我们是否正确收到了与步骤2末尾所述类似的响应。

到目前为止的代码库可以在以下Github存储库中找到

现在,我们在服务器上托管了一个正常工作的API。如果一切正常,那么我们可以继续开发客户端应用程序。如果遇到任何问题,请在评论部分中提及你的问题。

第4部分:使用react和bootstrap创建客户端应用程序

我们将需要在我们的计算机上正确安装和设置Node.js。因此,请先下载并安装适用于你相关操作系统和系统的Node.js,然后再继续进行操作。另外,建议安装yarn管理器:yarn 安装

现在,在上一步中创建frontend的服务器文件夹外部创建一个新文件夹,并从终端进入该frontend文件夹内部。

接下来,我们将创建一个新的react应用程序,并通过在终端中运行以下命令来启动它:

npx create-react-app sales-prediction-app
cd sales-prediction-app
npm start

你应该在浏览器中看到默认打开的浏览器选项卡,以及react.js默认模板应用程序。现在我们需要在我们最喜欢的编辑器中打开该项目(我正在使用VSCode),并开始进行更改以构建前端应用程序。

首先,我们需要在应用程序公共文件夹中的index.html文件中导入相关的引导程序文件。

我们需要按照bootstrap文档提供的说明在index.html文件中添加文件,如下所示:

<head>
...
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
...
</head>
<body>
...
<div id="root"></div>
...
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script>
...
</body>

我们的最终用户界面是集合下拉菜单项,其中单个项如下所示:

我们将在src文件夹中创建一个名称为optionsSources.json的JSON文件。JSON文件中的每个条目都包含以下对象:

{
    "CONSOLE": {
        "options": [
            "ps2","x360","ps3","pc"
        ],
        "icon": "🕹️",
        "dropDownPlaceholder": "Select Console"
    }
}

下拉菜单中显示的选项位于options数组中,下拉菜单选项左侧显示的图标和标签位于icon和dropDownPlaceholder项。我们需要创建多个这样的下拉列表,因此要添加的完整JSON文件如以下文件所示:

接下来,我们需要在我们的应用程序中实现下拉组件。在src文件夹中创建一个名为components的文件夹,并在components文件夹中创建一个名为OptionSelection.js的文件

我们将编写一个功能组件,该组件返回一个下拉项,如下所示:

import React,{ useState } from 'react';
import optionSources from  '../optionsSources.json';
function OptionSelection({itemKey, setOptionInObject}) {
    const title = optionSources[itemKey].dropDownPlaceholder;
    const icon = optionSources[itemKey].icon;
    return(
        <div className="d-flex justify-content-start align-items-center mt-2 selection-item">
            <div className="option-label">
            <b><span role="img" aria-label="label-icon">{icon}</span>{` ${title}`}</b>
            </div>
            <div className="dropdown ml-4">
            <button className="btn btn-primary dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                {title}
            </button>
            <div className="dropdown-menu" aria-labelledby="dropdownMenuButton">
                {renderOptionsDropdown()}
            </div>
            </div>
        </div>
    )
}

export default OptionSelection;

在上面的组件中,我们itemKey从第3行的父组件中获得prop(param)值。我们假设itemKey从父组件接收的是CONSOLE。在第4行和第5行,我们首先提取显示在下拉菜单左侧的标题和图标。然后,根据Boostrap文档在创建下拉列表时,在第6行的返回函数中使用HTML标签。

接下来,我们需要实现renderOptionsDrop在返回函数中定义的函数,如下所示:

import optionSources from  '../optionsSources.json';
function OptionSelection({itemKey, setOptionInObject}) {
...
const renderOptionsDropdown = () => {
        const selectionOptions = optionSources[itemKey].options;
        return selectionOptions.map((selectionOption, index)=>{
            return (
                <div className="dropdown-item pointer" 
                     key={`${index}${selectionOption}`} 
                     onClick={() => handleDropDownSelection(selectionOption)}
                >
                    {selectionOption}
                </div>
            );
        })
}
...
}

在第5行,我们从optionSources JSON对象获取特定项的options数组,并将其存储在selectionOptions变量中。

然后在第6行,我们使用map函数迭代数组并显示下拉选择项。我们必须在第10行使用onClick函数更新下拉项的选定值。

然后实现onClick处理程序中的函数handleDropDownSelection,如下所示:

import React,{ useState } from 'react';
...
function OptionSelection({itemKey, setOptionInObject}) {
    const [currentSelectedOption, setSelectedOption] = useState(null);
    const handleDropDownSelection = (consoleOption) => {
        setSelectedOption(consoleOption)
        setOptionInObject(itemKey, consoleOption)
    }
    ...
}

我们在第1行输入了useState hook。它是一个内部函数,允许我们使用状态变量的概念动态更新值。关于这个函数的更多信息可以在这里找到:

在第7行,我们更新下拉列表的选定选项。在第8行中,我们将选择的值传递回父函数以进行进一步处理。

这个组件的完整代码可以在这里找到:https://github.com/codeclassifiers/video-salesprediction-frontend/blob/master/src/components/ConsoleSelection.js

然后我们在src文件夹中导入此选项并对服务器进行API调用。完整的代码可以在这里找到:

然后在handleInputSubmission函数中对后端进行API调用,如下所示:

import React, {useState} from 'react';
import axios from 'axios';
function App() {
  ...
  const handleInputSubmission = () => {
    if(selectedObject && Object.keys(selectedObject).length === 7) {
      ...
      axios.post(process.env.REACT_APP_HEROKU_SERVER_URL, selectedObject)
      .then(function (response) {
        setPredictionLoading(false)
        setModelPrediction(response.data.result)
      })
      .catch(function (error) {
        setPredictionLoading(false)
        setRequestFailed("Some error ocurred while fetching prediction")
      });
    } else {
      setRequestFailed("Please select all fields before submitting request")
    }
  }
}

我们正在使用Axios npm模块对后端Heroku服务器进行POST API调用。确保在process.env.REACT_APP_HEROKU_SERVER_URL占位符的第8行上添加自己的Heroku服务器URL,以接收来自服务器API的响应。

最好将API URL变量保存在.env文件中,然后在部署环境中进行设置。可以在这里找到更多详细信息:

在此处找到Github上的前端应用程序的完整资源:

这使我们有了在线部署Web应用程序的最后一步。因此,请耐心一些,让我们开始项目的最后一步。

第5部分:将客户端应用程序部署到Netlify

Netlify是一个可以轻松在线部署静态网站的平台。在部署使用createreact app模块生成的应用程序时,它有一个非常简单的过程。我们将利用此服务在线托管我们的web应用程序。

首先,我们需要在Github上创建一个帐户。

然后,我们需要将前端文件夹上传到Github存储库。我们可以按照官方文档中显示的步骤将项目部署到Github:官方文档(https://docs.github.com/en/github/importing-your-projects-to-github/adding-an-existing-project-to-github-using-the-command-line)

一旦该项目在GitHub上进行部署,通过遵循以下官方文档即可简单,直接地完成netlify的过程:Netlify Deploy(https://www.netlify.com/blog/2016/09/29/a-step-by-step-guide-deploying-on-netlify/)

如果你已在上一步中将环境变量用于服务器URL,请确保如本文档所示将其添加到netlify dashboard中。

最后,我们将提供一个如下所示的网络应用程序:

额外提示

  • 改进UI和配色方案

老实说,上面的UI非常简单。它没有很好的配色方案(主要是因为像我这样的开发人员不是优秀的设计师)。你可以改善设计并调整CSS,以更好地查看网页。

这样就完成了从机器学习hackathon数据集创建销售预测Web应用程序的过程。

如果你在完成项目的过程中没有遇到任何麻烦,那么你的分析和编码技能将受到赞誉。但是,如果你确实遇到了困难,那么,像往常一样,可以寻求Google和StackOverflow的帮助。如果你仍然无法找到解决问题的方法,请随时在评论中提及它们或在LinkedIn或Twitter上与我联系。

原文链接:https://www.analyticsvidhya.com/blog/2020/08/building-sales-prediction-web-application-using-machine-learning-dataset/

欢迎关注磐创AI博客站:
http://panchuang.net/

sklearn机器学习中文官方文档:
http://sklearn123.com/

欢迎关注磐创博客资源汇总站:
http://docs.panchuang.net/

原创文章,作者:磐石,如若转载,请注明出处:https://panchuang.net/2020/10/19/%e4%bd%bf%e7%94%a8%e6%9c%ba%e5%99%a8%e5%ad%a6%e4%b9%a0%e6%95%b0%e6%8d%ae%e9%9b%86%e6%9e%84%e5%bb%ba%e9%94%80%e5%94%ae%e9%a2%84%e6%b5%8bweb%e5%ba%94%e7%94%a8%e7%a8%8b%e5%ba%8f/


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK