Skip to content

Commit

Permalink
Replaced standardized and windowed methods with standardize and windo…
Browse files Browse the repository at this point in the history
…w, respectively. Changed local moran variance method to use sparse matrix
  • Loading branch information
keithdoggett committed Apr 17, 2020
1 parent 3ce4f42 commit 380e04d
Show file tree
Hide file tree
Showing 12 changed files with 46 additions and 40 deletions.
5 changes: 2 additions & 3 deletions lib/spatial_stats/global/bivariate_moran.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def initialize(scope, x_field, y_field, weights)
@scope = scope
@x_field = x_field
@y_field = y_field
@weights = weights.standardized
@weights = weights.standardize
end
attr_writer :x, :y

Expand All @@ -29,8 +29,7 @@ def initialize(scope, x_field, y_field, weights)
#
# @return [Float]
def stat
w = @weights.standardized
y_lag = SpatialStats::Utils::Lag.neighbor_sum(w, y)
y_lag = SpatialStats::Utils::Lag.neighbor_sum(weights, y)
numerator = 0
x.each_with_index do |xi, idx|
numerator += xi * y_lag[idx]
Expand Down
2 changes: 1 addition & 1 deletion lib/spatial_stats/global/stat.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class Stat
def initialize(scope, field, weights)
@scope = scope
@field = field
@weights = weights.standardized
@weights = weights.standardize
end
attr_accessor :scope, :field, :weights

Expand Down
2 changes: 1 addition & 1 deletion lib/spatial_stats/local/bivariate_moran.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def initialize(scope, x_field, y_field, weights)
@scope = scope
@x_field = x_field
@y_field = y_field
@weights = weights.standardized
@weights = weights.standardize
end
attr_accessor :scope, :x_field, :y_field, :weights

Expand Down
4 changes: 2 additions & 2 deletions lib/spatial_stats/local/getis_ord.rb
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,9 @@ def mc_i(wi, perms, idx)

def calc_weights
@weights = if star?
weights.windowed.standardized
weights.window.standardize
else
weights.standardized
weights.standardize
end
end

Expand Down
22 changes: 14 additions & 8 deletions lib/spatial_stats/local/moran.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,11 @@ def expectation
# @return [Array] of variances for each observation
def variance
# formula is A - B - (E[I])**2
wt = w.row_standardized
exp = expectation

vars = []
a_terms = a_calc(wt)
b_terms = b_calc(wt)
a_terms = a_calc
b_terms = b_calc

a_terms.each_with_index do |a_term, idx|
vars << (a_term - b_terms[idx] - (exp**2))
Expand Down Expand Up @@ -109,20 +108,27 @@ def si2
end

# https://pro.arcgis.com/en/pro-app/tool-reference/spatial-statistics/h-local-morans-i-additional-math.htm
def a_calc(wt)
n = wt.shape[0]
# TODO: sparse
def a_calc
n = weights.n
b2i = b2i_calc

wts = weights.sparse.values
row_index = weights.sparse.row_index

a_terms = []

(0..n - 1).each do |idx|
sigma_term = wt[idx, true].to_a.sum { |v| v**2 }
row_range = row_index[idx]..(row_index[idx + 1] - 1)
wt = wts[row_range]
sigma_term = wt.sum { |v| v**2 }
a_terms << (n - b2i) * sigma_term / (n - 1)
end
a_terms
end

def b_calc(wt)
n = wt.shape[0]
def b_calc
n = weights.n
b2i = b2i_calc
b_terms = []

Expand Down
2 changes: 1 addition & 1 deletion lib/spatial_stats/local/multivariate_geary.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class MultivariateGeary < Stat
def initialize(scope, fields, weights)
@scope = scope
@fields = fields
@weights = weights.standardized
@weights = weights.standardize
end
attr_accessor :scope, :fields, :weights

Expand Down
2 changes: 1 addition & 1 deletion lib/spatial_stats/local/stat.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class Stat
def initialize(scope, field, weights)
@scope = scope
@field = field
@weights = weights.standardized
@weights = weights.standardize
end
attr_accessor :scope, :field, :weights

