-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapp.py
More file actions
234 lines (178 loc) · 8 KB
/
Copy pathapp.py
File metadata and controls
234 lines (178 loc) · 8 KB
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
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
import pandas as pd
import io
import requests
import json
from flask import Flask, request, jsonify, make_response
from flask_restful import Api, Resource, reqparse
from flask_cors import CORS, cross_origin
from sklearn.preprocessing import MinMaxScaler
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
from sklearn import metrics
'''
Function to get all the data from the github repo
and prepare it, by cleaning categorical data from
it and eliminating part of the geolocation data
'''
def get_data():
#Get the data from the githun root folder and turn it into JSON format
with open("Data/hexagon_collection_master.geojson") as jsonFile:
data = json.loads(jsonFile.read())
#Get all the features from the JSON data
features = [f["properties"] for f in data["features"]]
#Turn all the data into a pandas data frame
df = pd.DataFrame.from_records(features)
#List of columns to exclude
columns_to_exclude = ['id', 'top', 'right', 'bottom',"predominant_race_by_population_per_cell"]
#Find all the columns that contain the word "name" / Find all columns with categorical data with "Name"
withName = [i for i in df.columns if "name" in i]
#Merge found columns with existing list
columns_to_exclude = columns_to_exclude + withName
#Drop the excluded columns from the main data frame
clean_data_frame = df.drop(columns_to_exclude,axis=1)
#Convert data frame to JSON format
clean_data_frame_JSON = clean_data_frame.to_json()
#For debugging
#print(clean_data_frame)
return clean_data_frame_JSON
'''
Function to generate a set of cluster based on the desired
attributes and selected number of clusters
'''
def kmeans_cluster_generator(data,features=None,n_clusters=5):
#Convert the json data into a pandas data frame
data_frame = pd.read_json(data)
fid_column = data_frame['fid']
#Generate normalization of values from 0 to 1
min_max_scaler = MinMaxScaler()
#Normalize all the values in data set to fit between 0 to 1
data_frame[data_frame.columns] = min_max_scaler.fit_transform(data_frame)
#Get all the features in the data set
if features:
data_frame = data_frame[features]
#Based on the number of clusters selected find kmeans
kmeans = KMeans(n_clusters=n_clusters,random_state=23)
#Fit the data to generate clusters based on selected attributes
kmeans = kmeans.fit(data_frame)
#Get the newly made clusters
clusters = kmeans.labels_
#Get and store the distance to each cluster centroid
#Note: kmeans.transforms returns the distance to all the cluster centroids the for loop is to get the distance to the assigned cluster
distance_to_cluster_centroid = []
for i in range(len(kmeans.transform(data_frame))):
#For debugging
#print (kmeans.transform(data_frame)[i][kmeans.labels_[i]])
distance_to_cluster_centroid.append(kmeans.transform(data_frame)[i][kmeans.labels_[i]])
#Add newly labels for the cluster data to original data frame an re-add fid column
data_frame['fid'] = fid_column
data_frame["clusters"] = clusters
data_frame['distance_to_cluster_centroid'] = distance_to_cluster_centroid
#Convert data frame into json format
clean_data = data_frame.to_json(orient='index')
parsed = json.loads(clean_data)
#Remap the keys of the json format to be the fid of the hexagon cells
stored_data = []
for data in range(len(parsed)):
all_the_data = parsed[str(data)]
stored_data.append(all_the_data)
#Organize the data into a dictionary
lean_data = {int(key):value for key,value in zip(fid_column,stored_data)}
'''
Example of data structure
Data is organized by hexagonal grid cell which contains all the information
that was requested for the clustes, additional to the cluster number,
and the distance from the cluster centroid
"1": {
"adult_obesity": 0.3087912088,
"clusters": 0,
"distance_to_cluster_centroid": 0.13183805,
"fid": 1,
"nearest_hospital_distance": 0.0880002894,
"population_no_health_insurance": 0.5324675325
},
'''
return lean_data
'''
Function to find the optimal number of clusters
based on the selected features
'''
def kmeans_silouhette_method_optimun_cluster_number(data,features=None):
#Convert the json data into a pandas data frame
data_frame = pd.read_json(data)
fid_column = data_frame['fid']
#Generate normalization of values from 0 to 1
min_max_scaler = MinMaxScaler()
#Normalize all the values in data set to fit between 0 to 1
data_frame[data_frame.columns] = min_max_scaler.fit_transform(data_frame)
#Get all the features in the data set
if features:
data_frame = data_frame[features]
standarized_data = StandardScaler().fit_transform(data_frame)
#Lists to store scores to determine optimal cluster
sum_of_squared_distances = []
CH_scores = []
models = []
#Loop to generates cluster and find the optimal number, ranging from 2 to 7
K = range(2,7)
for k in K:
k_means = KMeans(n_clusters=k)
model = k_means.fit(standarized_data)
models.append(model)
sum_of_squared_distances.append(k_means.inertia_)
labels = k_means.labels_
CV_score = metrics.silhouette_score(standarized_data, labels, metric = 'euclidean')
CH_score = metrics.calinski_harabasz_score(standarized_data, labels)
CH_scores.append(CH_score)
highest_CH_score = max(CH_scores)
maxChScoreIndex = CH_scores.index(highest_CH_score)
modelChoice = models[maxChScoreIndex]
ideal_cluster_number = maxChScoreIndex + 2
#For debugging
print(ideal_cluster_number)
#Run kmeans clustering function to generate clusters, based on the optimal number for the selected features
cluster_data = kmeans_cluster_generator(data,features,ideal_cluster_number)
return cluster_data
#Creation of the Flask Application
app = Flask(__name__,static_folder='./MedLoc/build', static_url_path='/')
api = Api(app)
CORS(app,support_credentials=True)
#List of required arguments
cluster_post_arguments = reqparse.RequestParser()
cluster_post_arguments.add_argument("data", type=str)
cluster_post_arguments.add_argument("selected features", type=str, action='append', default=[])
cluster_post_arguments.add_argument("number of clusters", type=int)
#The set of request for the APi begin here
#Initial web request
@app.route('/',methods=['POST', 'GET', 'OPTIONS'])
@cross_origin(supports_credentials=True)
def index():
return app.send_static_file('index.html')
#POST request to get the clusters for the data based on the siluhette method to get the optimal number
@app.route('/get_kmeans_silouhette_optimun_cluster_number/', methods=['POST'])
def kmeans_silouhette_cluster_number():
#Get the data from the hexagon_collection_master document in the root folder to the Github
data = get_data()
#Define and get arguments from request
arguments = cluster_post_arguments.parse_args()
selected_attributes = arguments['selected features']
#Function to get the ideal cluster
ideal_cluster_number = kmeans_silouhette_method_optimun_cluster_number(data, selected_attributes)
return ideal_cluster_number
#POST reuqest to get the set of cluster based on user input
@app.route('/get_kmeans_cluster/', methods=['POST'])
def post_kmeans_cluster():
#Get the data from the hexagon_collection_master document in the root folder to the Github
data = get_data()
#Define and get arguments from request
arguments = cluster_post_arguments.parse_args()
selected_attributes = arguments['selected features']
number_of_cluster = arguments['number of clusters']
#Run Kmeans cluster algorithm
cluster_data = kmeans_cluster_generator(data, selected_attributes, number_of_cluster)
#For debuging
#print(cluster_data)
return cluster_data
#Run the API
#Turn debug=False when deploying to the web / For more information look at Flask lib.
if __name__ == "__main__":
app.run(debug=True)