move to class-based module

This commit is contained in:
Andy Eschbacher 2016-11-18 17:46:55 +00:00
parent a8bd122762
commit 2738c1f29c
2 changed files with 151 additions and 167 deletions

View File

@ -10,9 +10,11 @@ CREATE OR REPLACE FUNCTION
id_col TEXT DEFAULT 'cartodb_id') id_col TEXT DEFAULT 'cartodb_id')
RETURNS TABLE (moran NUMERIC, significance NUMERIC) RETURNS TABLE (moran NUMERIC, significance NUMERIC)
AS $$ AS $$
from crankshaft.clustering import moran from crankshaft.clustering import Moran
# TODO: use named parameters or a dictionary # TODO: use named parameters or a dictionary
return moran(subquery, column_name, w_type, num_ngbrs, permutations, geom_col, id_col) moran = Moran()
return moran.global_stat(subquery, column_name, w_type,
num_ngbrs, permutations, geom_col, id_col)
$$ LANGUAGE plpythonu; $$ LANGUAGE plpythonu;
-- Moran's I Local (internal function) -- Moran's I Local (internal function)
@ -27,9 +29,11 @@ CREATE OR REPLACE FUNCTION
id_col TEXT) id_col TEXT)
RETURNS TABLE (moran NUMERIC, quads TEXT, significance NUMERIC, rowid INT, vals NUMERIC) RETURNS TABLE (moran NUMERIC, quads TEXT, significance NUMERIC, rowid INT, vals NUMERIC)
AS $$ AS $$
from crankshaft.clustering import moran_local from crankshaft.clustering import Moran
moran = Moran()
# TODO: use named parameters or a dictionary # TODO: use named parameters or a dictionary
return moran_local(subquery, column_name, w_type, num_ngbrs, permutations, geom_col, id_col) return moran.local_stat(subquery, column_name, w_type,
num_ngbrs, permutations, geom_col, id_col)
$$ LANGUAGE plpythonu; $$ LANGUAGE plpythonu;
-- Moran's I Local (public-facing function) -- Moran's I Local (public-facing function)
@ -120,9 +124,11 @@ CREATE OR REPLACE FUNCTION
id_col TEXT DEFAULT 'cartodb_id') id_col TEXT DEFAULT 'cartodb_id')
RETURNS TABLE (moran FLOAT, significance FLOAT) RETURNS TABLE (moran FLOAT, significance FLOAT)
AS $$ AS $$
from crankshaft.clustering import moran_local from crankshaft.clustering import Moran
moran = Moran()
# TODO: use named parameters or a dictionary # TODO: use named parameters or a dictionary
return moran_rate(subquery, numerator, denominator, w_type, num_ngbrs, permutations, geom_col, id_col) return moran.global_rate_stat(subquery, numerator, denominator, w_type,
num_ngbrs, permutations, geom_col, id_col)
$$ LANGUAGE plpythonu; $$ LANGUAGE plpythonu;
@ -140,9 +146,10 @@ CREATE OR REPLACE FUNCTION
RETURNS RETURNS
TABLE(moran NUMERIC, quads TEXT, significance NUMERIC, rowid INT, vals NUMERIC) TABLE(moran NUMERIC, quads TEXT, significance NUMERIC, rowid INT, vals NUMERIC)
AS $$ AS $$
from crankshaft.clustering import moran_local_rate from crankshaft.clustering import Moran
moran = Moran()
# TODO: use named parameters or a dictionary # TODO: use named parameters or a dictionary
return moran_local_rate(subquery, numerator, denominator, w_type, num_ngbrs, permutations, geom_col, id_col) return moran.local_rate_stat(subquery, numerator, denominator, w_type, num_ngbrs, permutations, geom_col, id_col)
$$ LANGUAGE plpythonu; $$ LANGUAGE plpythonu;
-- Moran's I Local Rate (public-facing function) -- Moran's I Local Rate (public-facing function)

View File

