Module: SpatialStats::Queries::Weights
- Defined in:
- lib/spatial_stats/queries/weights.rb
Overview
Weights includes methods for querying a scope using PostGIS sql methods to determine neighbors and weights based on different weighting schemes/formulas.
Class Method Summary collapse
-
._contiguity_neighbors(scope, column, pattern) ⇒ Hash
Generic function to compute contiguity neighbor weights for a given scope.
-
.distance_band_neighbors(scope, column, bandwidth) ⇒ Hash
Compute distance band weights for a given scope.
-
.idw_band(scope, column, bandwidth, alpha = 1) ⇒ Hash
Compute inverse distance weighted, band limited weights for a given scope and geometry.
-
.idw_knn(scope, column, k, alpha = 1) ⇒ Hash
Compute inverse distance weighted, k nearest neighbors weights for a given scope and geometry.
-
.knn(scope, column, k) ⇒ Hash
Compute k nearest neighbor weights for a given scope.
-
.queen_contiguity_neighbors(scope, column) ⇒ Hash
Compute queen contiguity weights for a given scope.
-
.rook_contiguity_neighbors(scope, column) ⇒ Hash
Compute rook contiguity weights for a given scope.
Class Method Details
._contiguity_neighbors(scope, column, pattern) ⇒ Hash
Generic function to compute contiguity neighbor weights for a given scope. Takes any valid DE-9IM pattern and computes the neighbors based off of that.
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 |
# File 'lib/spatial_stats/queries/weights.rb', line 203 def self._contiguity_neighbors(scope, column, pattern) klass = scope.klass column = ActiveRecord::Base.connection.quote_column_name(column) primary_key = klass.quoted_primary_key klass.find_by_sql([<<-SQL, scope: scope]) WITH neighbors AS ( WITH scope AS (:scope) SELECT a.#{primary_key} as i_id, b.#{primary_key} as j_id, ST_RELATE(a.#{column}, b.#{column}, \'#{pattern}\') as is_neighbor FROM scope as a, scope as b ORDER BY i_id ) SELECT * FROM neighbors WHERE is_neighbor = 't' SQL end |
.distance_band_neighbors(scope, column, bandwidth) ⇒ Hash
Compute distance band weights for a given scope. Identifies neighbors as other observations in scope that are within the distance band from the observation.
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
# File 'lib/spatial_stats/queries/weights.rb', line 146 def self.distance_band_neighbors(scope, column, bandwidth) klass = scope.klass column = ActiveRecord::Base.connection.quote_column_name(column) primary_key = klass.quoted_primary_key klass.find_by_sql([<<-SQL, scope: scope, distance: bandwidth]) WITH neighbors AS ( WITH scope AS (:scope) SELECT a.#{primary_key} as i_id, b.#{primary_key} as j_id, ST_DWithin(a.#{column}, b.#{column}, :distance) as is_neighbor FROM scope as a, scope as b ORDER BY i_id ) SELECT * FROM neighbors WHERE is_neighbor = 't' AND i_id <> j_id SQL end |
.idw_band(scope, column, bandwidth, alpha = 1) ⇒ Hash
Compute inverse distance weighted, band limited weights for a given scope and geometry.
Combines distance_band and idw weightings. Each observation will have neighbers in the bandwidth, but the weights will be calculated by 1/(d**alpha).
Only works for geometry types that implement ST_Distance and ST_DWithin.
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 |
# File 'lib/spatial_stats/queries/weights.rb', line 76 def self.idw_band(scope, column, bandwidth, alpha = 1) klass = scope.klass column = ActiveRecord::Base.connection.quote_column_name(column) primary_key = klass.quoted_primary_key neighbors = klass.find_by_sql([<<-SQL, scope: scope, bandwidth: bandwidth]) WITH neighbors AS ( WITH scope AS (:scope) SELECT a.#{primary_key} as i_id, b.#{primary_key} as j_id, ST_DWithin(a.#{column}, b.#{column}, :bandwidth) as is_neighbor, ST_Distance(a.#{column}, b.#{column}) as distance FROM scope as a, scope as b ORDER BY i_id ) SELECT * FROM neighbors WHERE is_neighbor = 't' AND i_id <> j_id SQL # if the lowest distance is <1, then we need to scale # every distance by the factor that makes the lowest 1 min_dist = neighbors.map(&:distance).min scale = if min_dist < 1 1 / min_dist else 1 end neighbors.map do |neighbor| # formula is 1/(d^alpha) weight = 1.0 / ((scale * neighbor.distance)**alpha) hash = neighbor.as_json.symbolize_keys hash[:weight] = weight hash end end |
.idw_knn(scope, column, k, alpha = 1) ⇒ Hash
Compute inverse distance weighted, k nearest neighbors weights for a given scope and geometry.
Combines knn and idw weightings. Each observation will have k neighbors, but the weights will be calculated by 1/(d**alpha).
Only works for geometry types that implement ST_Distance.
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 |
# File 'lib/spatial_stats/queries/weights.rb', line 25 def self.idw_knn(scope, column, k, alpha = 1) klass = scope.klass column = ActiveRecord::Base.connection.quote_column_name(column) primary_key = klass.quoted_primary_key neighbors = klass.find_by_sql([<<-SQL, scope: scope, k: k]) WITH scope as (:scope) SELECT neighbors.* FROM scope AS a CROSS JOIN LATERAL ( SELECT a.#{primary_key} as i_id, b.#{primary_key} as j_id, ST_Distance(a.#{column}, b.#{column}) as distance FROM scope as b WHERE a.#{primary_key} <> b.#{primary_key} ORDER BY a.#{column} <-> b.#{column} LIMIT :k ) AS neighbors SQL # if the lowest distance is <1, then we need to scale # every distance by the factor that makes the lowest 1 min_dist = neighbors.map(&:distance).min scale = if min_dist < 1 1 / min_dist else 1 end neighbors.map do |neighbor| # formula is 1/(d^alpha) weight = 1.0 / ((scale * neighbor.distance)**alpha) hash = neighbor.as_json.symbolize_keys hash[:weight] = weight hash end end |
.knn(scope, column, k) ⇒ Hash
Compute k nearest neighbor weights for a given scope.
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/spatial_stats/queries/weights.rb', line 118 def self.knn(scope, column, k) klass = scope.klass column = ActiveRecord::Base.connection.quote_column_name(column) primary_key = klass.quoted_primary_key klass.find_by_sql([<<-SQL, scope: scope, k: k]) WITH scope as (:scope) SELECT neighbors.* FROM scope AS a CROSS JOIN LATERAL ( SELECT a.#{primary_key} as i_id, b.#{primary_key} as j_id FROM scope as b WHERE a.#{primary_key} <> b.#{primary_key} ORDER BY a.#{column} <-> b.#{column} LIMIT :k ) AS neighbors SQL end |
.queen_contiguity_neighbors(scope, column) ⇒ Hash
Compute queen contiguity weights for a given scope. Queen contiguity weights are defined by geometries sharing an edge or vertex.
DE-9IM pattern = F**T***
173 174 175 |
# File 'lib/spatial_stats/queries/weights.rb', line 173 def self.queen_contiguity_neighbors(scope, column) _contiguity_neighbors(scope, column, 'F***T****') end |
.rook_contiguity_neighbors(scope, column) ⇒ Hash
Compute rook contiguity weights for a given scope. Rook contiguity weights are defined by geometries sharing an edge.
DE-9IM pattern = 'F**1***'
187 188 189 |
# File 'lib/spatial_stats/queries/weights.rb', line 187 def self.rook_contiguity_neighbors(scope, column) _contiguity_neighbors(scope, column, 'F***1****') end |