Add edist term for spatial network models - #659
Closed
smjenness wants to merge 1 commit into
Closed
Conversation
Adds an edist term that contributes, per edge, the Euclidean distance
between the two incident nodes in a space defined by two or more numeric
nodal coordinates (e.g., edist(c("lat", "long"))), optionally raised to
one or more powers.
The pow argument sets the functional form of distance dependence in the
log-odds of a tie: pow = 1 (default) is linear in Euclidean distance,
pow = 2 is squared Euclidean distance (Gaussian-type decay), and a vector
such as pow = c(1, 2) fits a polynomial in distance. Distances are
computed on the fly from the length-n coordinate vectors, so memory use
is linear rather than quadratic in network size, unlike an equivalent
edgecov distance matrix.
The statistic is dyad-independent and works for both directed and
undirected networks. Implementation is a c_edist change statistic in
changestats.c and an InitErgmTerm.edist definition in InitErgmTerm.R,
with distances read on the fly from a coordinate matrix passed through
the term inputs. Includes unit tests covering summary and change
statistics across scalar and vector powers, the two-dimension minimum,
and three-dimensional coordinates.
|
Hmm. See the userterms package forwarded to the statnet list for a term
with more extensive functionality; among other things, it will perform
calculations on the geosphere, and work with log distances. One does not
typically want to use raw distance as a predictor for social networks, as
logistic SIFs are too light-tailed to model most relations. (And also, one
should not typically use Euclidean or other Minkowski metrics with lat/lon
data, at least not if one is trying to use the distance as a proxy for
distance in the real world. Lat/lon coordinates are angular, and distances
in lat/lon space do not have a simple nor linear relationship with distance
on the Earth's surface. One needs to compute great circle distances, per
the above-mentined package.)
…On Fri, Jul 24, 2026 at 10:18 AM Samuel Jenness ***@***.***> wrote:
Adds an edist ERGM term. For each edge it contributes the Euclidean
distance between the two incident nodes in a space defined by two or more
numeric nodal coordinates (e.g., edist(c("lat", "long"))), optionally
raised to one or more powers.
What it does
For an edge between nodes i and j with numeric coordinate attributes,
edist contributes d_ij = sqrt(sum_k (x_ik - x_jk)^2), optionally raised
to each requested power.
~edges + edist(c("lat", "long")) # Euclidean distance~edges + edist(c("lat", "long"), pow = 2) # squared Euclidean distance~edges + edist(c("lat", "long"), pow = c(1, 2)) # polynomial in distance
The pow argument controls whether the log-odds of a tie are linear or
non-linear in distance. pow = 1 (default) is linear in Euclidean
distance, pow = 2 gives a Gaussian-type decay in tie probability, larger
powers decline more sharply, and a vector of powers adds one statistic per
power so a single term fits a polynomial in distance.
Why a dedicated term
edgecov with a precomputed distance matrix can do the same thing but
costs O(n^2) memory. The Sum/Prod operators reach squared Euclidean
distance but not true Euclidean distance, because they compose statistics
already summed over edges, so a square root there gives sqrt(sum_edges
d^2) rather than sum_edges d. The square root has to be applied per dyad,
inside the change statistic, before summing. edist computes the distance
on the fly from the length-n coordinate vectors, so memory is O(n).
Implementation
- src/changestats.c: c_edist, a dyad-independent change statistic that
reads the coordinate matrix and the pow vector from the term inputs
and emits one statistic per power.
- R/InitErgmTerm.R: InitErgmTerm.edist, using ergm_get_vattr(...,
multiple = "matrix") to gather the coordinate columns. Requires two or
more dimensions and errors otherwise, pointing single-dimension users to
absdiff.
- Works for both directed and undirected networks.
- roxygen term documentation and an inst/NEWS.Rd item.
Testing
tests/testthat/test-term-edist.R covers:
- summary statistics for pow = 1, pow = 2, pow = 1.5, and vector pow,
including coefficient names.
- change statistics under interleaved add/remove toggles via
ergm.godfather.
- the two-dimension minimum error.
- three-dimensional coordinates.
- directed networks.
- estimation with ergm() and simulation.
All pass locally, and the existing term tests are unaffected.
Ported from EpiModel/EpiModel#1052
<EpiModel/EpiModel#1052>, which adds the same
term as an EpiModel user term. That PR stays open until this one lands; the
term is a better fit here as a general spatial ERGM term.
------------------------------
You can view, comment on, or merge this pull request online at:
#659
Commit Summary
- 4e4cfad
<4e4cfad>
Add edist ERGM term for spatial network models
File Changes
(5 files <https://github.com/statnet/ergm/pull/659/files>)
- *M* R/InitErgmTerm.R
<https://github.com/statnet/ergm/pull/659/files#diff-8f3a20af85af265e2927b173f3ae84b03f89782d14768437ae7c122dd4876548>
(64)
- *M* inst/NEWS.Rd
<https://github.com/statnet/ergm/pull/659/files#diff-a790b7464c26e39ba6edad826e905198bf0ed3740a7da645277ccc4107b21a26>
(5)
- *A* man/edist-ergmTerm-4a4c7bb0.Rd
<https://github.com/statnet/ergm/pull/659/files#diff-8e8a07a569dbcc799fafdb1828e58280298812a131647d38317be6813c645b40>
(49)
- *M* src/changestats.c
<https://github.com/statnet/ergm/pull/659/files#diff-ebd904f30c32aaf30803046ab9369c64a728b6f3f84423bb3c067ad7211a2eeb>
(33)
- *A* tests/testthat/test-term-edist.R
<https://github.com/statnet/ergm/pull/659/files#diff-56ff7491d25fb9d3b5cda9231405f89b736964724c19577b9fd74160725e0db3>
(89)
Patch Links:
- https://github.com/statnet/ergm/pull/659.patch
- https://github.com/statnet/ergm/pull/659.diff
—
Reply to this email directly, view it on GitHub
<#659?email_source=notifications&email_token=AAJM3GBVBWBMYOXWXDNNI4D5GOK6BA5CNFSNUABEM5UWIORPF5TWS5BNNB2WEL2QOVWGYUTFOF2WK43UF42DCMRWGU2DSNBXGOTHEZLBONXW5KTTOVRHGY3SNFRGKZFFMV3GK3TUVRTG633UMVZF6Y3MNFRWW>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAJM3GDHWK6NXTRH7Q2QJPD5GOK6BAVCNFSNUABEKJSXA33TNF2G64TZHM4TKMRUG43DCNJ3JFZXG5LFHM2DSNZQGYYDCNJRGKQXMAQ>
.
Triage notifications, keep track of coding agent tasks and review pull
requests on the go with GitHub Mobile for iOS
<https://github.com/notifications/mobile/ios/AAJM3GA3IALANJ5WDL3LKL35GOK6BA5CNFSNUABEM5UWIORPF5TWS5BNNB2WEL2QOVWGYUTFOF2WK43UF42DCMRWGU2DSNBXGOTHEZLBONXW5KTTOVRHGY3SNFRGKZFFMV3GK3TUVJTG633UMVZF62LPOM>
and Android
<https://github.com/notifications/mobile/android/AAJM3GDI7UO3UOWHWULHLHT5GOK6BA5CNFSNUABEM5UWIORPF5TWS5BNNB2WEL2QOVWGYUTFOF2WK43UF42DCMRWGU2DSNBXGOTHEZLBONXW5KTTOVRHGY3SNFRGKZFFMV3GK3TUVZTG633UMVZF6YLOMRZG62LE>.
Download it today!
You are receiving this because you are subscribed to this thread.Message
ID: ***@***.***>
|
|
I'm going to go ahead and put in a fork with the fancier term and will submit a pull request for that; this should be more straightforward than having folks use an add-on package. |
Member
Author
|
Closing as this better addressed in #660 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds an
edistERGM term. For each edge it contributes the Euclidean distance between the two incident nodes in a space defined by two or more numeric nodal coordinates (e.g.,edist(c("lat", "long"))), optionally raised to one or more powers.What it does
For an edge between nodes i and j with numeric coordinate attributes,
edistcontributesd_ij = sqrt(sum_k (x_ik - x_jk)^2), optionally raised to each requested power.The
powargument controls whether the log-odds of a tie are linear or non-linear in distance.pow = 1(default) is linear in Euclidean distance,pow = 2gives a Gaussian-type decay in tie probability, larger powers decline more sharply, and a vector of powers adds one statistic per power so a single term fits a polynomial in distance.Why a dedicated term
edgecovwith a precomputed distance matrix can do the same thing but costs O(n^2) memory. TheSum/Prodoperators reach squared Euclidean distance but not true Euclidean distance, because they compose statistics already summed over edges, so a square root there givessqrt(sum_edges d^2)rather thansum_edges d. The square root has to be applied per dyad, inside the change statistic, before summing.edistcomputes the distance on the fly from the length-n coordinate vectors, so memory is O(n).Implementation
src/changestats.c:c_edist, a dyad-independent change statistic that reads the coordinate matrix and thepowvector from the term inputs and emits one statistic per power.R/InitErgmTerm.R:InitErgmTerm.edist, usingergm_get_vattr(..., multiple = "matrix")to gather the coordinate columns. Requires two or more dimensions and errors otherwise, pointing single-dimension users toabsdiff.inst/NEWS.Rditem.Testing
tests/testthat/test-term-edist.Rcovers:pow = 1,pow = 2,pow = 1.5, and vectorpow, including coefficient names.ergm.godfather.ergm()and simulation.All pass locally, and the existing term tests are unaffected.
Ported from EpiModel/EpiModel#1052, which adds the same term as an EpiModel user term. That PR stays open until this one lands; the term is a better fit here as a general spatial ERGM term.