@ -15,204 +15,181 @@ import crankshaft.pysal_utils as pu
# High level interface --------------------------------------- # High level interface ---------------------------------------
def moran(subquery, attr_name, class QueryRunner:
w_type, num_ngbrs, permutations, geom_col, id_col): def get_result(self, query):
""" try:
Moran's I (global) data = plpy.execute(query)
Implementation building neighbors with a PostGIS database and Moran's I except plpy.SPIError, err:
core clusters with PySAL. plpy.error("k-means (spatial) cluster analysis failed: %s" % err)
Andy Eschbacher return data
"""
qvals = OrderedDict([("id_col", id_col),
("attr1", attr_name),
("geom_col", geom_col),
("subquery", subquery),
("num_ngbrs", num_ngbrs)])
query = pu.construct_neighbor_query(w_type, qvals)
try:
result = plpy.execute(query)
# if there are no neighbors, exit
if len(result) == 0:
return pu.empty_zipped_array(2)
except plpy.SPIError, e:
plpy.error('Analysis failed: %s' % e)
return pu.empty_zipped_array(2)
# collect attributes
attr_vals = pu.get_attributes(result)
# calculate weights
weight = pu.get_weight(result, w_type, num_ngbrs)
# calculate moran global
moran_global = ps.esda.moran.Moran(attr_vals, weight,
permutations=permutations)
return zip([moran_global.I], [moran_global.EI])
def moran_local(subquery, attr, class Moran:
w_type, num_ngbrs, permutations, geom_col, id_col): def __init__(self, query_runner=None):
""" if query_runner is None:
Moran's I implementation for PL/Python self.query_runner = QueryRunner()
Andy Eschbacher else:
""" self.query_runner = query_runner
# geometries with attributes that are null are ignored def global_stat(self, subquery, attr_name,
# resulting in a collection of not as near neighbors w_type, num_ngbrs, permutations, geom_col, id_col):
"""
Moran's I (global)
Implementation building neighbors with a PostGIS database and Moran's I
core clusters with PySAL.
Andy Eschbacher
"""
qvals = OrderedDict([("id_col", id_col),
("attr1", attr_name),
("geom_col", geom_col),
("subquery", subquery),
("num_ngbrs", num_ngbrs)])
qvals = OrderedDict([("id_col", id_col), query = pu.construct_neighbor_query(w_type, qvals)
("attr1", attr),
("geom_col", geom_col),
("subquery", subquery),
("num_ngbrs", num_ngbrs)])
query = pu.construct_neighbor_query(w_type, qvals) result = self.query_runner.get_result(query)
try: # collect attributes
result = plpy.execute(query) attr_vals = pu.get_attributes(result)
# if there are no neighbors, exit
if len(result) == 0:
return pu.empty_zipped_array(5)
except plpy.SPIError, e:
plpy.error('Analysis failed: %s' % e)
return pu.empty_zipped_array(5)
attr_vals = pu.get_attributes(result) # calculate weights
weight = pu.get_weight(result, w_type, num_ngbrs) weight = pu.get_weight(result, w_type, num_ngbrs)
# calculate LISA values # calculate moran global
lisa = ps.esda.moran.Moran_Local(attr_vals, weight, moran_global = ps.esda.moran.Moran(attr_vals, weight,
permutations=permutations) permutations=permutations)
# find quadrants for each geometry return zip([moran_global.I], [moran_global.EI])
quads = quad_position(lisa.q)
return zip(lisa.Is, quads, lisa.p_sim, weight.id_order, lisa.y) def local_stat(self, subquery, attr,
w_type, num_ngbrs, permutations, geom_col, id_col):
"""
Moran's I implementation for PL/Python
Andy Eschbacher
"""
# geometries with attributes that are null are ignored
# resulting in a collection of not as near neighbors
def moran_rate(subquery, numerator, denominator, qvals = OrderedDict([("id_col", id_col),
w_type, num_ngbrs, permutations, geom_col, id_col): ("attr1", attr),
""" ("geom_col", geom_col),
Moran's I Rate (global) ("subquery", subquery),
Andy Eschbacher ("num_ngbrs", num_ngbrs)])
"""
qvals = OrderedDict([("id_col", id_col),
("attr1", numerator),
("attr2", denominator)
("geom_col", geom_col),
("subquery", subquery),
("num_ngbrs", num_ngbrs)])
query = pu.construct_neighbor_query(w_type, qvals) query = pu.construct_neighbor_query(w_type, qvals)
try: result = self.query_runner.get_result(query)
result = plpy.execute(query)
# if there are no neighbors, exit
if len(result) == 0:
return pu.empty_zipped_array(2)
except plpy.SPIError, e:
plpy.error('Analysis failed: %s' % e)
return pu.empty_zipped_array(2)
# collect attributes attr_vals = pu.get_attributes(result)
numer = pu.get_attributes(result, 1) weight = pu.get_weight(result, w_type, num_ngbrs)
denom = pu.get_attributes(result, 2)
weight = pu.get_weight(result, w_type, num_ngbrs) # calculate LISA values
lisa = ps.esda.moran.Moran_Local(attr_vals, weight,
# calculate moran global rate
lisa_rate = ps.esda.moran.Moran_Rate(numer, denom, weight,
permutations=permutations) permutations=permutations)
return zip([lisa_rate.I], [lisa_rate.EI]) # find quadrants for each geometry
quads = quad_position(lisa.q)
return zip(lisa.Is, quads, lisa.p_sim, weight.id_order, lisa.y)
def moran_local_rate(subquery, numerator, denominator, def global_rate_stat(self, subquery, numerator, denominator,
w_type, num_ngbrs, permutations, geom_col, id_col): w_type, num_ngbrs, permutations, geom_col, id_col):
""" """
Moran's I Local Rate Moran's I Rate (global)
Andy Eschbacher Andy Eschbacher
""" """
# geometries with values that are null are ignored qvals = OrderedDict([("id_col", id_col),
# resulting in a collection of not as near neighbors ("attr1", numerator),
("attr2", denominator)
("geom_col", geom_col),
("subquery", subquery),
("num_ngbrs", num_ngbrs)])
qvals = OrderedDict([("id_col", id_col), query = pu.construct_neighbor_query(w_type, qvals)
("numerator", numerator),
("denominator", denominator),
("geom_col", geom_col),
("subquery", subquery),
("num_ngbrs", num_ngbrs)])
query = pu.construct_neighbor_query(w_type, qvals) result = self.query_runner.get_result(query)
try: # collect attributes
result = plpy.execute(query) numer = pu.get_attributes(result, 1)
# if there are no neighbors, exit denom = pu.get_attributes(result, 2)
if len(result) == 0:
return pu.empty_zipped_array(5)
except plpy.SPIError, e:
plpy.error('Analysis failed: %s' % e)
return pu.empty_zipped_array(5)
# collect attributes weight = pu.get_weight(result, w_type, num_ngbrs)
numer = pu.get_attributes(result, 1)
denom = pu.get_attributes(result, 2)
weight = pu.get_weight(result, w_type, num_ngbrs) # calculate moran global rate
lisa_rate = ps.esda.moran.Moran_Rate(numer, denom, weight,
permutations=permutations)
# calculate LISA values return zip([lisa_rate.I], [lisa_rate.EI])
lisa = ps.esda.moran.Moran_Local_Rate(numer, denom, weight,
permutations=permutations)
# find quadrants for each geometry def local_rate_stat(self, subquery, numerator, denominator,
quads = quad_position(lisa.q) w_type, num_ngbrs, permutations, geom_col, id_col):
"""
Moran's I Local Rate
Andy Eschbacher
"""
# geometries with values that are null are ignored
# resulting in a collection of not as near neighbors
return zip(lisa.Is, quads, lisa.p_sim, weight.id_order, lisa.y) qvals = OrderedDict([("id_col", id_col),
("numerator", numerator),
("denominator", denominator),
("geom_col", geom_col),
("subquery", subquery),
("num_ngbrs", num_ngbrs)])
query = pu.construct_neighbor_query(w_type, qvals)
def moran_local_bv(subquery, attr1, attr2, result = self.query_runner.get_result(query)
permutations, geom_col, id_col, w_type, num_ngbrs):
"""
Moran's I (local) Bivariate (untested)
"""
qvals = OrderedDict([("id_col", id_col), # collect attributes
("attr1", attr1), numer = pu.get_attributes(result, 1)
("attr2", attr2), denom = pu.get_attributes(result, 2)
("geom_col", geom_col),
("subquery", subquery),
("num_ngbrs", num_ngbrs)])
query = pu.construct_neighbor_query(w_type, qvals) weight = pu.get_weight(result, w_type, num_ngbrs)
try: # calculate LISA values
result = plpy.execute(query) lisa = ps.esda.moran.Moran_Local_Rate(numer, denom, weight,
# if there are no neighbors, exit permutations=permutations)
if len(result) == 0:
return pu.empty_zipped_array(4)
except plpy.SPIError:
plpy.error("Error: areas of interest query failed, "
"check input parameters")
return pu.empty_zipped_array(4)
# collect attributes # find quadrants for each geometry
attr1_vals = pu.get_attributes(result, 1) quads = quad_position(lisa.q)
attr2_vals = pu.get_attributes(result, 2)
# create weights return zip(lisa.Is, quads, lisa.p_sim, weight.id_order, lisa.y)
weight = pu.get_weight(result, w_type, num_ngbrs)
# calculate LISA values def local_bivariate_stat(self, subquery, attr1, attr2,
lisa = ps.esda.moran.Moran_Local_BV(attr1_vals, attr2_vals, weight, permutations, geom_col, id_col,
permutations=permutations) w_type, num_ngbrs):
"""
Moran's I (local) Bivariate (untested)
"""
# find clustering of significance qvals = OrderedDict([("id_col", id_col),
lisa_sig = quad_position(lisa.q) ("attr1", attr1),
("attr2", attr2),
("geom_col", geom_col),
("subquery", subquery),
("num_ngbrs", num_ngbrs)])
return zip(lisa.Is, lisa_sig, lisa.p_sim, weight.id_order) query = pu.construct_neighbor_query(w_type, qvals)
result = self.query_runner.get_result(query)
# collect attributes
attr1_vals = pu.get_attributes(result, 1)
attr2_vals = pu.get_attributes(result, 2)
# create weights
weight = pu.get_weight(result, w_type, num_ngbrs)
# calculate LISA values
lisa = ps.esda.moran.Moran_Local_BV(attr1_vals, attr2_vals, weight,
permutations=permutations)
# find clustering of significance
lisa_sig = quad_position(lisa.q)
return zip(lisa.Is, lisa_sig, lisa.p_sim, weight.id_order)
# Low level functions ---------------------------------------- # Low level functions ----------------------------------------