-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathapp.py
201 lines (167 loc) · 7.58 KB
/
app.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
import logging.config
import pandas as pd
import pickle
import traceback
from flask import render_template, request, redirect, url_for
import logging.config
from flask import Flask
from src.customer_db import Customer
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__, template_folder="app/templates")
rf = pickle.load(open('models/rf.pkl', 'rb'))
from src.helper import make_ingest_df
from src.customer_db import ingest_db
app.config.from_pyfile('config/flaskconfig.py')
logging.config.fileConfig(app.config["LOGGING_CONFIG"])
logger = logging.getLogger(app.config["APP_NAME"])
logger.debug('Test log')
# Initialize the database
db = SQLAlchemy(app)
@app.route('/')
def home():
return render_template('index.html')
@app.route('/database')
def database():
"""Main view that lists customers and their predicted outcome of churning in the database.
Create view into index page that uses data queried from Customer database and
inserts it into the app/templates/index.html template.
Returns: rendered html template
"""
try:
customers = db.session.query(Customer).limit(app.config["MAX_ROWS_SHOW"]).all()
logger.debug("databse page accessed")
return render_template('show_db.html', customers=customers)
except:
traceback.print_exc()
logger.warning("Not able to display customers, error page returned")
return render_template('error.html')
@app.route('/predict', methods=['POST'])
def predict():
# get user inputs for binary features
SeniorCitizen = 'No'
if 'SeniorCitizen' in request.form:
SeniorCitizen = 'Yes'
logger.info('SeniorCitizen: ' + SeniorCitizen)
Partner = 'No'
if 'Partner' in request.form:
Partner = 'Yes'
logger.info('Partner: ' + Partner)
Dependents = 'No'
if 'Dependents' in request.form:
Dependents = 'Yes'
logger.info('Dependents: ' + Dependents)
PhoneService = 'No'
if 'PhoneService' in request.form:
PhoneService = 'Yes'
logger.info('PhoneService: ' + PhoneService)
OnlineSecurity = 'No'
if 'OnlineSecurity' in request.form:
OnlineSecurity = 'Yes'
logger.info('OnlineSecurity: ' + OnlineSecurity)
OnlineBackup = 'No'
if 'OnlineBackup' in request.form:
OnlineBackup = 'Yes'
logger.info('OnlineBackup: ' + OnlineBackup)
DeviceProtection = 'No'
if 'DeviceProtection' in request.form:
DeviceProtection = 'Yes'
logger.info('DeviceProtection: ' + DeviceProtection)
TechSupport = 'No'
if 'TechSupport' in request.form:
TechSupport = 'Yes'
logger.info('TechSupport: ' + TechSupport)
StreamingTV = 'No'
if 'StreamingTV' in request.form:
StreamingTV = 'Yes'
logger.info('StreamingTV: ' + StreamingTV)
StreamingMovies = 'No'
if 'StreamingMovies' in request.form:
StreamingMovies = 'Yes'
logger.info('StreamingMovies: ' + StreamingMovies)
PaperlessBilling = 'No'
if 'PaperlessBilling' in request.form:
PaperlessBilling = 'Yes'
logger.info('PaperlessBilling: ' + PaperlessBilling)
# get user inputs for numeric features
Tenure = float(request.form["Tenure"])
logger.info('Tenure: ' + str(Tenure))
MonthlyCharges = float(request.form["MonthlyCharges"])
logger.info('MonthlyCharges: ' + str(MonthlyCharges))
TotalCharges = float(request.form["TotalCharges"])
logger.info('TotalCharges: ' + str(TotalCharges))
# get user inputs for multi-category features
Gender = 'Female'
if request.form["Gender"] == '1':
Gender = 'Male'
logger.info('Gender: ' + Gender)
MultipleLines = 'No'
if request.form["MultipleLines"] == '1':
MultipleLines = 'Yes'
elif request.form["MultipleLines"] == '2':
MultipleLines = 'No phone service'
logger.info('MultipleLines: ' + MultipleLines)
InternetService = 'No'
if request.form["InternetService"] == '1':
InternetService = 'DSL'
elif request.form["InternetService"] == '2':
InternetService = 'Fiber optic'
logger.info('InternetService: ' + InternetService)
Contract = 'Month-to-month'
if request.form["Contract"] == '1':
Contract = 'One year'
elif request.form["Contract"] == '2':
Contract = 'Two year'
logger.info('contact: ' + Contract)
PaymentMethod = 'Electronic check'
if request.form["PaymentMethod"] == '1':
PaymentMethod = 'Mailed check'
elif request.form["PaymentMethod"] == '2':
PaymentMethod = 'Bank transfer (automatic)'
elif request.form["PaymentMethod"] == '3':
PaymentMethod = 'Credit card (automatic)'
logger.info('PaymentMethod: ' + PaymentMethod)
# combine user inputs into a pandas dataframe for
values = [Gender, SeniorCitizen, Partner, Dependents, Tenure, PhoneService, OnlineSecurity, OnlineBackup,
DeviceProtection, TechSupport, StreamingTV, StreamingMovies, PaperlessBilling, MonthlyCharges,
TotalCharges, MultipleLines, InternetService, Contract, PaymentMethod]
cols = ['Gender', 'SeniorCitizen', 'Partner', 'Dependents', 'Tenure', 'PhoneService', 'OnlineSecurity',
'OnlineBackup',
'DeviceProtection', 'TechSupport', 'StreamingTV', 'StreamingMovies', 'PaperlessBilling', 'MonthlyCharges',
'TotalCharges', 'MultipleLines', 'InternetService', 'Contract', 'PaymentMethod']
# combine user inputs to a data frame
preprocessed_df = pd.DataFrame(data=[values], columns=cols)
logger.info('User input has been retrieved.')
# use random forest model to make prediction
ingest_df = make_ingest_df(rf, preprocessed_df)
output = ingest_df.PredProbability[0]
logger.info('The predicted probability of churn for the given customer is: ' + str(output))
# ingest this record to the customer database
ingest_db(ingest_df, db.get_engine())
logger.info('User input and the corresponding predictions haven been added to the database.')
# process outputs necessary for rendering the html file
user_input_str = preprocessed_df.T.reset_index().rename(columns={'index': 'Features', 0: 'Values'}).to_html()
# different suggested offer for different predicted probability
if output > 0.75:
progress_bar_class = "progress-bar progress-bar-danger"
recommendation = 'This customer has a high risk of churning. The recommended offer is to lower fees for 6 ' \
'months.'
elif output > 0.50:
progress_bar_class = "progress-bar progress-bar-warning"
recommendation = 'This customer has a moderate risk of churning. The recommended offer is to lower fees for 3' \
' months.'
elif output > 0.25:
progress_bar_class = "progress-bar progress-bar-info"
recommendation = 'This customer has a low risk of churning. The recommended offer is to lower fees for 1 month.'
else:
progress_bar_class = "progress-bar progress-bar-success"
recommendation = 'This customer is not at risk. No action is needed.'
return render_template('index.html',
tables=user_input_str,
proba=round(output, 5),
percent=100 * output,
progress_bar_class=progress_bar_class,
rec=recommendation,
prediction_text='Based on input values, the random forest model predicts that the '
'probability this customer will churn is: {}'.format(round(output, 5)))
if __name__ == '__main__':
app.run(debug=app.config["DEBUG"], port=app.config["PORT"], host=app.config["HOST"])