stubs in kmeans non-spatial
This commit is contained in:
@@ -44,8 +44,15 @@ class AnalysisDataProvider:
|
|||||||
plpy.error('Analysis failed: %s' % e)
|
plpy.error('Analysis failed: %s' % e)
|
||||||
return pu.empty_zipped_array(2)
|
return pu.empty_zipped_array(2)
|
||||||
|
|
||||||
def get_nonspatial_kmeans(self, query):
|
def get_nonspatial_kmeans(self, params):
|
||||||
"""fetch data for non-spatial kmeans"""
|
"""fetch data for non-spatial kmeans"""
|
||||||
|
query = '''
|
||||||
|
SELECT {cols}, array_agg({id_col}) As rowid
|
||||||
|
FROM ({subquery}) As a
|
||||||
|
'''.format(subquery=subquery,
|
||||||
|
id_col=id_col,
|
||||||
|
cols=', '.join(['array_agg({0}) As arr_{0}'.format(c)
|
||||||
|
for c in params[colnames]]))
|
||||||
try:
|
try:
|
||||||
data = plpy.execute(query)
|
data = plpy.execute(query)
|
||||||
return data
|
return data
|
||||||
|
|||||||
@@ -30,3 +30,75 @@ class Kmeans:
|
|||||||
km = KMeans(n_clusters=no_clusters, n_init=no_init)
|
km = KMeans(n_clusters=no_clusters, n_init=no_init)
|
||||||
labels = km.fit_predict(zip(xs, ys))
|
labels = km.fit_predict(zip(xs, ys))
|
||||||
return zip(ids, labels)
|
return zip(ids, labels)
|
||||||
|
|
||||||
|
def nonspatial(self, subquery, colnames, num_clusters=5,
|
||||||
|
id_col='cartodb_id', standarize=True):
|
||||||
|
"""
|
||||||
|
query (string): A SQL query to retrieve the data required to do the
|
||||||
|
k-means clustering analysis, like so:
|
||||||
|
SELECT * FROM iris_flower_data
|
||||||
|
colnames (list): a list of the column names which contain the data
|
||||||
|
of interest, like so: ["sepal_width",
|
||||||
|
"petal_width",
|
||||||
|
"sepal_length",
|
||||||
|
"petal_length"]
|
||||||
|
num_clusters (int): number of clusters (greater than zero)
|
||||||
|
id_col (string): name of the input id_column
|
||||||
|
"""
|
||||||
|
import json
|
||||||
|
from sklearn import metrics
|
||||||
|
|
||||||
|
out_id_colname = 'rowids'
|
||||||
|
# TODO: need a random seed?
|
||||||
|
params = {"cols": colnames,
|
||||||
|
"subquery": subquery,
|
||||||
|
"id_col": id_col}
|
||||||
|
|
||||||
|
data = self.query_runner.get_nonspatial_kmeans(params, standarize)
|
||||||
|
|
||||||
|
# fill array with values for k-means clustering
|
||||||
|
if standarize:
|
||||||
|
cluster_columns = _scale_data(
|
||||||
|
_extract_columns(data, colnames))
|
||||||
|
else:
|
||||||
|
cluster_columns = _extract_columns(data, colnames)
|
||||||
|
|
||||||
|
print str(cluster_columns)
|
||||||
|
# TODO: decide on optimal parameters for most cases
|
||||||
|
# Are there ways of deciding parameters based on inputs?
|
||||||
|
kmeans = KMeans(n_clusters=num_clusters,
|
||||||
|
random_state=0).fit(cluster_columns)
|
||||||
|
|
||||||
|
centers = [json.dumps(dict(zip(colnames, c)))
|
||||||
|
for c in kmeans.cluster_centers_[kmeans.labels_]]
|
||||||
|
|
||||||
|
silhouettes = metrics.silhouette_samples(cluster_columns,
|
||||||
|
kmeans.labels_,
|
||||||
|
metric='sqeuclidean')
|
||||||
|
|
||||||
|
return zip(kmeans.labels_,
|
||||||
|
centers,
|
||||||
|
silhouettes,
|
||||||
|
data[0][out_id_colname])
|
||||||
|
|
||||||
|
|
||||||
|
# -- Preprocessing steps
|
||||||
|
|
||||||
|
def _extract_columns(data, colnames):
|
||||||
|
"""
|
||||||
|
Extract the features from the query and pack them into a NumPy array
|
||||||
|
data (list of dicts): result of the kmeans request
|
||||||
|
id_col_name (string): name of column which has the row id (not a
|
||||||
|
feature of the analysis)
|
||||||
|
"""
|
||||||
|
return np.array([data[0]['arr_{}'.format(c)] for c in colnames],
|
||||||
|
dtype=float).T
|
||||||
|
|
||||||
|
|
||||||
|
def _scale_data(features):
|
||||||
|
"""
|
||||||
|
Scale all input columns to center on 0 with a standard devation of 1
|
||||||
|
features (numpy matrix): features of dimension (n_features, n_samples)
|
||||||
|
"""
|
||||||
|
from sklearn.preprocessing import StandardScaler
|
||||||
|
return StandardScaler().fit_transform(features)
|
||||||
|
|||||||
Reference in New Issue
Block a user