一、项目介绍
1.1项目简介
本项目使用Flask框架搭建基于机器学习的南昌市租房价格预测系统 (简易版)
其中关于Flask知识点可参考文章Flask全套知识点从入门到精通,学完可直接做项目
其中关于南昌市租房价格预测可参考文章基于XGBoost算法构造房屋租赁价格评估模型
整个项目分为以下几个模块:
- 1.登录和注册模块
- 2.训练模型模块
- 3.预测价格模块
- 4.查看房价信息模块
项目文件框架如下:
其中manager.py为主程序,password.csv为存储用户账号密码的文件,lianjia是房租价格原始数据集,model.pkl是经过机器学习算法训练出的模型。
1.2技术工具
IDE编辑器:vscode
后端框架:Flask
前端框架:Bootstrap
1.3页面概述
运行manager.py程序后,浏览器打开http://127.0.0.1:5000/
映入眼帘的登录页面,有账号的话就之间输入用户名和密码,没有就点击Sign up先注册再登录
注册页面如下:
登录后进入主页面如下:
在导航栏中有训练模型、预测价格、查看房价信息、退出模块
训练模型模块如下:
需要依次按照步骤进行构建模型
预测房价模块:
在预测模块只需要输入地区、装修情况、楼层情况、电梯情况、房屋面积即可,每个输入类型都有提示(必须按照提示信息填写)
示例如下,填完信息后点击预测即可得到预测的房价信息:
查看房价信息模块:
在查看房价信息模块默认展示的是全部数据,当然你也可以通过输入价格区间进行筛选。
二、项目步骤
2.1登录模块
manager.py
class LoginView(views.MethodView): def __jump(self,error=None): return render_template('login.html',error=error) def get(self, error=None): return self.__jump() def post(self): uname = request.form['username'] pwd = int(request.form['password']) if uname and pwd: data = pd.read_csv('password.csv') for index,item in enumerate(data.values,1): if uname == item[0] and pwd == item[1]: return redirect('/main') if index == len(data): return self.__jump(error="用户名或者密码错误") else: return self.__jump(error="用户名或者密码不能为空") app.add_url_rule('/login/',view_func=LoginView.as_view('my_login'))
login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>登录</title> <style> * { margin: 0; padding: 0; } html { height: 100%; } body { height: 100%; } .container { height: 100%; background-image: linear-gradient(to right, #999999, #330867); } .login-wrapper { background-color: bisque; width: 358px; height: 588px; border-radius: 15px; padding: 0 50px; position: relative; left: 50%; top: 50%; transform: translate(-50%, -50%); } .header { font-size: 38px; font-weight: bold; text-align: center; line-height: 200px; } .input-item { display: block; width: 100%; margin-bottom: 20px; border: 0; padding: 10px; border-bottom: 1px solid rgb(128, 125, 125); font-size: 15px; outline: none; } .input-item::placeholder { text-transform: uppercase; } .btn { text-align: center; padding: 10px; width: 100%; margin-top: 40px; background-image: linear-gradient(to right, #a6c1ee, #fbc2eb); color: #fff; } .msg { text-align: center; line-height: 88px; } a { text-decoration-line: none; color: #abc1ee; } </style> </head> <body> <div class="container"> <div class="login-wrapper"> <form action="/login/" method="post"> <div class="header">Login</div> <div class="form-wrapper"> <input type="text" name="username" placeholder="username" class="input-item"> <input type="password" name="password" placeholder="password" class="input-item"> {% if error %} <font color="red">{{ error }}</font> {% endif %} <input class="btn" type="submit" value="立即登录"> </div> <div class="msg"> Don't have account? <a href="{{url_for('my_register')}}">Sign up</a> </div> </form> </div> </div> </body> </html>
2.2注册模块
manager.py
# 注册类视图 class RegisterView(views.MethodView): def __jump(self,error=None): return render_template('register.html',error=error) def get(self,error=None): return self.__jump() def post(self): # 模拟实现 uname = request.form['username'] pwd = request.form['password'] print(uname,pwd) if uname and pwd: with open('password.csv','a',encoding='utf-8',newline='\n')as f: cswriter = csv.writer(f) cswriter.writerow((uname,pwd)) f.flush() return redirect('/login') else: return self.__jump(error="用户名或者密码不能为空") app.add_url_rule('/register/',view_func=RegisterView.as_view('my_register'))
register.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>注册</title> <style> * { margin: 0; padding: 0; } html { height: 100%; } body { height: 100%; } .container { height: 100%; background-image: linear-gradient(to right, #999999, #330867); } .login-wrapper { background-color: bisque; width: 358px; height: 588px; border-radius: 15px; padding: 0 50px; position: relative; left: 50%; top: 50%; transform: translate(-50%,-50%); } .header { font-size: 38px; font-weight: bold; text-align: center; line-height: 200px; } .input-item { display: block; width: 100%; margin-bottom: 20px; border: 0; padding: 10px; border-bottom: 1px solid rgb(128,125,125); font-size: 15px; outline: none; } .input-item::placeholder { text-transform: uppercase; } .btn { text-align: center; padding: 10px; width: 100%; margin-top: 40px; background-image: linear-gradient(to right,#a6c1ee, #fbc2eb); color: #fff; } .msg { text-align: center; line-height: 88px; } a { text-decoration-line: none; color: #abc1ee; } </style> </head> <body> <div class="container"> <div class="login-wrapper"> <form action="/register/" method="post"> <div class="header">Register</div> <div class="form-wrapper"> <input type="text" name="username" placeholder="username" class="input-item"> <input type="password" name="password" placeholder="password" class="input-item"> <!-- <a href="{{url_for('my_login')}}"><div class="btn">Submit</div></a> --> {% if error %} <font color="red">{{ error }}</font> {% endif %} <input class="btn" type="submit" value="Submit"> </div> </form> </div> </div> </body> </html>
2.3训练模型模块
2.3.1导入数据
manager.py
@app.route('/load_data') def load_data(): return render_template('load_data.html')
load_data.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>导入数据</title> <link rel="stylesheet" href="../static/bootstrap.min.css"> <link rel="stylesheet" href="../static/main.css"> </head> <body> <div class="container-fluid"> <div class="row"> <div class="col-xl-2"> <div class="top" style="margin-top: 40px;margin-left: 40px;"> <ul class="nav flex-column"> <li class="nav-item" > <a class="nav-link" href="" > <button type="button" class="btn btn-outline-primary" disabled>1.导入数据</button> </a> </li> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-down" viewBox="0 0 16 16" style="margin-left: 60px;"> <path fill-rule="evenodd" d="M8 1a.5.5 0 0 1 .5.5v11.793l3.146-3.147a.5.5 0 0 1 .708.708l-4 4a.5.5 0 0 1-.708 0l-4-4a.5.5 0 0 1 .708-.708L7.5 13.293V1.5A.5.5 0 0 1 8 1z"/> </svg> <li class="nav-item" > <a class="nav-link" href="{{url_for('see_data')}}"> <button type="button" class="btn btn-outline-primary">2.查看数据</button> </a> </li> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-down" viewBox="0 0 16 16" style="margin-left: 60px;"> <path fill-rule="evenodd" d="M8 1a.5.5 0 0 1 .5.5v11.793l3.146-3.147a.5.5 0 0 1 .708.708l-4 4a.5.5 0 0 1-.708 0l-4-4a.5.5 0 0 1 .708-.708L7.5 13.293V1.5A.5.5 0 0 1 8 1z"/> </svg> <li class="nav-item" > <a class="nav-link" href=""> <button type="button" class="btn btn-outline-primary" disabled>3.数据预处理</button> </a> </li> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-down" viewBox="0 0 16 16" style="margin-left: 60px;"> <path fill-rule="evenodd" d="M8 1a.5.5 0 0 1 .5.5v11.793l3.146-3.147a.5.5 0 0 1 .708.708l-4 4a.5.5 0 0 1-.708 0l-4-4a.5.5 0 0 1 .708-.708L7.5 13.293V1.5A.5.5 0 0 1 8 1z"/> </svg> <li class="nav-item" > <a class="nav-link" href=""> <button type="button" class="btn btn-outline-primary" disabled>4.数据可视化</button> </a> </li> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-down" viewBox="0 0 16 16" style="margin-left: 60px;"> <path fill-rule="evenodd" d="M8 1a.5.5 0 0 1 .5.5v11.793l3.146-3.147a.5.5 0 0 1 .708.708l-4 4a.5.5 0 0 1-.708 0l-4-4a.5.5 0 0 1 .708-.708L7.5 13.293V1.5A.5.5 0 0 1 8 1z"/> </svg> <li class="nav-item" > <a class="nav-link" href=""> <button type="button" class="btn btn-outline-primary" disabled>5.特征工程</button> </a> </li> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-down" viewBox="0 0 16 16" style="margin-left: 60px;"> <path fill-rule="evenodd" d="M8 1a.5.5 0 0 1 .5.5v11.793l3.146-3.147a.5.5 0 0 1 .708.708l-4 4a.5.5 0 0 1-.708 0l-4-4a.5.5 0 0 1 .708-.708L7.5 13.293V1.5A.5.5 0 0 1 8 1z"/> </svg> <li class="nav-item" > <a class="nav-link" href=""> <button type="button" class="btn btn-outline-primary" disabled>6.构建模型</button> </a> </li> </li> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-down" viewBox="0 0 16 16" style="margin-left: 60px;"> <path fill-rule="evenodd" d="M8 1a.5.5 0 0 1 .5.5v11.793l3.146-3.147a.5.5 0 0 1 .708.708l-4 4a.5.5 0 0 1-.708 0l-4-4a.5.5 0 0 1 .708-.708L7.5 13.293V1.5A.5.5 0 0 1 8 1z"/> </svg> <li class="nav-item" > <a class="nav-link" href=""> <button type="button" class="btn btn-outline-primary" disabled>7.保存模型</button> </a> </li> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-down" viewBox="0 0 16 16" style="margin-left: 60px;"> <path fill-rule="evenodd" d="M8 1a.5.5 0 0 1 .5.5v11.793l3.146-3.147a.5.5 0 0 1 .708.708l-4 4a.5.5 0 0 1-.708 0l-4-4a.5.5 0 0 1 .708-.708L7.5 13.293V1.5A.5.5 0 0 1 8 1z"/> </svg> <li class="nav-item" > <a class="nav-link" href="{{url_for('index')}}"> <button type="button" class="btn btn-outline-primary" disabled>返回首页</button> </a> </li> </ul> </div> </div> <div class="col-xl-10" style="margin-top: 10px;"> <div class="card"> <div class="card-body"> <div class="card-body"> <img src="../static/img/load_data.png" width="1160px"> <br> <br> <p>导入数据成功!!!</p> </div> </div> </div> </div> </div> </div> </body> </html>
2.3.2查看数据
manager.py
@app.route('/see_data') def see_data(): return render_template('see_data.html')
see_data.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>查看数据</title> <link rel="stylesheet" href="../static/bootstrap.min.css"> <link rel="stylesheet" href="../static/main.css"> </head> <body> <div class="container-fluid"> <div class="row"> <div class="col-xl-2"> <div class="top" style="margin-top: 40px;margin-left: 40px;"> <ul class="nav flex-column"> <li class="nav-item" > <a class="nav-link" href="" > <button type="button" class="btn btn-outline-primary" disabled>1.导入数据</button> </a> </li> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-down" viewBox="0 0 16 16" style="margin-left: 60px;"> <path fill-rule="evenodd" d="M8 1a.5.5 0 0 1 .5.5v11.793l3.146-3.147a.5.5 0 0 1 .708.708l-4 4a.5.5 0 0 1-.708 0l-4-4a.5.5 0 0 1 .708-.708L7.5 13.293V1.5A.5.5 0 0 1 8 1z"/> </svg> <li class="nav-item" > <a class="nav-link" href=""> <button type="button" class="btn btn-outline-primary" disabled>2.查看数据</button> </a> </li> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-down" viewBox="0 0 16 16" style="margin-left: 60px;"> <path fill-rule="evenodd" d="M8 1a.5.5 0 0 1 .5.5v11.793l3.146-3.147a.5.5 0 0 1 .708.708l-4 4a.5.5 0 0 1-.708 0l-4-4a.5.5 0 0 1 .708-.708L7.5 13.293V1.5A.5.5 0 0 1 8 1z"/> </svg> <li class="nav-item" > <a class="nav-link" href="{{url_for('dispose_data')}}"> <button type="button" class="btn btn-outline-primary">3.数据预处理</button> </a> </li> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-down" viewBox="0 0 16 16" style="margin-left: 60px;"> <path fill-rule="evenodd" d="M8 1a.5.5 0 0 1 .5.5v11.793l3.146-3.147a.5.5 0 0 1 .708.708l-4 4a.5.5 0 0 1-.708 0l-4-4a.5.5 0 0 1 .708-.708L7.5 13.293V1.5A.5.5 0 0 1 8 1z"/> </svg> <li class="nav-item" > <a class="nav-link" href=""> <button type="button" class="btn btn-outline-primary" disabled>4.数据可视化</button> </a> </li> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-down" viewBox="0 0 16 16" style="margin-left: 60px;"> <path fill-rule="evenodd" d="M8 1a.5.5 0 0 1 .5.5v11.793l3.146-3.147a.5.5 0 0 1 .708.708l-4 4a.5.5 0 0 1-.708 0l-4-4a.5.5 0 0 1 .708-.708L7.5 13.293V1.5A.5.5 0 0 1 8 1z"/> </svg> <li class="nav-item" > <a class="nav-link" href=""> <button type="button" class="btn btn-outline-primary" disabled>5.特征工程</button> </a> </li> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-down" viewBox="0 0 16 16" style="margin-left: 60px;"> <path fill-rule="evenodd" d="M8 1a.5.5 0 0 1 .5.5v11.793l3.146-3.147a.5.5 0 0 1 .708.708l-4 4a.5.5 0 0 1-.708 0l-4-4a.5.5 0 0 1 .708-.708L7.5 13.293V1.5A.5.5 0 0 1 8 1z"/> </svg> <li class="nav-item" > <a class="nav-link" href=""> <button type="button" class="btn btn-outline-primary" disabled>6.构建模型</button> </a> </li> </li> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-down" viewBox="0 0 16 16" style="margin-left: 60px;"> <path fill-rule="evenodd" d="M8 1a.5.5 0 0 1 .5.5v11.793l3.146-3.147a.5.5 0 0 1 .708.708l-4 4a.5.5 0 0 1-.708 0l-4-4a.5.5 0 0 1 .708-.708L7.5 13.293V1.5A.5.5 0 0 1 8 1z"/> </svg> <li class="nav-item" > <a class="nav-link" href=""> <button type="button" class="btn btn-outline-primary" disabled>7.保存模型</button> </a> </li> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-down" viewBox="0 0 16 16" style="margin-left: 60px;"> <path fill-rule="evenodd" d="M8 1a.5.5 0 0 1 .5.5v11.793l3.146-3.147a.5.5 0 0 1 .708.708l-4 4a.5.5 0 0 1-.708 0l-4-4a.5.5 0 0 1 .708-.708L7.5 13.293V1.5A.5.5 0 0 1 8 1z"/> </svg> <li class="nav-item" > <a class="nav-link" href="{{url_for('index')}}"> <button type="button" class="btn btn-outline-primary" disabled>返回首页</button> </a> </li> </ul> </div> </div> <div class="col-xl-10" style="margin-top: 10px;"> <div class="card"> <div class="card-body"> <p>数据大小为:(1500,13)</p> <p>数据基本信息为:</p> <img src="../static/img/see_data1.png"> <br> <br> <p>数值型数据描述为:</p> <img src="../static/img/see_data2.png"> <br> <br> <p>非数值型数据描述为:</p> <br> <img src="../static/img/see_data3.png"> </div> </div> </div> </div> </div> </body> </html>
2.3.3数据预处理
manager.py
@app.route('/dispose_data') def dispose_data(): return render_template('dispose_data.html')
dispose_data.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>数据预处理</title> <link rel="stylesheet" href="../static/bootstrap.min.css"> <link rel="stylesheet" href="../static/main.css"> </head> <body> <div class="container-fluid"> <div class="row"> <div class="col-xl-2"> <div class="top" style="margin-top: 40px;margin-left: 40px;"> <ul class="nav flex-column"> <li class="nav-item" > <a class="nav-link" href="" > <button type="button" class="btn btn-outline-primary" disabled>1.导入数据</button> </a> </li> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-down" viewBox="0 0 16 16" style="margin-left: 60px;"> <path fill-rule="evenodd" d="M8 1a.5.5 0 0 1 .5.5v11.793l3.146-3.147a.5.5 0 0 1 .708.708l-4 4a.5.5 0 0 1-.708 0l-4-4a.5.5 0 0 1 .708-.708L7.5 13.293V1.5A.5.5 0 0 1 8 1z"/> </svg> <li class="nav-item" > <a class="nav-link" href=""> <button type="button" class="btn btn-outline-primary" disabled>2.查看数据</button> </a> </li> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-down" viewBox="0 0 16 16" style="margin-left: 60px;"> <path fill-rule="evenodd" d="M8 1a.5.5 0 0 1 .5.5v11.793l3.146-3.147a.5.5 0 0 1 .708.708l-4 4a.5.5 0 0 1-.708 0l-4-4a.5.5 0 0 1 .708-.708L7.5 13.293V1.5A.5.5 0 0 1 8 1z"/> </svg> <li class="nav-item" > <a class="nav-link" href=""> <button type="button" class="btn btn-outline-primary" disabled>3.数据预处理</button> </a> </li> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-down" viewBox="0 0 16 16" style="margin-left: 60px;"> <path fill-rule="evenodd" d="M8 1a.5.5 0 0 1 .5.5v11.793l3.146-3.147a.5.5 0 0 1 .708.708l-4 4a.5.5 0 0 1-.708 0l-4-4a.5.5 0 0 1 .708-.708L7.5 13.293V1.5A.5.5 0 0 1 8 1z"/> </svg> <li class="nav-item" > <a class="nav-link" href="{{url_for('display_data')}}"> <button type="button" class="btn btn-outline-primary" >4.数据可视化</button> </a> </li> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-down" viewBox="0 0 16 16" style="margin-left: 60px;"> <path fill-rule="evenodd" d="M8 1a.5.5 0 0 1 .5.5v11.793l3.146-3.147a.5.5 0 0 1 .708.708l-4 4a.5.5 0 0 1-.708 0l-4-4a.5.5 0 0 1 .708-.708L7.5 13.293V1.5A.5.5 0 0 1 8 1z"/> </svg> <li class="nav-item" > <a class="nav-link" href=""> <button type="button" class="btn btn-outline-primary" disabled>5.特征工程</button> </a> </li> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-down" viewBox="0 0 16 16" style="margin-left: 60px;"> <path fill-rule="evenodd" d="M8 1a.5.5 0 0 1 .5.5v11.793l3.146-3.147a.5.5 0 0 1 .708.708l-4 4a.5.5 0 0 1-.708 0l-4-4a.5.5 0 0 1 .708-.708L7.5 13.293V1.5A.5.5 0 0 1 8 1z"/> </svg> <li class="nav-item" > <a class="nav-link" href=""> <button type="button" class="btn btn-outline-primary" disabled>6.构建模型</button> </a> </li> </li> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-down" viewBox="0 0 16 16" style="margin-left: 60px;"> <path fill-rule="evenodd" d="M8 1a.5.5 0 0 1 .5.5v11.793l3.146-3.147a.5.5 0 0 1 .708.708l-4 4a.5.5 0 0 1-.708 0l-4-4a.5.5 0 0 1 .708-.708L7.5 13.293V1.5A.5.5 0 0 1 8 1z"/> </svg> <li class="nav-item" > <a class="nav-link" href=""> <button type="button" class="btn btn-outline-primary" disabled>7.保存模型</button> </a> </li> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-down" viewBox="0 0 16 16" style="margin-left: 60px;"> <path fill-rule="evenodd" d="M8 1a.5.5 0 0 1 .5.5v11.793l3.146-3.147a.5.5 0 0 1 .708.708l-4 4a.5.5 0 0 1-.708 0l-4-4a.5.5 0 0 1 .708-.708L7.5 13.293V1.5A.5.5 0 0 1 8 1z"/> </svg> <li class="nav-item" > <a class="nav-link" href="{{url_for('index')}}"> <button type="button" class="btn btn-outline-primary" disabled>返回首页</button> </a> </li> </ul> </div> </div> <div class="col-xl-10"> <div class="card" style="margin-top: 20px;"> <div class="card-body"> <p>查看数据缺失值情况:</p> <img src="../static/img/dispose_data.png"> <br> <br> <p>检测数据是否存在重复值:True</p> <p>删除重复值前的数据的大小:(1500,13)</p> <p>删除重复值后的数据的大小:(1445,13)</p> <p>数据预处理完毕!!!</p> </div> </div> </div> </div> </div> </body> </html>
基于Flask+Bootstrap+机器学习的南昌市租房价格预测系统(下):https://developer.aliyun.com/article/1434868