Expand Down
10 changes: 5 additions & 5 deletions lib/spatial_stats/narray_ext.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ class NArray
#
# @ example
#
# Numo::DFloat [[0, 1, 1], [1, 1, 1]].row_standardized
# Numo::DFloat [[0, 1, 1], [1, 1, 1]].row_standardize
# Numo::DFloat [[0, 0.5, 0.5], [0.33333, 0.33333, 0.33333]]
#
# @return [Numo::NArray]
def row_standardized
def row_standardize
# every row will sum up to 1, or if they are all 0, do nothing
standardized = each_over_axis.map do |row|
sum = row.sum
Expand All @@ -38,16 +38,16 @@ def row_standardized
#
# @ example
#
# Numo::DFloat [[0, 1, 0], [1, 0, 1], [0, 1, 0]].windowed
# Numo::DFloat [[0, 1, 0], [1, 0, 1], [0, 1, 0]].window
# Numo::DFloat [[1, 1, 0], [1, 1, 1], [0, 1, 1]]
#
# @ example
# # Input will be equivalent to output in this case
# Numo::DFloat [[1, 1, 0], [1, 0, 1], [0, 1, 0]].windowed
# Numo::DFloat [[1, 1, 0], [1, 0, 1], [0, 1, 0]].window
# Numo::DFloat [[1, 1, 0], [1, 0, 1], [0, 1, 0]]
#
# @return [Numo::NArray]
def windowed
def window
# in windowed calculations, the diagonal is set to 1
# if trace (sum of diag) is 0, add it, else return input
if trace.zero?
Expand Down
6 changes: 3 additions & 3 deletions lib/spatial_stats/utils/lag.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ module Lag
#
# @return [Array] resultant vector
def self.neighbor_average(matrix, variables)
matrix = matrix.standardized
matrix = matrix.standardize
neighbor_sum(matrix, variables)
end

Expand All @@ -40,7 +40,7 @@ def self.neighbor_sum(matrix, variables)
#
# @return [Array] resultant vector
def self.window_average(matrix, variables)
matrix = matrix.windowed.standardized
matrix = matrix.window.standardize
window_sum(matrix, variables)
end

Expand All @@ -53,7 +53,7 @@ def self.window_average(matrix, variables)
#
# @return [Array] resultant vector
def self.window_sum(matrix, variables)
matrix = matrix.windowed
matrix = matrix.window
matrix.sparse.mulvec(variables)
end
end
Expand Down
7 changes: 4 additions & 3 deletions lib/spatial_stats/weights/weights_matrix.rb
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,11 @@ def sparse

##
# Row standardized version of the weights matrix.
# Will return a new version of the weights matrix standardized weights.
# Will return a new version of the weights matrix with standardized
# weights.
#
# @return [WeightsMatrix]
def standardized
def standardize
new_weights = weights

new_weights.transform_values do |neighbors|
Expand All @@ -83,7 +84,7 @@ def standardized
# If a row already has an entry for itself, it will be skipped.
#
# @return [WeightsMatrix]
def windowed
def window
new_weights = weights

new_weights.each do |key, neighbors|
Expand Down
16 changes: 8 additions & 8 deletions test/narray_ext_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,29 @@ def setup
@matrix = Numo::DFloat[[0, 1, 0], [1, 0, 1], [0, 1, 0]]
end

def test_row_standardized
def test_row_standardize
expected = Numo::DFloat[[0, 1, 0], [1.0 / 2, 0, 1.0 / 2], [0, 1, 0]]
result = @matrix.row_standardized
result = @matrix.row_standardize
assert_equal(expected, result)
end

def test_row_standardized_zeros
def test_row_standardize_zeros
zero_matrix = Numo::DFloat[[0, 1, 0], [1, 0, 1], [0, 0, 0]]
expected = Numo::DFloat[[0, 1, 0], [1.0 / 2, 0, 1.0 / 2], [0, 0, 0]]
result = zero_matrix.row_standardized
result = zero_matrix.row_standardize
assert_equal(expected, result)
end

def test_windowed_success
def test_window_success
expected = Numo::DFloat[[1, 1, 0], [1, 1, 1], [0, 1, 1]]
result = @matrix.windowed
result = @matrix.window
assert_equal(expected, result)
end

def test_windowed_failure
def test_window_failure
# will fail if the trace isn't already 0 and just return input
input = Numo::DFloat[[1, 1, 0], [1, 0, 1], [0, 1, 0]]
result = input.windowed
result = input.window
assert_equal(input, result)
end
end
8 changes: 4 additions & 4 deletions test/weights/weights_matrix_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ def test_sparse
assert_equal(expected.row_index, result.row_index)
end

def test_standardized
def test_standardize
mat = SpatialStats::Weights::WeightsMatrix.new(@weights)
standardized_mat = mat.standardized
standardized_mat = mat.standardize

expected = {
1 => [{ id: 2, weight: 1.0 / 2 }, { id: 4, weight: 1.0 / 2 }],
Expand All @@ -62,9 +62,9 @@ def test_standardized
assert_equal(expected, standardized_mat.weights)
end

def test_windowed
def test_window
mat = SpatialStats::Weights::WeightsMatrix.new(@weights)
windowed_mat = mat.windowed
windowed_mat = mat.window

expected = {
1 => [{ id: 1, weight: 1 }, { id: 2, weight: 1 }, { id: 4, weight: 1 }],
Expand Down

0 comments on commit 380e04d

Please sign in to comment.