3  Migration Graphs and Spatial Interaction

import geopandas as gpd
import numpy as np
import networkx as nx
import pandas as pd
import seaborn as sns
import statsmodels.formula.api as smf
from formulaic import Formula
from geosnap import DataStore
from geosnap import io as gio
from libpysal.graph import Graph
from lonboard import Map, PolygonLayer, ScatterplotLayer, basemap, viz
from lonboard.experimental import ArcLayer
from lonboard.layer_extension import BrushingExtension
from mapclassify.util import get_color_array
from shapely import LineString
from spint.gravity import Attraction, Doubly, Gravity, Production
from statsmodels.api import families
%load_ext watermark
%watermark -a 'eli knaap'
OMP: Info #276: omp_set_nested routine deprecated, please use omp_set_max_active_levels instead.
Author: eli knaap

3.1 Demographic & Socioeconomic Data

3.1.1 ACS Data

datasets = DataStore()

dc = gio.get_acs(datasets, state_fips="11", years=2021, level="tract")
/Users/knaaptime/Dropbox/projects/geosnap/geosnap/io/util.py:273: UserWarning: Unable to find local adjustment year for 2021. Attempting from online data
  warn(
/Users/knaaptime/Dropbox/projects/geosnap/geosnap/io/constructors.py:218: UserWarning: Currency columns unavailable at this resolution; not adjusting for inflation
  warn(
dc.head()
geoid n_mexican_pop n_cuban_pop n_puerto_rican_pop n_russian_pop n_italian_pop n_german_pop n_irish_pop n_scandaniavian_pop n_foreign_born_pop ... p_poverty_rate p_poverty_rate_over_65 p_poverty_rate_children p_poverty_rate_white p_poverty_rate_black p_poverty_rate_hispanic p_poverty_rate_native p_poverty_rate_asian geometry year
0 11001000101 102.0 0.0 0.0 0.0 68.0 26.0 59.0 0.0 149.0 ... 2.341920 0.000000 0.000000 2.341920 0.000000 2.341920 0.0 0.0 MULTIPOLYGON (((-77.05714 38.91054, -77.05702 ... 2021
1 11001000102 134.0 0.0 0.0 68.0 56.0 14.0 146.0 0.0 746.0 ... 6.724512 1.487450 1.456461 4.834211 0.000000 0.000000 0.0 0.0 MULTIPOLYGON (((-77.06927 38.90058, -77.06871 ... 2021
2 11001000201 152.0 0.0 109.0 5.0 45.0 8.0 98.0 0.0 731.0 ... 19.402985 0.000000 0.000000 16.417910 2.985075 0.000000 0.0 0.0 MULTIPOLYGON (((-77.07927 38.91268, -77.07902 ... 2021
3 11001000202 42.0 46.0 58.0 61.0 91.0 56.0 220.0 0.0 793.0 ... 12.948793 2.472042 0.000000 10.829900 0.588582 0.824014 0.0 0.0 MULTIPOLYGON (((-77.07991 38.90507, -77.07989 ... 2021
4 11001000300 150.0 103.0 8.0 33.0 220.0 74.0 71.0 0.0 1308.0 ... 13.308750 0.301710 0.201140 12.504190 0.000000 0.620181 0.0 0.0 MULTIPOLYGON (((-77.08262 38.9212, -77.08256 3... 2021

5 rows × 158 columns

dc.plot()

3.1.2 LODES Data

See the technical documentation

dc_flows = pd.read_csv(
    "https://lehd.ces.census.gov/data/lodes/LODES8/dc/od/dc_od_main_JT00_2022.csv.gz",
    converters={"w_geocode": str, "h_geocode": str},
    low_memory=False,
    encoding="latin1",
)
dc_flows
w_geocode h_geocode S000 SA01 SA02 SA03 SE01 SE02 SE03 SI01 SI02 SI03 createdate
0 110010001011000 110010001011000 1 1 0 0 0 0 1 0 1 0 20240920
1 110010001011000 110010001011001 3 1 2 0 0 0 3 0 0 3 20240920
2 110010001011000 110010001011003 1 0 0 1 0 0 1 0 0 1 20240920
3 110010001011000 110010001011009 1 1 0 0 0 0 1 0 1 0 20240920
4 110010001011000 110010001021011 1 0 0 1 0 0 1 0 1 0 20240920
... ... ... ... ... ... ... ... ... ... ... ... ... ...
169140 110019800001187 110010094004008 1 0 1 0 0 0 1 0 0 1 20240920
169141 110019800001187 110010095071000 1 0 1 0 0 0 1 0 0 1 20240920
169142 110019800001187 110010099021011 1 0 1 0 0 0 1 0 0 1 20240920
169143 110019800001192 110010047041001 1 0 1 0 1 0 0 0 0 1 20240920
169144 110019800001192 110010096041011 1 0 1 0 1 0 0 0 0 1 20240920

169145 rows × 13 columns

add tract-level geoids and drop extraneous columns

dc_flows["w_tr_geocode"] = dc_flows["w_geocode"].str[:11]
dc_flows["h_tr_geocode"] = dc_flows["h_geocode"].str[:11]

dc_flows = dc_flows[["w_geocode", "h_geocode", "w_tr_geocode", "h_tr_geocode", "S000"]]

pretend like its a closed system, only consdidering intra-regional flows

aggregate to tract-level flows (from block-level)

dc_flows = (
    dc_flows.groupby(["w_tr_geocode", "h_tr_geocode"])["S000"].sum().reset_index()
)

this is an origin-destination matrix (as an adjacency list). S000 is the number of flows between home census tract h_tr_geocode and work tract w_tr_geocode. There are many intra-tract flows \(W_{ii}\neq0\)} (people commuting within the same tract, or possibly WFH, though that would be tough with LODES) and the flows are directed \(W_{ij} \neq W_{ji}\)

dc_flows
w_tr_geocode h_tr_geocode S000
0 11001000101 11001000101 22
1 11001000101 11001000102 8
2 11001000101 11001000202 6
3 11001000101 11001000300 3
4 11001000101 11001000501 1
... ... ... ...
23301 11001980000 11001010900 26
23302 11001980000 11001011001 91
23303 11001980000 11001011002 50
23304 11001980000 11001011100 90
23305 11001980000 11001980000 3

23306 rows × 3 columns

create a pysal Graph to represent these flows. to represent the direction of flow correctly the focal column is home and neighbor is work (this shows the AM commute)

dc_flow_graph = Graph.from_adjacency(
    adjacency=dc_flows,
    focal_col="h_tr_geocode",
    neighbor_col="w_tr_geocode",
    weight_col="S000",
)
dc_flow_graph.summary()
Graph Summary Statistics
Number of nodes: 206
Number of edges: 23306
Number of connected components: 1
Number of isolates: 0
Number of non-zero edges: 23306
Percentage of non-zero edges: 54.92%
Number of asymmetries: NA
Sum of weights and Traces
S0: 206135 GG: 915878
S1: 12398975 G'G: 11483097
S3: 2363152954 G'G + GG: 12398975
Graph indexed by: ['11001000101', '11001000102', '11001000202', '1100100030...]
dc_flow_graph.adjacency.head()
focal        neighbor   
11001000101  11001000101    22
             11001000102    23
             11001000202    12
             11001000703     1
             11001000704     1
Name: weight, dtype: int64

the Graph is ordered, and to visualize it correctly we want to align our other data to match this Graph; so stash the id/order

idx = dc_flow_graph.unique_ids

create a geodataframe of centroids to visualize point-to-point flows, then reindex to re-order appropriately and drop observations with no flow.

dc_centroids = dc.set_geometry(dc.centroid)
dc_centroids = dc_centroids.set_index("geoid").reindex(idx)
/var/folders/j8/5bgcw6hs7cqcbbz48d6bsftw0000gp/T/ipykernel_24509/898227089.py:1: UserWarning: Geometry is in a geographic CRS. Results from 'centroid' are likely incorrect. Use 'GeoSeries.to_crs()' to re-project geometries to a projected CRS before this operation.

  dc_centroids = dc.set_geometry(dc.centroid)
dc_centroids.shape  # matches our Graph.n
(206, 157)
dc = dc.set_index("geoid")

3.2 Migration as a Graph

the matrix representation of the network shows us the level of flow from each origin-destination pair

3.2.1 Matrix Representation

dc_flow_graph.sparse.todense()
array([[ 22.,  23.,  12., ...,  32.,   0.,  38.],
       [  8., 123.,  30., ...,  51.,   0.,  53.],
       [  6.,  51.,  84., ..., 137.,   0.,  44.],
       ...,
       [  0.,   0.,   5., ...,  95.,   0.,   1.],
       [  0.,   0.,   0., ...,   0.,   2.,   1.],
       [  0.,   0.,   0., ...,   0.,   0.,   3.]], shape=(206, 206))

there are lots of “internal flows”, i.e. commutes that begin and end in the same tract (relatively large numbers along the diagonal). But it’s common in migration studies to focus on inter-zonal flows, so we remove these–but first we will record the total numbers

all_commutes = pd.Series(
    dc_flow_graph.sparse.sum(axis=1), index=dc_flow_graph.unique_ids, name="flows"
)

now save the total number of internal commutes (self-loops in the network; the diagonal of the matrix)

# how many self-loops (trips originating and ending in the same tract
# not sure if there's an easier way to get this, but its the diagonal of the weights matrix
intra_commutes = pd.Series(
    np.diag(dc_flow_graph.sparse.todense()),
    index=dc_flow_graph.unique_ids,
    name="self_loops",
)
intra_share = intra_commutes / all_commutes
intra_commutes
focal
11001000101     22.0
11001000102    123.0
11001000202     84.0
11001000300     81.0
11001000501     36.0
               ...  
11001011002     13.0
11001011100     83.0
11001000201     95.0
11001006804      2.0
11001980000      3.0
Name: self_loops, Length: 206, dtype: float64

just so we can take a look: internal commutes are a small but non-significant share of our job flow data

intra_share
focal
11001000101    0.047826
11001000102    0.142857
11001000202    0.097335
11001000300    0.052907
11001000501    0.029826
                 ...   
11001011002    0.022491
11001011100    0.056271
11001000201    0.590062
11001006804    0.028169
11001980000    0.090909
Length: 206, dtype: float64
intra_commutes.sum() / all_commutes.sum()
np.float64(0.0358114827661484)

in DC, 3.6% of the employees in LODES data have a job and workplace in the same census tract

dc.join(intra_commutes, how="left").explore(
    "self_loops",
    style_kwds={"weight": 0.5},
    tiles="cartodb positron",
    tooltip="self_loops",
    scheme="fisherjenks",
    cmap="RdBu_r",
)
Make this Notebook Trusted to load map: File -> Trust Notebook
dc.join(intra_share.rename("intra_share"), how="left").explore(
    "intra_share",
    style_kwds={"weight": 0.5},
    tiles="cartodb positron",
    tooltip="intra_share",
    scheme="fisherjenks",
    cmap="RdBu_r",
)
Make this Notebook Trusted to load map: File -> Trust Notebook

3.2.2 Network Representation

to look at directionality (sending regions vs receiving regions) we can use network method from networkx

we only want to consider incoming and outgoing flows, so we first remove the diagonal in our Graph (and drop those observations), then convert to a networkx object

dc_nx = dc_flow_graph.assign_self_weight(0).eliminate_zeros().to_networkx()

the degree of a node is the number of connections it has. Out-degree is the number of outgoing connections and in-degree is the number of incoming connections. For a focal observation, the out degree is the number of ‘neighbors’ it has (in spatial graph terminology), which is the same as its cardinality

dc_flow_graph.assign_self_weight(0).eliminate_zeros().cardinalities
focal
11001000101     59
11001000102     86
11001000202     84
11001000300    111
11001000501    114
              ... 
11001011002     83
11001011100    138
11001000201     41
11001006804     37
11001980000     22
Name: cardinalities, Length: 206, dtype: int64
pd.Series(dict(dc_nx.out_degree))
11001000101     59
11001000102     86
11001000202     84
11001000703     80
11001000704    106
              ... 
11001009507     96
11001009905    130
11001009801    101
11001009906     97
11001009802     95
Length: 206, dtype: int64

when the degree measure is weighted, each link/edge/relationship is multiplied by by its weight. Thus the weighted degree for each node is the sum of its weights (in spatial econometric parlance, this is equivalent to an un-transformed spatial lag)

with out flow data, the weighted out degree measures the number of trips moving away from a home tract in the AM, and in-degree measures the number of trips incoming during the AM commute. The weighted degree (plain) is their sum, capturing the total fluctuation in the unit

out_degree = pd.Series(
    dict(dc_nx.out_degree(dc_nx, weight="weight")), name="out_degree"
)
in_degree = pd.Series(
    dict(dc_nx.in_degree(dc_nx, weight="weight")), name="in_degree"
)

degree = pd.Series(dict(dc_nx.degree(dc_nx, weight="weight")), name="degree")

note the weighted out-degree is the same as the spatial lag when the weights matrix is unstandardized

lag = dc_flow_graph.lag(np.ones(dc_flow_graph.n))
pd.Series(lag).hist()

out_degree.hist()

pop_change = intra_commutes + in_degree - out_degree
pop_change.hist()

# daily population change
# internal movers plus immigration minus emigration
intra_commutes + in_degree - out_degree
11001000101     -287.0
11001000102     2343.0
11001000201     4132.0
11001000202     1560.0
11001000300    -1092.0
                ...   
11001010900     -340.0
11001011001     -814.0
11001011002     -383.0
11001011100      295.0
11001980000    13076.0
Length: 206, dtype: float64
out_degree
11001000101    438
11001000102    738
11001000202    779
11001000703    547
11001000704    699
              ... 
11001009507    551
11001009905    852
11001009801    407
11001009906    454
11001009802    463
Name: out_degree, Length: 206, dtype: int64
out_degree.sum() + intra_commutes.sum() == all_commutes.sum()
np.True_
dc_flow_graph.adjacency.reset_index().groupby("neighbor").sum().sum()
focal     1100100010111001000102110010002021100100030011...
weight                                               206135
dtype: object
out_degree.sum()
np.int64(198753)
out_degree.sum() / all_commutes.sum()
np.float64(0.9641885172338516)
all_commutes.sum()
np.float64(206135.0)
sns.heatmap(dc_flow_graph.sparse.todense())

out_degree.hist(bins=20)

in_degree.sum()
np.int64(198753)
in_degree.hist(bins=20)

3.3 Visualization

3.3.1 Mapping Graph Metrics

mapping out-degree shows exports/out-migration

dc.join(out_degree, how="left").explore(
    "out_degree",
    style_kwds={"weight": 0.5},
    tiles="cartodb positron",
    tooltip="out_degree",
    scheme="fisherjenks",
)
Make this Notebook Trusted to load map: File -> Trust Notebook

out migration as a share of all change

dc.join((out_degree / all_commutes).rename("out_share"), how="left").plot(
    "out_share",
    linewidth=0.5,
    #style_kwds={"weight": 0.5},
    #tiles="cartodb positron",
    #tooltip="out_share",
    scheme="fisherjenks",
    cmap="RdBu_r",
)

in-degree measures imports/immigration

dc.join(in_degree, how="left").explore(
    "in_degree",
    style_kwds={"weight": 0.5},
    linewidth=0.5,
    tiles="cartodb positron",
    tooltip="in_degree",
    scheme="fisherjenks",
)
Make this Notebook Trusted to load map: File -> Trust Notebook

in-migration as a share of all change

(in_degree / (intra_commutes + in_degree)).hist()

dc.join(
    (in_degree / (intra_commutes + in_degree)).rename("in_share"), how="left"
).plot(
    "in_share",
    #style_kwds={"weight": 0.5},
    #tiles="cartodb positron",
    #tooltip="in_share",
    linewidth=0.5,
    scheme="fisherjenks",
    cmap="RdBu_r",
)

(out_degree / all_commutes).hist()

net immigration

dc.join(((in_degree - out_degree) / degree).rename("diff"), how="left").plot(
    "diff",
    #style_kwds={"weight": 0.5},
    #tiles="cartodb positron",
    #tooltip="diff",
    linewidth=0.5,
    scheme="fisherjenks",
    cmap="RdBu_r",
    legend=True
)

out_degree / all_commutes
11001000101    0.952174
11001000102    0.857143
11001000201    0.409938
11001000202    0.902665
11001000300    0.947093
                 ...   
11001010900    0.986527
11001011001    0.975391
11001011002    0.977509
11001011100    0.943729
11001980000    0.909091
Length: 206, dtype: float64

3.3.2 Mapping with Three Dimensions

the flow graph is difficult to visualize because (1) it’s so dense (there’s so many lines they obscure one another), and (2) the flows are bi-directional (so they lay on top of each other). With a bit more work, we can get a better visualization via lonboard. Using the Graph and a little geopandas knowledge, we can get our data in good shape quickly.

flows = dc_flow_graph.adjacency.reset_index()
flows
focal neighbor weight
0 11001000101 11001000101 22
1 11001000101 11001000102 23
2 11001000101 11001000202 12
3 11001000101 11001000703 1
4 11001000101 11001000704 1
... ... ... ...
23301 11001980000 11001009400 1
23302 11001980000 11001009510 2
23303 11001980000 11001010100 3
23304 11001980000 11001010202 2
23305 11001980000 11001980000 3

23306 rows × 3 columns

# mapping of geoid to (point) geometry
dc.centroid.head()
/var/folders/j8/5bgcw6hs7cqcbbz48d6bsftw0000gp/T/ipykernel_24509/4023599085.py:2: UserWarning: Geometry is in a geographic CRS. Results from 'centroid' are likely incorrect. Use 'GeoSeries.to_crs()' to re-project geometries to a projected CRS before this operation.

  dc.centroid.head()
geoid
11001000101    POINT (-77.05459 38.90863)
11001000102    POINT (-77.06127 38.90555)
11001000201    POINT (-77.07434 38.90922)
11001000202    POINT (-77.06946 38.90617)
11001000300    POINT (-77.07577 38.91755)
dtype: geometry

start by creating a set of lines representing flows

flows['focal'] = flows['focal'].replace(dc_centroids['geometry'].to_dict())
flows['neighbor'] = flows['neighbor'].replace(dc_centroids['geometry'].to_dict())
flows
focal neighbor weight
0 POINT (-77.0545901773603 38.90863168678613) POINT (-77.0545901773603 38.90863168678613) 22
1 POINT (-77.0545901773603 38.90863168678613) POINT (-77.06126938548466 38.90554704444118) 23
2 POINT (-77.0545901773603 38.90863168678613) POINT (-77.06945761360377 38.90616754177441) 12
3 POINT (-77.0545901773603 38.90863168678613) POINT (-77.07904623332543 38.92909409426648) 1
4 POINT (-77.0545901773603 38.90863168678613) POINT (-77.07523846048979 38.93002154576946) 1
... ... ... ...
23301 POINT (-77.03521796878309 38.88015568912712) POINT (-76.97424646610372 38.936806296574765) 1
23302 POINT (-77.03521796878309 38.88015568912712) POINT (-77.00462558924458 38.945597917488946) 2
23303 POINT (-77.03521796878309 38.88015568912712) POINT (-77.03184718492626 38.90269707590609) 3
23304 POINT (-77.03521796878309 38.88015568912712) POINT (-77.0244550492709 38.88309525105518) 2
23305 POINT (-77.03521796878309 38.88015568912712) POINT (-77.03521796878309 38.88015568912712) 3

23306 rows × 3 columns

origins = gpd.GeoSeries(flows.focal).get_coordinates().values

destinations = (
    gpd.GeoSeries(flows.neighbor).get_coordinates().values
)
origins
array([[-77.05459018,  38.90863169],
       [-77.05459018,  38.90863169],
       [-77.05459018,  38.90863169],
       ...,
       [-77.03521797,  38.88015569],
       [-77.03521797,  38.88015569],
       [-77.03521797,  38.88015569]], shape=(23306, 2))
LineString([flows['focal'][0], flows['neighbor'][0]])

lines = gpd.GeoSeries([LineString([row[1]['focal'], row[1]['neighbor']]) for row in flows.iterrows()], crs=4326)
flow_lines =gpd.GeoDataFrame(flows['weight'], geometry=lines)
flow_lines
weight geometry
0 22 LINESTRING (-77.05459 38.90863, -77.05459 38.9...
1 23 LINESTRING (-77.05459 38.90863, -77.06127 38.9...
2 12 LINESTRING (-77.05459 38.90863, -77.06946 38.9...
3 1 LINESTRING (-77.05459 38.90863, -77.07905 38.9...
4 1 LINESTRING (-77.05459 38.90863, -77.07524 38.9...
... ... ...
23301 1 LINESTRING (-77.03522 38.88016, -76.97425 38.9...
23302 2 LINESTRING (-77.03522 38.88016, -77.00463 38.9...
23303 3 LINESTRING (-77.03522 38.88016, -77.03185 38.9...
23304 2 LINESTRING (-77.03522 38.88016, -77.02446 38.8...
23305 3 LINESTRING (-77.03522 38.88016, -77.03522 38.8...

23306 rows × 2 columns

this is the best we can do with a generic explore

lines.explore()
Make this Notebook Trusted to load map: File -> Trust Notebook

piping the same dataset into lonboard, we get basically the same thing

viz(flow_lines)
dc_flow_graph.adjacency
focal        neighbor   
11001000101  11001000101    22
             11001000102    23
             11001000202    12
             11001000703     1
             11001000704     1
                            ..
11001980000  11001009400     1
             11001009510     2
             11001010100     3
             11001010202     2
             11001980000     3
Name: weight, Length: 23306, dtype: int64
flow_lines[['weight', 'geometry']]
weight geometry
0 22 LINESTRING (-77.05459 38.90863, -77.05459 38.9...
1 23 LINESTRING (-77.05459 38.90863, -77.06127 38.9...
2 12 LINESTRING (-77.05459 38.90863, -77.06946 38.9...
3 1 LINESTRING (-77.05459 38.90863, -77.07905 38.9...
4 1 LINESTRING (-77.05459 38.90863, -77.07524 38.9...
... ... ...
23301 1 LINESTRING (-77.03522 38.88016, -76.97425 38.9...
23302 2 LINESTRING (-77.03522 38.88016, -77.00463 38.9...
23303 3 LINESTRING (-77.03522 38.88016, -77.03185 38.9...
23304 2 LINESTRING (-77.03522 38.88016, -77.02446 38.8...
23305 3 LINESTRING (-77.03522 38.88016, -77.03522 38.8...

23306 rows × 2 columns

lets do better

brushing_extension = BrushingExtension()
brushing_radius = 300

arc_layer = ArcLayer(
    table=flow_lines[['weight', 'geometry']].to_arrow(),
    get_width=flow_lines.weight.apply(lambda x: x**.7),
    get_source_position=origins,
    get_target_position=destinations,
    opacity=0.4,
    pickable=False,
    extensions=[brushing_extension],
    brushing_radius=brushing_radius,
    get_source_color=get_color_array(flow_lines.weight**.7, scheme='fisher_jenks', k=10, cmap='inferno_r'),
    get_target_color=get_color_array(flow_lines.weight**.7, scheme='fisher_jenks', k=10, cmap='inferno_r')
)

source_gdf = gpd.GeoDataFrame(geometry=flows["focal"], crs=4326)
target_gdf = gpd.GeoDataFrame(geometry=flows["neighbor"], crs=4326)

tgt = ScatterplotLayer.from_geopandas(
    target_gdf,
    radius_scale=30,
    pickable=True,
    stroked=False,
    filled=True,
    line_width_min_pixels=2,
    extensions=[brushing_extension],
    brushing_radius=brushing_radius,
)

src = ScatterplotLayer.from_geopandas(
    source_gdf,
    radius_scale=15,
    pickable=False,
    stroked=False,
    filled=True,
    line_width_min_pixels=2,
    extensions=[brushing_extension],
    brushing_radius=brushing_radius,
)

bounds = PolygonLayer.from_geopandas(
    dc.to_crs(4326),
    get_fill_color=[255, 255, 255, 200],
    stroked=True,
    line_width_min_pixels=0.5,
    pickable=False,
    opacity=0.3
)

ogb = ScatterplotLayer.from_geopandas(
    source_gdf,
    get_fill_color=[255, 255, 255, 200],
    stroked=True,
    line_width_min_pixels=0.5,
    pickable=False,
)

gmap = Map(layers=[bounds, src, tgt, arc_layer,ogb], picking_radius=500)
gmap.to_html('dc_flow_orig_orient.html')


gmap

The mouseover is keyed on home (origin), so the visualization shows flows away from the selected location. To focus on destinations/inflows, we can reverse the orientation in the ArcLayer. Use control+click and drag in the map to change the view angle.

flows
focal neighbor weight
0 POINT (-77.0545901773603 38.90863168678613) POINT (-77.0545901773603 38.90863168678613) 22
1 POINT (-77.0545901773603 38.90863168678613) POINT (-77.06126938548466 38.90554704444118) 23
2 POINT (-77.0545901773603 38.90863168678613) POINT (-77.06945761360377 38.90616754177441) 12
3 POINT (-77.0545901773603 38.90863168678613) POINT (-77.07904623332543 38.92909409426648) 1
4 POINT (-77.0545901773603 38.90863168678613) POINT (-77.07523846048979 38.93002154576946) 1
... ... ... ...
23301 POINT (-77.03521796878309 38.88015568912712) POINT (-76.97424646610372 38.936806296574765) 1
23302 POINT (-77.03521796878309 38.88015568912712) POINT (-77.00462558924458 38.945597917488946) 2
23303 POINT (-77.03521796878309 38.88015568912712) POINT (-77.03184718492626 38.90269707590609) 3
23304 POINT (-77.03521796878309 38.88015568912712) POINT (-77.0244550492709 38.88309525105518) 2
23305 POINT (-77.03521796878309 38.88015568912712) POINT (-77.03521796878309 38.88015568912712) 3

23306 rows × 3 columns

dest_graph = Graph.from_adjacency(dc_flows,
    focal_col="w_tr_geocode",
    neighbor_col="h_tr_geocode",
    weight_col="S000",
)

dest_graph_flows = dest_graph.adjacency.reset_index()

dest_graph_flows['focal'] = dest_graph_flows['focal'].replace(dc_centroids['geometry'].to_dict())
dest_graph_flows['neighbor'] = dest_graph_flows['neighbor'].replace(dc_centroids['geometry'].to_dict())

dest_lines = gpd.GeoSeries([LineString([row[1]['focal'], row[1]['neighbor']]) for row in dest_graph_flows.iterrows()], crs=4326)
dest_lines =gpd.GeoDataFrame(dest_graph_flows['weight'], geometry=dest_lines)

origins = gpd.GeoSeries(dest_graph_flows.focal).get_coordinates().values

destinations = (
    gpd.GeoSeries(dest_graph_flows.neighbor).get_coordinates().values
)

arc_layer = ArcLayer(
    table=dest_lines[['weight', 'geometry']].to_arrow(),
    get_width=dest_lines.weight.apply(lambda x: x**.7),
    get_source_position=origins,
    get_target_position=destinations,
    opacity=0.4,
    pickable=False,
    extensions=[brushing_extension],
    brushing_radius=brushing_radius,
    get_source_color=get_color_array(dest_lines.weight**.8, scheme='fisher_jenks', k=10, cmap='inferno_r'),
    get_target_color=get_color_array(dest_lines.weight**.6, scheme='fisher_jenks', k=10, cmap='inferno_r')
)
gmap = Map(layers=[bounds, src, tgt, arc_layer,ogb], picking_radius=500)

gmap.to_html('dc_flow_dest_orient.html')

gmap

This map is keyed on destination, so mousing over each observation shows flows migrating into the pointer.

3.4 Spatial Interaction Models

Spatial interaction models are a classic regional science technique for modeling flows (migration, commuting, trading, etc). Spatial interaction models try to explain these flows between origin and destination as a function of origin (push) and destination (pull) factors, attenuated by the cost of traveling between them. The PySAL spint package implements a custom estimation engine designed for fast performance on sparse design matrices (like those typical in spatial interaction models), but they can also be fit using conventional statistical packages like statsmodels albeit with a performance downgrade.

In this model, the dependent variable \(y\) is the level of flow between an origin and destination. Our Graph is based on flows, which means \(y\) is the value of the “weight” held in dc_flow_graph, thus can use the adjacency list as our core data structure.

Describing spatial interaction with an equation has a long and storied history, with Carrothers (1956), Sen and Smith (1995), and Farmer and Oshan (2017), among many others, furnishing point-in-time reviews of this topic in terms of its popular gravity model formulation, whose general form is as follows:

\[F_{ij} = g[O_i, D_j, f(d_{ij})] \tag{3.1}\]

where \(F_{ij}\) denotes the flow between origin \(i\) and destination \(j\) areal units, \(O_i\) is some attribute variable(s) quantifying relevant features of origin \(i\), \(D_j\) is some attribute variable(s) quantifying relevant features of destination \(j\), \(g\) is some function (frequently multiplicative in form), and \(f(d_{ij})\) is some deterrent. The initial functional form resulted in Eq. (7.1) being transformed to a log-linear version and a normally distributed error attached to it for estimation and inference purposes, yielding

\[ log(F_{ij} + \delta) = log(\kappa) + \alpha log(O_i) + \beta log(D_j) + \gamma d_{ij} + \epsilon_{ij} \tag{3.2}\]

where log denotes natural logarithm, \(\epsilon_{ij}\) is a normally distributed random error term, \(\delta \geq 0\) added to the response variable \(F_{ij}\) is a translation parameter needed if any \(F_{ij} = 0\), and \(\kappa, \alpha, \beta\) and \(\gamma\) are linear regression coefficients; sometimes this equation includes \(log(d_{ij})\) rather than \(d_{ij}\). This specification results in exponents for the \(O_i\) and \(D_j\) variables when the equation is backtransformed to its multiplicative form. Difficulties associated with this implementation include that \(F_{ij}\) often is a count for which many cases are zero (hence the need for \(\delta\)).

Griffith, Chun, and Li (2019)

Given spatial interaction modeling’s rich history in regional science, there are many good resources, both old and new, including Getis (1991), Putman and Chung (1989), Griffith, Chun, and Li (2019), and Fotheringham and O’Kelly (1989) (as usual, there’s an insane Tobler paper on the topic (Tobler 1983)). The U.S. International Trade Commission also has a Python statistical package for estimating gravity models (though with no emphasis on space), as well as a nice paper on different estimators and their tradeoffs.

dc_flow_graph = dc_flow_graph.assign_self_weight(0).eliminate_zeros()

we use the flow graph as the basis for our new data structure

# sparse representation
dc_interaction = (
    dc_flow_graph.assign_self_weight(0).eliminate_zeros().adjacency.reset_index()
)
dc_interaction
focal neighbor weight
0 11001000101 11001000102 23
1 11001000101 11001000202 12
2 11001000101 11001000703 1
3 11001000101 11001000704 1
4 11001000101 11001000804 2
... ... ... ...
23096 11001980000 11001006900 1
23097 11001980000 11001009400 1
23098 11001980000 11001009510 2
23099 11001980000 11001010100 3
23100 11001980000 11001010202 2

23101 rows × 3 columns

but we actually need the full dense representation (with the zeroes)

# for our dataset we want the full dense matrix
dc_interaction = pd.Series(dc_flow_graph.sparse.toarray().reshape(-1), 
                             index=pd.MultiIndex.from_product([dc_flow_graph.unique_ids, 
                                                               dc_flow_graph.unique_ids.rename('neighbor')])).rename('weight')
dc_interaction = dc_interaction.reset_index()
dc_interaction
focal neighbor weight
0 11001000101 11001000101 0.0
1 11001000101 11001000102 23.0
2 11001000101 11001000202 12.0
3 11001000101 11001000300 0.0
4 11001000101 11001000501 0.0
... ... ... ...
42431 11001980000 11001011002 0.0
42432 11001980000 11001011100 0.0
42433 11001980000 11001000201 0.0
42434 11001980000 11001006804 0.0
42435 11001980000 11001980000 0.0

42436 rows × 3 columns

in spatial interaction terms focal=origin and neighbor=destination, so we can attach attributes of origins and destinations by doing left-joins on the y-variable successively based on focal, then neighbor

# first merge origin attributes
dc_interaction = dc_interaction.merge(
    dc.drop(columns=["geometry"]), left_on="focal", right_index=True, how="left"
)
# now merge destination attributes
dc_interaction = dc_interaction.merge(
    dc.drop(columns=["geometry"]),
    left_on="neighbor",
    right_index=True,
    how="left",
    suffixes=["_origin", "_destination"],
)

note the suffixes differentiate columns referring to origin and destination values, e.g. median_household_income_origin and median_household_income_destination

dc_interaction
focal neighbor weight n_mexican_pop_origin n_cuban_pop_origin n_puerto_rican_pop_origin n_russian_pop_origin n_italian_pop_origin n_german_pop_origin n_irish_pop_origin ... p_veterans_destination p_poverty_rate_destination p_poverty_rate_over_65_destination p_poverty_rate_children_destination p_poverty_rate_white_destination p_poverty_rate_black_destination p_poverty_rate_hispanic_destination p_poverty_rate_native_destination p_poverty_rate_asian_destination year_destination
0 11001000101 11001000101 0.0 102.0 0.0 0.0 0.0 68.0 26.0 59.0 ... 6.245121 2.341920 0.000000 0.000000 2.341920 0.000000 2.341920 0.000000 0.0 2021
1 11001000101 11001000102 23.0 102.0 0.0 0.0 0.0 68.0 26.0 59.0 ... 6.073753 6.724512 1.487450 1.456461 4.834211 0.000000 0.000000 0.000000 0.0 2021
2 11001000101 11001000202 12.0 102.0 0.0 0.0 0.0 68.0 26.0 59.0 ... 3.525424 12.948793 2.472042 0.000000 10.829900 0.588582 0.824014 0.000000 0.0 2021
3 11001000101 11001000300 0.0 102.0 0.0 0.0 0.0 68.0 26.0 59.0 ... 0.838082 13.308750 0.301710 0.201140 12.504190 0.000000 0.620181 0.000000 0.0 2021
4 11001000101 11001000501 0.0 102.0 0.0 0.0 0.0 68.0 26.0 59.0 ... 0.993571 8.556307 1.705381 0.000000 2.087621 6.380476 0.529256 0.000000 0.0 2021
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
42431 11001980000 11001011002 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 9.414088 6.126617 3.335602 0.000000 6.126617 0.000000 0.000000 0.000000 0.0 2021
42432 11001980000 11001011100 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 3.466872 17.596308 1.645265 0.000000 0.521669 17.074639 0.100321 0.000000 0.0 2021
42433 11001980000 11001000201 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.177755 19.402985 0.000000 0.000000 16.417910 2.985075 0.000000 0.000000 0.0 2021
42434 11001980000 11001006804 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 2.166193 55.902778 31.597222 0.000000 11.805556 39.236111 2.083333 4.861111 0.0 2021
42435 11001980000 11001980000 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.0 2021

42436 rows × 315 columns

dc_interaction[
    ["weight", "median_household_income_origin", "median_household_income_destination"]
]
weight median_household_income_origin median_household_income_destination
0 0.0 157276.0 157276.0
1 23.0 157276.0 166816.0
2 12.0 157276.0 161490.0
3 0.0 157276.0 159714.0
4 0.0 157276.0 109363.0
... ... ... ...
42431 0.0 NaN 110594.0
42432 0.0 NaN 74213.0
42433 0.0 NaN NaN
42434 0.0 NaN 250001.0
42435 0.0 NaN NaN

42436 rows × 3 columns

for a spatial interaction model we also need another Graph that measures the distance between observations. There are many ways to do this, but the easiest is to use a distance band weight where all observations are guaranteed to lie within the threshold (giving us a pairwise matrix)

dc = dc.to_crs(dc.estimate_utm_crs())

keep only tracts in the dataframe in our flow graph (origins), then get distance between observations with no decay

dc = dc[dc.index.isin(dc_flow_graph.unique_ids)]
dc_dist = Graph.build_distance_band(
    dc.set_geometry(dc.centroid), threshold=1e20, binary=False, alpha=1
)
dc_dist.summary()
Graph Summary Statistics
Number of nodes: 206
Number of edges: 42230
Number of connected components: 1
Number of isolates: 0
Number of non-zero edges: 42230
Percentage of non-zero edges: 99.51%
Number of asymmetries: NA
Sum of weights and Traces
S0: 264750122 GG: 2148736844278
S1: 4297473688556 G'G: 2148736844278
S3: 1435759541759836 G'G + GG: 4297473688556
Graph indexed by: ['11001000101', '11001000102', '11001000201', '1100100020...]
dc_dist.adjacency
focal        neighbor   
11001000101  11001000102     673.024487
             11001000201    1714.423693
             11001000202    1318.286816
             11001000300    2086.439842
             11001000400    1954.193812
                               ...     
11001980000  11001010800    2075.840579
             11001010900    7660.568101
             11001011001    1816.050530
             11001011002    1999.546509
             11001011100    7177.371175
Name: weight, Length: 42230, dtype: float64
# subset the distance graph by the travel graph (remove destinations we dont need)
# but this resets weights to 1
dc_dist_adj = dc_dist.intersection(dc_flow_graph).adjacency
# update with the old values
dc_dist_adj.update(dc_dist.adjacency)
/var/folders/j8/5bgcw6hs7cqcbbz48d6bsftw0000gp/T/ipykernel_24509/3611604903.py:2: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '[ 673.02448689 1714.42369324 1318.28681649 ... 7734.28131571 2519.49437645
  989.25225739]' has dtype incompatible with int8, please explicitly cast to a compatible dtype first.
  dc_dist_adj.update(dc_dist.adjacency)
dc_interaction["distance"] = dc_dist.sparse.toarray().reshape(-1)
dc_interaction['weight'] = dc_interaction['weight'].astype(int)

finally, we’ll do some simple cleanup since we have missing values etc.

# mean-impute missing values
dc_interaction = dc_interaction.fillna(dc_interaction.mean(numeric_only=True))

# increment cols by 1 to make logs easier
dc_interaction['distance'] = dc_interaction['distance'] +1

dc_interaction['n_total_pop_origin'] = dc_interaction['n_total_pop_origin'] +1
dc_interaction['n_total__pop_destination'] = dc_interaction['n_total_pop_destination'] +1

dc_interaction['p_nonhisp_black_persons_origin'] = dc_interaction['p_nonhisp_black_persons_origin'] +1
dc_interaction['p_nonhisp_black_persons_destination'] = dc_interaction['p_nonhisp_black_persons_destination'] +1

dc_interaction = dc_interaction.copy()
/var/folders/j8/5bgcw6hs7cqcbbz48d6bsftw0000gp/T/ipykernel_24509/3950422283.py:8: PerformanceWarning: DataFrame is highly fragmented.  This is usually the result of calling `frame.insert` many times, which has poor performance.  Consider joining all columns at once using pd.concat(axis=1) instead. To get a de-fragmented frame, use `newframe = frame.copy()`
  dc_interaction['n_total__pop_destination'] = dc_interaction['n_total_pop_destination'] +1
dc_interaction
focal neighbor weight n_mexican_pop_origin n_cuban_pop_origin n_puerto_rican_pop_origin n_russian_pop_origin n_italian_pop_origin n_german_pop_origin n_irish_pop_origin ... p_poverty_rate_over_65_destination p_poverty_rate_children_destination p_poverty_rate_white_destination p_poverty_rate_black_destination p_poverty_rate_hispanic_destination p_poverty_rate_native_destination p_poverty_rate_asian_destination year_destination distance n_total__pop_destination
0 11001000101 11001000101 0 102.0 0.0 0.0 0.0 68.0 26.0 59.0 ... 0.000000 0.000000 2.341920 0.000000 2.341920 0.000000 0.0 2021 1.000000 1282.0
1 11001000101 11001000102 23 102.0 0.0 0.0 0.0 68.0 26.0 59.0 ... 1.487450 1.456461 4.834211 0.000000 0.000000 0.000000 0.0 2021 674.024487 3228.0
2 11001000101 11001000202 12 102.0 0.0 0.0 0.0 68.0 26.0 59.0 ... 2.472042 0.000000 10.829900 0.588582 0.824014 0.000000 0.0 2021 1715.423693 4426.0
3 11001000101 11001000300 0 102.0 0.0 0.0 0.0 68.0 26.0 59.0 ... 0.301710 0.201140 12.504190 0.000000 0.620181 0.000000 0.0 2021 1319.286816 5967.0
4 11001000101 11001000501 0 102.0 0.0 0.0 0.0 68.0 26.0 59.0 ... 1.705381 0.000000 2.087621 6.380476 0.529256 0.000000 0.0 2021 2087.439842 3423.0
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
42431 11001980000 11001011002 0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 3.335602 0.000000 6.126617 0.000000 0.000000 0.000000 0.0 2021 7661.568101 1520.0
42432 11001980000 11001011100 0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 1.645265 0.000000 0.521669 17.074639 0.100321 0.000000 0.0 2021 1817.050530 5193.0
42433 11001980000 11001000201 0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.000000 0.000000 16.417910 2.985075 0.000000 0.000000 0.0 2021 2000.546509 3939.0
42434 11001980000 11001006804 0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 31.597222 0.000000 11.805556 39.236111 2.083333 4.861111 0.0 2021 7178.371175 2817.0
42435 11001980000 11001980000 0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.0 2021 1.000000 18.0

42436 rows × 317 columns

3.5 Using spint and statsmodels

The spint package implements a family of SI models in the Wilson (1967) via a generalized linear modeling framework with a Poisson link function, which is generally viewed as a statistically-sound approach (Liao and Oshan 2025; Oshan 2016, 2021; Oshan and Liao 2025; Rey et al. 2021). See Oshan (2016) for a deeper discussion of spatial interaction models and their implementation details in PySAL. You can also fit the same models using statsmodels for more verbose output, albeit at a performance cost.

In thie example, we explore the influences of population size, income, and race (at origin and destination locations) on the total flow moving between origin and destination. Though this is a toy example, this approach combines traditional interaction variables i.e. gravity driven by population size) with an inquiry about social inequality. Since D.C. is such a famously segregated city, it may be that predominantly Black neighbrhoods are greater exporters than importers, like the spatial mismatch hypothesis suggests (Glaeser, Hanushek, and Quigley 2004; Kain 1968, 1992).

3.5.1 Gravity

g = Gravity(
    dc_interaction["weight"].values,
    o_vars=dc_interaction[["n_total_pop_origin", "median_household_income_origin", "p_nonhisp_black_persons_origin"]].values,
    d_vars=dc_interaction[
        ["n_total_pop_destination", "median_household_income_destination",  "p_nonhisp_black_persons_destination"]
    ]
    .values,
    cost=dc_interaction["distance"],
    cost_func="exp",
    constant=True,
).fit()
g.params
array([-1.30328257e+00,  6.72022888e-01,  1.40801006e-01,  4.76000489e-02,
       -2.84857860e-01, -4.83240629e-02, -4.79830945e-01, -2.88418095e-05])
g.adj_pseudoR2
np.float64(0.2064445085777441)
dc_interaction["distance"]
0           1.000000
1         674.024487
2        1715.423693
3        1319.286816
4        2087.439842
            ...     
42431    7661.568101
42432    1817.050530
42433    2000.546509
42434    7178.371175
42435       1.000000
Name: distance, Length: 42436, dtype: float64
g_statsmodels = smf.glm(
    "weight ~ 1 + np.log(n_total_pop_origin) + np.log(median_household_income_origin) + np.log(p_nonhisp_black_persons_origin) + np.log(n_total_pop_destination) + np.log(median_household_income_destination) + np.log(p_nonhisp_black_persons_destination) + distance",
    family=families.Poisson(),
    data=dc_interaction,).fit(cov_type='HC0', scale='X2')
g_statsmodels.summary()
Generalized Linear Model Regression Results
Dep. Variable: weight No. Observations: 42436
Model: GLM Df Residuals: 42428
Model Family: Poisson Df Model: 7
Link Function: Log Scale: 28.247
Method: IRLS Log-Likelihood: -10249.
Date: Thu, 24 Jul 2025 Deviance: 5.0560e+05
Time: 23:22:05 Pearson chi2: 1.20e+06
No. Iterations: 9 Pseudo R-squ. (CS): 0.1181
Covariance Type: HC0
coef std err z P>|z| [0.025 0.975]
Intercept -1.3110 0.636 -2.063 0.039 -2.557 -0.065
np.log(n_total_pop_origin) 0.6721 0.044 15.110 0.000 0.585 0.759
np.log(median_household_income_origin) 0.1408 0.029 4.817 0.000 0.084 0.198
np.log(p_nonhisp_black_persons_origin) 0.0476 0.018 2.660 0.008 0.013 0.083
np.log(n_total_pop_destination) -0.2850 0.009 -31.810 0.000 -0.303 -0.267
np.log(median_household_income_destination) -0.0478 0.033 -1.457 0.145 -0.112 0.016
np.log(p_nonhisp_black_persons_destination) -0.4794 0.012 -38.890 0.000 -0.504 -0.455
distance -2.884e-05 4.53e-06 -6.361 0.000 -3.77e-05 -2e-05
g.params.round(4)
array([-1.3033,  0.672 ,  0.1408,  0.0476, -0.2849, -0.0483, -0.4798,
       -0.    ])
out = g_statsmodels.params.rename("statsmdodels").to_frame().copy()
out["spint"] = g.params.T.round(4)

compare coefs in a table format

out
statsmdodels spint
Intercept -1.311015 -1.3033
np.log(n_total_pop_origin) 0.672147 0.6720
np.log(median_household_income_origin) 0.140799 0.1408
np.log(p_nonhisp_black_persons_origin) 0.047622 0.0476
np.log(n_total_pop_destination) -0.285020 -0.2849
np.log(median_household_income_destination) -0.047778 -0.0483
np.log(p_nonhisp_black_persons_destination) -0.479354 -0.4798
distance -0.000029 -0.0000

3.5.2 Production-Constrained

unit-level fixed effects for origins

mod_prod = Production(
    dc_interaction["weight"].values,
    dc_interaction["focal"].values,
    d_vars=dc_interaction[
        ["n_total_pop_destination", "median_household_income_destination", "p_nonhisp_black_persons_destination"]
    ]
    .values,
    cost=dc_interaction["distance"].values,
    cost_func="exp",
).fit()
mod_prod.params[-4:]
array([-2.84911877e-01, -5.07558277e-02, -4.80596880e-01, -3.39053694e-05])
mod_prod.adj_pseudoR2
np.float64(0.23213835591897392)

also do the power version/

mod_prod_pow = Production(
    dc_interaction["weight"].values,
    dc_interaction["focal"].values,
    d_vars=dc_interaction[
        ["n_total_pop_destination", "median_household_income_destination", "p_nonhisp_black_persons_destination"]
    ]
    .values,
    cost=dc_interaction["distance"].values,
    cost_func="pow",
).fit()
mod_prod_pow.params[-4:]
array([-0.28759278, -0.04250044, -0.47854842, -0.03982813])
mod_prod_pow.adj_pseudoR2
np.float64(0.22975444627289543)

3.5.3 Attraction-Constrained

unit-level fixed effects for destinations

mod_attr = Attraction(
    flows=dc_interaction["weight"].values,
    destinations=dc_interaction["neighbor"].values,
    o_vars=dc_interaction[["n_total_pop_origin", "median_household_income_origin",  "p_nonhisp_black_persons_origin"]]
    .values,
    cost=dc_interaction["distance"].values,
    cost_func="exp",
)

the constrained models can be calibrated locally, i.e. each observation has its own set of coefficients, thus we can map the effect of a given parameter, say distance:

attr_local = pd.DataFrame(mod_attr.local())
attr_local.columns
Index(['AIC', 'deviance', 'pseudoR2', 'adj_pseudoR2', 'D2', 'adj_D2', 'SSI',
       'SRMSE', 'param0', 'stde0', 'pvalue0', 'tvalue0', 'param1', 'stde1',
       'pvalue1', 'tvalue1', 'param2', 'stde2', 'pvalue2', 'tvalue2', 'param3',
       'stde3', 'pvalue3', 'tvalue3'],
      dtype='object')
dc.assign(dist=attr_local['param3'].values).explore('dist', scheme='quantiles', tooltip='dist',  cmap='RdBu_r',   style_kwds={"weight": 0.5},
 tiles='cartodb positron')
Make this Notebook Trusted to load map: File -> Trust Notebook
mod_attr.fit()
<spint.count_model.CountModelResults at 0x35066dc70>
mod_attr.params[-4:]
array([ 6.74477248e-01,  1.45735531e-01,  4.61204174e-02, -1.19007021e-05])
mod_attr.pseudoR2
np.float64(0.7394749340844884)
# attraction-constrained
a_statsmodels = smf.glm(
    "weight ~ 1 + I(neighbor) + np.log(n_total_pop_origin) + np.log(median_household_income_origin) + np.log(p_nonhisp_black_persons_origin) + distance",
    family=families.Poisson(),
    data=dc_interaction
).fit()
a_statsmodels.summary()
Generalized Linear Model Regression Results
Dep. Variable: weight No. Observations: 42436
Model: GLM Df Residuals: 42226
Model Family: Poisson Df Model: 209
Link Function: Log Scale: 1.0000
Method: IRLS Log-Likelihood: -94971.
Date: Thu, 24 Jul 2025 Deviance: 1.1656e+05
Time: 23:22:10 Pearson chi2: 1.32e+05
No. Iterations: 8 Pseudo R-squ. (CS): 1.000
Covariance Type: nonrobust
coef std err z P>|z| [0.025 0.975]
Intercept -7.7468 0.120 -64.487 0.000 -7.982 -7.511
I(neighbor)[T.11001000102] 3.1373 0.090 34.880 0.000 2.961 3.314
I(neighbor)[T.11001000201] 3.4699 0.089 38.804 0.000 3.295 3.645
I(neighbor)[T.11001000202] 2.8744 0.091 31.750 0.000 2.697 3.052
I(neighbor)[T.11001000300] 0.7745 0.107 7.265 0.000 0.566 0.983
I(neighbor)[T.11001000400] 1.4074 0.098 14.335 0.000 1.215 1.600
I(neighbor)[T.11001000501] 1.1021 0.102 10.826 0.000 0.903 1.302
I(neighbor)[T.11001000502] 0.3071 0.116 2.649 0.008 0.080 0.534
I(neighbor)[T.11001000600] 1.4798 0.098 15.175 0.000 1.289 1.671
I(neighbor)[T.11001000702] -0.9011 0.164 -5.485 0.000 -1.223 -0.579
I(neighbor)[T.11001000703] -1.4589 0.203 -7.198 0.000 -1.856 -1.062
I(neighbor)[T.11001000704] -0.6504 0.151 -4.319 0.000 -0.946 -0.355
I(neighbor)[T.11001000802] 0.6872 0.108 6.373 0.000 0.476 0.899
I(neighbor)[T.11001000803] 0.6246 0.109 5.713 0.000 0.410 0.839
I(neighbor)[T.11001000804] 1.0396 0.103 10.127 0.000 0.838 1.241
I(neighbor)[T.11001000902] 0.2520 0.118 2.139 0.032 0.021 0.483
I(neighbor)[T.11001000903] 2.2282 0.093 24.048 0.000 2.047 2.410
I(neighbor)[T.11001000904] 1.7655 0.095 18.540 0.000 1.579 1.952
I(neighbor)[T.11001001002] 2.1743 0.093 23.408 0.000 1.992 2.356
I(neighbor)[T.11001001003] -0.0901 0.127 -0.709 0.479 -0.339 0.159
I(neighbor)[T.11001001004] 1.8086 0.095 19.019 0.000 1.622 1.995
I(neighbor)[T.11001001100] 2.5528 0.091 27.937 0.000 2.374 2.732
I(neighbor)[T.11001001200] 1.6829 0.096 17.518 0.000 1.495 1.871
I(neighbor)[T.11001001301] -0.1733 0.131 -1.322 0.186 -0.430 0.084
I(neighbor)[T.11001001303] 1.2923 0.100 12.960 0.000 1.097 1.488
I(neighbor)[T.11001001304] 0.6917 0.109 6.365 0.000 0.479 0.905
I(neighbor)[T.11001001401] 0.2941 0.116 2.534 0.011 0.067 0.522
I(neighbor)[T.11001001402] 1.1050 0.102 10.831 0.000 0.905 1.305
I(neighbor)[T.11001001500] 0.6816 0.108 6.321 0.000 0.470 0.893
I(neighbor)[T.11001001600] 1.9566 0.094 20.813 0.000 1.772 2.141
I(neighbor)[T.11001001702] 1.3299 0.099 13.447 0.000 1.136 1.524
I(neighbor)[T.11001001803] -1.1805 0.185 -6.395 0.000 -1.542 -0.819
I(neighbor)[T.11001001804] -0.0585 0.126 -0.465 0.642 -0.306 0.188
I(neighbor)[T.11001001901] 1.8317 0.095 19.330 0.000 1.646 2.017
I(neighbor)[T.11001001902] 0.3712 0.115 3.229 0.001 0.146 0.597
I(neighbor)[T.11001002001] 0.3759 0.114 3.295 0.001 0.152 0.600
I(neighbor)[T.11001002002] 0.2936 0.116 2.530 0.011 0.066 0.521
I(neighbor)[T.11001002101] 1.0348 0.102 10.110 0.000 0.834 1.235
I(neighbor)[T.11001002102] 0.4956 0.111 4.446 0.000 0.277 0.714
I(neighbor)[T.11001002201] -0.1581 0.131 -1.206 0.228 -0.415 0.099
I(neighbor)[T.11001002202] -1.3433 0.193 -6.968 0.000 -1.721 -0.965
I(neighbor)[T.11001002301] -0.1697 0.130 -1.307 0.191 -0.424 0.085
I(neighbor)[T.11001002302] 3.5550 0.089 39.817 0.000 3.380 3.730
I(neighbor)[T.11001002400] 0.8142 0.106 7.659 0.000 0.606 1.023
I(neighbor)[T.11001002501] 0.7452 0.108 6.932 0.000 0.535 0.956
I(neighbor)[T.11001002503] 0.9686 0.103 9.378 0.000 0.766 1.171
I(neighbor)[T.11001002504] -0.3571 0.137 -2.608 0.009 -0.625 -0.089
I(neighbor)[T.11001002600] -0.4700 0.143 -3.290 0.001 -0.750 -0.190
I(neighbor)[T.11001002702] 0.7106 0.108 6.590 0.000 0.499 0.922
I(neighbor)[T.11001002703] 0.2445 0.117 2.083 0.037 0.014 0.475
I(neighbor)[T.11001002704] -0.3402 0.136 -2.493 0.013 -0.608 -0.073
I(neighbor)[T.11001002801] 0.0422 0.124 0.341 0.733 -0.200 0.284
I(neighbor)[T.11001002802] 1.7845 0.095 18.747 0.000 1.598 1.971
I(neighbor)[T.11001002900] 1.1590 0.101 11.491 0.000 0.961 1.357
I(neighbor)[T.11001003000] 0.1594 0.121 1.319 0.187 -0.077 0.396
I(neighbor)[T.11001003100] 0.9138 0.105 8.732 0.000 0.709 1.119
I(neighbor)[T.11001003200] 0.6058 0.110 5.497 0.000 0.390 0.822
I(neighbor)[T.11001003301] -0.1879 0.131 -1.437 0.151 -0.444 0.068
I(neighbor)[T.11001003302] 0.1405 0.122 1.155 0.248 -0.098 0.379
I(neighbor)[T.11001003400] 2.3600 0.092 25.621 0.000 2.179 2.541
I(neighbor)[T.11001003500] 1.6378 0.096 16.978 0.000 1.449 1.827
I(neighbor)[T.11001003600] 0.8725 0.105 8.290 0.000 0.666 1.079
I(neighbor)[T.11001003701] 0.2179 0.118 1.841 0.066 -0.014 0.450
I(neighbor)[T.11001003702] -0.5118 0.143 -3.568 0.000 -0.793 -0.231
I(neighbor)[T.11001003801] 1.4513 0.098 14.848 0.000 1.260 1.643
I(neighbor)[T.11001003802] 1.4861 0.097 15.254 0.000 1.295 1.677
I(neighbor)[T.11001003901] 0.7731 0.107 7.253 0.000 0.564 0.982
I(neighbor)[T.11001003902] 0.0080 0.125 0.064 0.949 -0.237 0.253
I(neighbor)[T.11001004001] 0.6793 0.108 6.287 0.000 0.467 0.891
I(neighbor)[T.11001004002] 2.0755 0.094 22.192 0.000 1.892 2.259
I(neighbor)[T.11001004100] 0.6419 0.109 5.905 0.000 0.429 0.855
I(neighbor)[T.11001004201] 1.6202 0.096 16.816 0.000 1.431 1.809
I(neighbor)[T.11001004202] 1.9987 0.094 21.300 0.000 1.815 2.183
I(neighbor)[T.11001004300] 1.7464 0.096 18.274 0.000 1.559 1.934
I(neighbor)[T.11001004401] 1.8972 0.094 20.089 0.000 1.712 2.082
I(neighbor)[T.11001004402] 1.6414 0.096 17.039 0.000 1.453 1.830
I(neighbor)[T.11001004600] 1.8355 0.095 19.347 0.000 1.650 2.021
I(neighbor)[T.11001004702] 2.7927 0.091 30.778 0.000 2.615 2.971
I(neighbor)[T.11001004703] 1.2668 0.100 12.700 0.000 1.071 1.462
I(neighbor)[T.11001004704] 0.6303 0.109 5.782 0.000 0.417 0.844
I(neighbor)[T.11001004801] 2.3290 0.092 25.251 0.000 2.148 2.510
I(neighbor)[T.11001004802] 1.8692 0.095 19.754 0.000 1.684 2.055
I(neighbor)[T.11001004901] 1.3067 0.099 13.158 0.000 1.112 1.501
I(neighbor)[T.11001004902] 2.1649 0.093 23.287 0.000 1.983 2.347
I(neighbor)[T.11001005001] 1.2067 0.100 12.008 0.000 1.010 1.404
I(neighbor)[T.11001005003] 1.2464 0.100 12.468 0.000 1.050 1.442
I(neighbor)[T.11001005004] -0.0175 0.125 -0.140 0.889 -0.263 0.228
I(neighbor)[T.11001005202] 1.8055 0.095 19.002 0.000 1.619 1.992
I(neighbor)[T.11001005203] 1.4658 0.098 15.012 0.000 1.274 1.657
I(neighbor)[T.11001005302] 1.1004 0.102 10.824 0.000 0.901 1.300
I(neighbor)[T.11001005303] 2.3340 0.092 25.311 0.000 2.153 2.515
I(neighbor)[T.11001005501] 3.6967 0.089 41.441 0.000 3.522 3.872
I(neighbor)[T.11001005502] 2.5902 0.091 28.326 0.000 2.411 2.769
I(neighbor)[T.11001005503] 2.4465 0.092 26.653 0.000 2.267 2.626
I(neighbor)[T.11001005601] 1.2029 0.101 11.962 0.000 1.006 1.400
I(neighbor)[T.11001005602] 2.1019 0.093 22.489 0.000 1.919 2.285
I(neighbor)[T.11001005801] 3.6990 0.089 41.478 0.000 3.524 3.874
I(neighbor)[T.11001005802] 5.0321 0.088 56.956 0.000 4.859 5.205
I(neighbor)[T.11001005900] 3.5547 0.089 39.792 0.000 3.380 3.730
I(neighbor)[T.11001006400] 0.6191 0.109 5.670 0.000 0.405 0.833
I(neighbor)[T.11001006500] 2.2543 0.093 24.316 0.000 2.073 2.436
I(neighbor)[T.11001006600] 1.7724 0.096 18.556 0.000 1.585 1.960
I(neighbor)[T.11001006700] 1.5424 0.097 15.859 0.000 1.352 1.733
I(neighbor)[T.11001006801] -0.6552 0.151 -4.329 0.000 -0.952 -0.359
I(neighbor)[T.11001006802] 0.1838 0.120 1.536 0.125 -0.051 0.418
I(neighbor)[T.11001006804] 0.4948 0.112 4.423 0.000 0.276 0.714
I(neighbor)[T.11001006900] 1.2475 0.100 12.472 0.000 1.051 1.444
I(neighbor)[T.11001007000] 1.9211 0.094 20.333 0.000 1.736 2.106
I(neighbor)[T.11001007100] 1.1790 0.101 11.678 0.000 0.981 1.377
I(neighbor)[T.11001007201] 2.2570 0.093 24.390 0.000 2.076 2.438
I(neighbor)[T.11001007202] 1.6971 0.096 17.695 0.000 1.509 1.885
I(neighbor)[T.11001007203] 2.4599 0.092 26.790 0.000 2.280 2.640
I(neighbor)[T.11001007301] 0.4629 0.113 4.091 0.000 0.241 0.685
I(neighbor)[T.11001007304] 0.7059 0.108 6.546 0.000 0.495 0.917
I(neighbor)[T.11001007401] 0.1772 0.120 1.480 0.139 -0.057 0.412
I(neighbor)[T.11001007403] -0.8102 0.160 -5.063 0.000 -1.124 -0.497
I(neighbor)[T.11001007404] -1.4864 0.206 -7.232 0.000 -1.889 -1.084
I(neighbor)[T.11001007406] -0.3305 0.136 -2.430 0.015 -0.597 -0.064
I(neighbor)[T.11001007407] -0.6377 0.151 -4.214 0.000 -0.934 -0.341
I(neighbor)[T.11001007408] -0.1747 0.131 -1.329 0.184 -0.432 0.083
I(neighbor)[T.11001007409] -0.4120 0.141 -2.917 0.004 -0.689 -0.135
I(neighbor)[T.11001007502] 0.1532 0.121 1.264 0.206 -0.084 0.391
I(neighbor)[T.11001007503] 1.3348 0.099 13.442 0.000 1.140 1.529
I(neighbor)[T.11001007504] -0.2860 0.134 -2.128 0.033 -0.549 -0.023
I(neighbor)[T.11001007601] 0.4407 0.113 3.903 0.000 0.219 0.662
I(neighbor)[T.11001007603] 0.2181 0.118 1.846 0.065 -0.014 0.450
I(neighbor)[T.11001007604] -0.6119 0.148 -4.122 0.000 -0.903 -0.321
I(neighbor)[T.11001007605] -0.3083 0.135 -2.280 0.023 -0.573 -0.043
I(neighbor)[T.11001007703] -0.3536 0.137 -2.583 0.010 -0.622 -0.085
I(neighbor)[T.11001007707] -1.3104 0.191 -6.875 0.000 -1.684 -0.937
I(neighbor)[T.11001007708] -1.4019 0.197 -7.098 0.000 -1.789 -1.015
I(neighbor)[T.11001007709] -1.0379 0.172 -6.044 0.000 -1.374 -0.701
I(neighbor)[T.11001007803] 1.4294 0.098 14.584 0.000 1.237 1.622
I(neighbor)[T.11001007804] 0.4127 0.113 3.640 0.000 0.190 0.635
I(neighbor)[T.11001007806] -0.3551 0.137 -2.594 0.009 -0.623 -0.087
I(neighbor)[T.11001007807] -1.7791 0.231 -7.713 0.000 -2.231 -1.327
I(neighbor)[T.11001007808] -0.0670 0.127 -0.529 0.597 -0.315 0.181
I(neighbor)[T.11001007809] -0.1239 0.128 -0.966 0.334 -0.375 0.127
I(neighbor)[T.11001007901] 0.5594 0.110 5.073 0.000 0.343 0.775
I(neighbor)[T.11001007903] -0.7701 0.156 -4.928 0.000 -1.076 -0.464
I(neighbor)[T.11001008001] 0.7079 0.107 6.586 0.000 0.497 0.919
I(neighbor)[T.11001008002] 0.6745 0.108 6.243 0.000 0.463 0.886
I(neighbor)[T.11001008100] 0.1901 0.119 1.599 0.110 -0.043 0.423
I(neighbor)[T.11001008200] 1.3882 0.098 14.108 0.000 1.195 1.581
I(neighbor)[T.11001008301] 1.3839 0.098 14.056 0.000 1.191 1.577
I(neighbor)[T.11001008302] 1.2899 0.099 12.972 0.000 1.095 1.485
I(neighbor)[T.11001008402] 0.8752 0.105 8.328 0.000 0.669 1.081
I(neighbor)[T.11001008410] 0.6252 0.109 5.735 0.000 0.412 0.839
I(neighbor)[T.11001008701] 0.7956 0.106 7.506 0.000 0.588 1.003
I(neighbor)[T.11001008702] 0.7190 0.107 6.706 0.000 0.509 0.929
I(neighbor)[T.11001008802] 0.4855 0.112 4.344 0.000 0.266 0.705
I(neighbor)[T.11001008803] 2.4719 0.092 26.967 0.000 2.292 2.652
I(neighbor)[T.11001008804] 1.0422 0.102 10.185 0.000 0.842 1.243
I(neighbor)[T.11001008903] -0.5675 0.146 -3.875 0.000 -0.855 -0.280
I(neighbor)[T.11001008904] 0.6944 0.108 6.444 0.000 0.483 0.906
I(neighbor)[T.11001009000] 1.3149 0.099 13.244 0.000 1.120 1.510
I(neighbor)[T.11001009102] 2.4598 0.092 26.804 0.000 2.280 2.640
I(neighbor)[T.11001009201] 1.5087 0.097 15.520 0.000 1.318 1.699
I(neighbor)[T.11001009203] -0.8474 0.161 -5.262 0.000 -1.163 -0.532
I(neighbor)[T.11001009204] 1.2908 0.100 12.955 0.000 1.096 1.486
I(neighbor)[T.11001009301] 1.2102 0.101 12.038 0.000 1.013 1.407
I(neighbor)[T.11001009302] 0.8965 0.105 8.564 0.000 0.691 1.102
I(neighbor)[T.11001009400] 1.2076 0.100 12.019 0.000 1.011 1.404
I(neighbor)[T.11001009503] -0.5110 0.144 -3.549 0.000 -0.793 -0.229
I(neighbor)[T.11001009504] 1.9580 0.094 20.818 0.000 1.774 2.142
I(neighbor)[T.11001009505] 1.5636 0.097 16.164 0.000 1.374 1.753
I(neighbor)[T.11001009507] -2.3528 0.302 -7.796 0.000 -2.944 -1.761
I(neighbor)[T.11001009508] 0.0998 0.121 0.823 0.410 -0.138 0.337
I(neighbor)[T.11001009509] -0.0743 0.127 -0.583 0.560 -0.324 0.175
I(neighbor)[T.11001009510] 0.1091 0.122 0.895 0.371 -0.130 0.348
I(neighbor)[T.11001009511] -1.6115 0.215 -7.496 0.000 -2.033 -1.190
I(neighbor)[T.11001009601] -0.2521 0.134 -1.887 0.059 -0.514 0.010
I(neighbor)[T.11001009602] 0.1262 0.122 1.034 0.301 -0.113 0.366
I(neighbor)[T.11001009603] 1.2662 0.100 12.635 0.000 1.070 1.463
I(neighbor)[T.11001009604] 0.0853 0.123 0.691 0.489 -0.157 0.327
I(neighbor)[T.11001009700] -0.3999 0.141 -2.841 0.004 -0.676 -0.124
I(neighbor)[T.11001009801] -1.3133 0.191 -6.891 0.000 -1.687 -0.940
I(neighbor)[T.11001009802] -2.0500 0.265 -7.734 0.000 -2.570 -1.531
I(neighbor)[T.11001009803] -1.0842 0.175 -6.210 0.000 -1.426 -0.742
I(neighbor)[T.11001009804] -0.2259 0.134 -1.686 0.092 -0.489 0.037
I(neighbor)[T.11001009807] 0.3270 0.117 2.799 0.005 0.098 0.556
I(neighbor)[T.11001009810] -1.9747 0.258 -7.652 0.000 -2.480 -1.469
I(neighbor)[T.11001009811] 0.4945 0.112 4.408 0.000 0.275 0.714
I(neighbor)[T.11001009901] 0.6434 0.109 5.884 0.000 0.429 0.858
I(neighbor)[T.11001009902] -1.7727 0.235 -7.533 0.000 -2.234 -1.311
I(neighbor)[T.11001009903] -0.7473 0.157 -4.755 0.000 -1.055 -0.439
I(neighbor)[T.11001009904] -0.3421 0.138 -2.474 0.013 -0.613 -0.071
I(neighbor)[T.11001009905] -1.5338 0.212 -7.247 0.000 -1.949 -1.119
I(neighbor)[T.11001009906] -1.9398 0.252 -7.709 0.000 -2.433 -1.447
I(neighbor)[T.11001009907] -0.5915 0.147 -4.021 0.000 -0.880 -0.303
I(neighbor)[T.11001010100] 4.7682 0.088 53.927 0.000 4.595 4.941
I(neighbor)[T.11001010201] 0.6856 0.108 6.358 0.000 0.474 0.897
I(neighbor)[T.11001010202] 3.6719 0.089 41.184 0.000 3.497 3.847
I(neighbor)[T.11001010300] 0.7109 0.108 6.574 0.000 0.499 0.923
I(neighbor)[T.11001010400] 1.9867 0.094 21.120 0.000 1.802 2.171
I(neighbor)[T.11001010500] 2.0277 0.094 21.651 0.000 1.844 2.211
I(neighbor)[T.11001010601] 3.5802 0.089 40.113 0.000 3.405 3.755
I(neighbor)[T.11001010602] 2.1489 0.093 23.107 0.000 1.967 2.331
I(neighbor)[T.11001010603] 3.4056 0.089 38.059 0.000 3.230 3.581
I(neighbor)[T.11001010700] 5.3132 0.088 60.198 0.000 5.140 5.486
I(neighbor)[T.11001010800] 3.9496 0.089 44.434 0.000 3.775 4.124
I(neighbor)[T.11001010900] 0.8752 0.105 8.353 0.000 0.670 1.081
I(neighbor)[T.11001011001] -1.2830 0.188 -6.807 0.000 -1.652 -0.914
I(neighbor)[T.11001011002] 0.3415 0.117 2.919 0.004 0.112 0.571
I(neighbor)[T.11001011100] 2.5251 0.092 27.592 0.000 2.346 2.705
I(neighbor)[T.11001980000] 4.6257 0.088 52.281 0.000 4.452 4.799
np.log(n_total_pop_origin) 0.6802 0.007 96.874 0.000 0.666 0.694
np.log(median_household_income_origin) 0.1475 0.005 29.365 0.000 0.138 0.157
np.log(p_nonhisp_black_persons_origin) 0.0464 0.003 17.165 0.000 0.041 0.052
distance -1.183e-05 7.69e-07 -15.379 0.000 -1.33e-05 -1.03e-05
mod_attr.pseudoR2
np.float64(0.7394749340844884)
mod_attr.params[-4:].round(4)
array([ 0.6745,  0.1457,  0.0461, -0.    ])
a_statsmodels.params[-4:]
np.log(n_total_pop_origin)                0.680187
np.log(median_household_income_origin)    0.147455
np.log(p_nonhisp_black_persons_origin)    0.046415
distance                                 -0.000012
dtype: float64
# mcfadden
1 - (a_statsmodels.llf / a_statsmodels.llnull)
np.float64(0.7396697682685844)
# cohen
(a_statsmodels.null_deviance - a_statsmodels.deviance) / a_statsmodels.null_deviance
np.float64(0.822375364673833)
# CS
1 - np.exp((2 / a_statsmodels.nobs) * (a_statsmodels.llnull - a_statsmodels.llf))
np.float64(0.9999970016617493)
a_statsmodels.pseudo_rsquared()
np.float64(0.9999970016617493)

yep, the CS psueudo \(R^2\) matches the reported one

3.5.4 Doubly-Constrained

fixed effects for both origin and destination

d = Doubly(
    dc_interaction["weight"].values,
    dc_interaction["focal"].values,
    dc_interaction["neighbor"].values,
    cost=dc_interaction["distance"],
    cost_func="exp",
).fit()
d.adj_pseudoR2
np.float64(0.7644170768314439)
d.params[-1:].round(5)
array([-2.e-05])
d_statsmodels = smf.glm(
    "weight ~ 1 + C(focal) + C(neighbor) + distance",
    family=families.Poisson(),
    data=dc_interaction
).fit()
d_statsmodels.summary()
Generalized Linear Model Regression Results
Dep. Variable: weight No. Observations: 42436
Model: GLM Df Residuals: 42024
Model Family: Poisson Df Model: 411
Link Function: Log Scale: 1.0000
Method: IRLS Log-Likelihood: -85400.
Date: Thu, 24 Jul 2025 Deviance: 97423.
Time: 23:22:39 Pearson chi2: 1.16e+05
No. Iterations: 8 Pseudo R-squ. (CS): 1.000
Covariance Type: nonrobust
coef std err z P>|z| [0.025 0.975]
Intercept -1.1748 0.100 -11.723 0.000 -1.371 -0.978
C(focal)[T.11001000102] 0.5283 0.060 8.759 0.000 0.410 0.647
C(focal)[T.11001000201] -1.8993 0.132 -14.384 0.000 -2.158 -1.640
C(focal)[T.11001000202] 0.6000 0.060 10.044 0.000 0.483 0.717
C(focal)[T.11001000300] 1.2141 0.055 22.265 0.000 1.107 1.321
C(focal)[T.11001000400] 0.0840 0.066 1.269 0.205 -0.046 0.214
C(focal)[T.11001000501] 1.0136 0.056 18.091 0.000 0.904 1.123
C(focal)[T.11001000502] 0.8584 0.057 15.046 0.000 0.747 0.970
C(focal)[T.11001000600] 0.9553 0.056 16.992 0.000 0.845 1.066
C(focal)[T.11001000702] 0.8953 0.057 15.732 0.000 0.784 1.007
C(focal)[T.11001000703] 0.2330 0.064 3.634 0.000 0.107 0.359
C(focal)[T.11001000704] 0.4880 0.061 8.007 0.000 0.369 0.607
C(focal)[T.11001000802] 0.5885 0.060 9.886 0.000 0.472 0.705
C(focal)[T.11001000803] 0.1124 0.066 1.693 0.090 -0.018 0.242
C(focal)[T.11001000804] 0.4014 0.062 6.449 0.000 0.279 0.523
C(focal)[T.11001000902] 0.1208 0.066 1.821 0.069 -0.009 0.251
C(focal)[T.11001000903] -0.6744 0.082 -8.198 0.000 -0.836 -0.513
C(focal)[T.11001000904] 0.3101 0.063 4.939 0.000 0.187 0.433
C(focal)[T.11001001002] 0.5863 0.060 9.851 0.000 0.470 0.703
C(focal)[T.11001001003] 0.5258 0.060 8.742 0.000 0.408 0.644
C(focal)[T.11001001004] 0.8352 0.058 14.500 0.000 0.722 0.948
C(focal)[T.11001001100] 0.9782 0.056 17.474 0.000 0.868 1.088
C(focal)[T.11001001200] 1.2291 0.055 22.499 0.000 1.122 1.336
C(focal)[T.11001001301] 0.9887 0.056 17.516 0.000 0.878 1.099
C(focal)[T.11001001303] 0.8587 0.058 14.917 0.000 0.746 0.972
C(focal)[T.11001001304] 1.1985 0.055 21.716 0.000 1.090 1.307
C(focal)[T.11001001401] 0.6707 0.059 11.441 0.000 0.556 0.786
C(focal)[T.11001001402] 0.6937 0.059 11.692 0.000 0.577 0.810
C(focal)[T.11001001500] 1.1106 0.055 20.192 0.000 1.003 1.218
C(focal)[T.11001001600] 0.9158 0.056 16.237 0.000 0.805 1.026
C(focal)[T.11001001702] 0.8644 0.057 15.211 0.000 0.753 0.976
C(focal)[T.11001001803] 1.1341 0.056 20.369 0.000 1.025 1.243
C(focal)[T.11001001804] 1.2583 0.054 23.278 0.000 1.152 1.364
C(focal)[T.11001001901] 1.0475 0.055 18.896 0.000 0.939 1.156
C(focal)[T.11001001902] 0.3705 0.063 5.893 0.000 0.247 0.494
C(focal)[T.11001002001] 0.6956 0.058 11.923 0.000 0.581 0.810
C(focal)[T.11001002002] 1.0475 0.055 18.896 0.000 0.939 1.156
C(focal)[T.11001002101] 1.4251 0.053 26.820 0.000 1.321 1.529
C(focal)[T.11001002102] 1.2410 0.054 22.911 0.000 1.135 1.347
C(focal)[T.11001002201] 1.1544 0.056 20.793 0.000 1.046 1.263
C(focal)[T.11001002202] 0.7922 0.057 13.789 0.000 0.680 0.905
C(focal)[T.11001002301] 0.8738 0.057 15.397 0.000 0.763 0.985
C(focal)[T.11001002302] -0.3924 0.075 -5.236 0.000 -0.539 -0.245
C(focal)[T.11001002400] 1.3090 0.054 24.059 0.000 1.202 1.416
C(focal)[T.11001002501] 0.8487 0.058 14.652 0.000 0.735 0.962
C(focal)[T.11001002503] 0.8579 0.057 15.079 0.000 0.746 0.969
C(focal)[T.11001002504] 1.0793 0.055 19.543 0.000 0.971 1.188
C(focal)[T.11001002600] 0.6054 0.060 10.080 0.000 0.488 0.723
C(focal)[T.11001002702] 1.4760 0.053 27.695 0.000 1.372 1.580
C(focal)[T.11001002703] 0.6552 0.059 11.148 0.000 0.540 0.770
C(focal)[T.11001002704] 0.8156 0.057 14.225 0.000 0.703 0.928
C(focal)[T.11001002801] 1.2221 0.055 22.358 0.000 1.115 1.329
C(focal)[T.11001002802] 1.2721 0.054 23.452 0.000 1.166 1.378
C(focal)[T.11001002900] 1.2731 0.054 23.569 0.000 1.167 1.379
C(focal)[T.11001003000] 1.1258 0.056 20.197 0.000 1.017 1.235
C(focal)[T.11001003100] 1.2737 0.055 23.328 0.000 1.167 1.381
C(focal)[T.11001003200] 1.4579 0.054 27.154 0.000 1.353 1.563
C(focal)[T.11001003301] 1.0648 0.055 19.224 0.000 0.956 1.173
C(focal)[T.11001003302] 0.8032 0.059 13.683 0.000 0.688 0.918
C(focal)[T.11001003400] 0.6545 0.059 11.116 0.000 0.539 0.770
C(focal)[T.11001003500] 1.1974 0.055 21.710 0.000 1.089 1.306
C(focal)[T.11001003600] 1.3979 0.054 25.957 0.000 1.292 1.503
C(focal)[T.11001003701] 0.9682 0.056 17.253 0.000 0.858 1.078
C(focal)[T.11001003702] 0.8513 0.057 14.956 0.000 0.740 0.963
C(focal)[T.11001003801] 0.5205 0.060 8.656 0.000 0.403 0.638
C(focal)[T.11001003802] 1.2175 0.054 22.427 0.000 1.111 1.324
C(focal)[T.11001003901] 0.8447 0.057 14.801 0.000 0.733 0.957
C(focal)[T.11001003902] 0.6489 0.060 10.858 0.000 0.532 0.766
C(focal)[T.11001004001] 1.1543 0.055 21.097 0.000 1.047 1.261
C(focal)[T.11001004002] 1.0734 0.056 19.205 0.000 0.964 1.183
C(focal)[T.11001004100] 0.5691 0.060 9.537 0.000 0.452 0.686
C(focal)[T.11001004201] 1.1440 0.055 20.864 0.000 1.037 1.251
C(focal)[T.11001004202] 0.7754 0.058 13.420 0.000 0.662 0.889
C(focal)[T.11001004300] 1.4121 0.054 26.294 0.000 1.307 1.517
C(focal)[T.11001004401] 1.1987 0.055 21.983 0.000 1.092 1.306
C(focal)[T.11001004402] 0.8819 0.057 15.378 0.000 0.770 0.994
C(focal)[T.11001004600] 1.1067 0.055 19.963 0.000 0.998 1.215
C(focal)[T.11001004702] 1.2392 0.055 22.697 0.000 1.132 1.346
C(focal)[T.11001004703] 0.9163 0.057 16.176 0.000 0.805 1.027
C(focal)[T.11001004704] 0.0946 0.066 1.434 0.152 -0.035 0.224
C(focal)[T.11001004801] 0.8914 0.057 15.731 0.000 0.780 1.002
C(focal)[T.11001004802] 1.0515 0.055 18.947 0.000 0.943 1.160
C(focal)[T.11001004901] 0.9591 0.056 17.084 0.000 0.849 1.069
C(focal)[T.11001004902] 1.0929 0.055 19.828 0.000 0.985 1.201
C(focal)[T.11001005001] 0.5791 0.060 9.610 0.000 0.461 0.697
C(focal)[T.11001005003] 0.5234 0.061 8.620 0.000 0.404 0.642
C(focal)[T.11001005004] 1.1142 0.055 20.135 0.000 1.006 1.223
C(focal)[T.11001005202] 1.0857 0.055 19.582 0.000 0.977 1.194
C(focal)[T.11001005203] 0.9580 0.056 17.014 0.000 0.848 1.068
C(focal)[T.11001005302] 0.6749 0.059 11.516 0.000 0.560 0.790
C(focal)[T.11001005303] 0.8879 0.057 15.587 0.000 0.776 1.000
C(focal)[T.11001005501] 0.2993 0.064 4.710 0.000 0.175 0.424
C(focal)[T.11001005502] 0.7336 0.059 12.536 0.000 0.619 0.848
C(focal)[T.11001005503] 0.3170 0.063 5.016 0.000 0.193 0.441
C(focal)[T.11001005601] 0.1947 0.065 3.017 0.003 0.068 0.321
C(focal)[T.11001005602] 0.2021 0.065 3.112 0.002 0.075 0.329
C(focal)[T.11001005801] 0.1786 0.065 2.742 0.006 0.051 0.306
C(focal)[T.11001005802] 0.0541 0.067 0.808 0.419 -0.077 0.185
C(focal)[T.11001005900] 0.5099 0.061 8.415 0.000 0.391 0.629
C(focal)[T.11001006400] 0.9000 0.057 15.840 0.000 0.789 1.011
C(focal)[T.11001006500] 0.5257 0.061 8.667 0.000 0.407 0.645
C(focal)[T.11001006600] 0.4370 0.062 7.071 0.000 0.316 0.558
C(focal)[T.11001006700] 1.0453 0.056 18.740 0.000 0.936 1.155
C(focal)[T.11001006801] 0.6022 0.060 10.119 0.000 0.486 0.719
C(focal)[T.11001006802] 0.6953 0.059 11.855 0.000 0.580 0.810
C(focal)[T.11001006804] -1.8180 0.130 -14.035 0.000 -2.072 -1.564
C(focal)[T.11001006900] 1.0491 0.056 18.875 0.000 0.940 1.158
C(focal)[T.11001007000] 0.5350 0.061 8.820 0.000 0.416 0.654
C(focal)[T.11001007100] 0.8925 0.057 15.662 0.000 0.781 1.004
C(focal)[T.11001007201] 1.2608 0.054 23.239 0.000 1.154 1.367
C(focal)[T.11001007202] 1.6212 0.052 30.962 0.000 1.519 1.724
C(focal)[T.11001007203] 1.0936 0.056 19.687 0.000 0.985 1.203
C(focal)[T.11001007301] -1.2406 0.103 -11.997 0.000 -1.443 -1.038
C(focal)[T.11001007304] 0.8903 0.057 15.628 0.000 0.779 1.002
C(focal)[T.11001007401] -0.4398 0.077 -5.728 0.000 -0.590 -0.289
C(focal)[T.11001007403] 0.5045 0.061 8.246 0.000 0.385 0.624
C(focal)[T.11001007404] 0.8896 0.057 15.594 0.000 0.778 1.001
C(focal)[T.11001007406] 0.6654 0.059 11.302 0.000 0.550 0.781
C(focal)[T.11001007407] 1.0517 0.056 18.750 0.000 0.942 1.162
C(focal)[T.11001007408] 0.3867 0.063 6.150 0.000 0.263 0.510
C(focal)[T.11001007409] 0.8578 0.058 14.819 0.000 0.744 0.971
C(focal)[T.11001007502] 0.9756 0.057 17.151 0.000 0.864 1.087
C(focal)[T.11001007503] 0.5323 0.061 8.717 0.000 0.413 0.652
C(focal)[T.11001007504] 0.3500 0.062 5.605 0.000 0.228 0.472
C(focal)[T.11001007601] 0.9888 0.056 17.642 0.000 0.879 1.099
C(focal)[T.11001007603] 0.9667 0.056 17.226 0.000 0.857 1.077
C(focal)[T.11001007604] 0.8827 0.057 15.536 0.000 0.771 0.994
C(focal)[T.11001007605] 0.8818 0.057 15.491 0.000 0.770 0.993
C(focal)[T.11001007703] 1.1151 0.055 20.270 0.000 1.007 1.223
C(focal)[T.11001007707] 0.8330 0.057 14.583 0.000 0.721 0.945
C(focal)[T.11001007708] 0.4617 0.061 7.587 0.000 0.342 0.581
C(focal)[T.11001007709] 0.3161 0.063 5.042 0.000 0.193 0.439
C(focal)[T.11001007803] 1.0339 0.056 18.544 0.000 0.925 1.143
C(focal)[T.11001007804] 0.7128 0.058 12.229 0.000 0.599 0.827
C(focal)[T.11001007806] 0.5107 0.060 8.456 0.000 0.392 0.629
C(focal)[T.11001007807] 0.3257 0.063 5.201 0.000 0.203 0.448
C(focal)[T.11001007808] 0.8371 0.057 14.606 0.000 0.725 0.949
C(focal)[T.11001007809] 0.7311 0.058 12.578 0.000 0.617 0.845
C(focal)[T.11001007901] 1.0744 0.055 19.403 0.000 0.966 1.183
C(focal)[T.11001007903] 0.3595 0.062 5.773 0.000 0.237 0.482
C(focal)[T.11001008001] 0.9031 0.057 15.921 0.000 0.792 1.014
C(focal)[T.11001008002] 0.8694 0.057 15.267 0.000 0.758 0.981
C(focal)[T.11001008100] 0.7976 0.058 13.860 0.000 0.685 0.910
C(focal)[T.11001008200] 0.5164 0.060 8.537 0.000 0.398 0.635
C(focal)[T.11001008301] 0.8303 0.057 14.480 0.000 0.718 0.943
C(focal)[T.11001008302] 0.8300 0.057 14.469 0.000 0.718 0.942
C(focal)[T.11001008402] 0.8459 0.058 14.681 0.000 0.733 0.959
C(focal)[T.11001008410] 0.4639 0.061 7.593 0.000 0.344 0.584
C(focal)[T.11001008701] 0.9296 0.057 16.444 0.000 0.819 1.040
C(focal)[T.11001008702] 1.1888 0.055 21.781 0.000 1.082 1.296
C(focal)[T.11001008802] 1.1883 0.055 21.758 0.000 1.081 1.295
C(focal)[T.11001008803] 1.0467 0.056 18.827 0.000 0.938 1.156
C(focal)[T.11001008804] 0.7786 0.058 13.477 0.000 0.665 0.892
C(focal)[T.11001008903] 0.9334 0.057 16.489 0.000 0.822 1.044
C(focal)[T.11001008904] 0.8972 0.057 15.792 0.000 0.786 1.009
C(focal)[T.11001009000] 1.0452 0.056 18.695 0.000 0.936 1.155
C(focal)[T.11001009102] 1.1477 0.055 20.803 0.000 1.040 1.256
C(focal)[T.11001009201] 0.7220 0.058 12.403 0.000 0.608 0.836
C(focal)[T.11001009203] 0.8484 0.057 14.778 0.000 0.736 0.961
C(focal)[T.11001009204] 0.9190 0.057 16.095 0.000 0.807 1.031
C(focal)[T.11001009301] 0.9485 0.057 16.692 0.000 0.837 1.060
C(focal)[T.11001009302] 0.5880 0.060 9.770 0.000 0.470 0.706
C(focal)[T.11001009400] 1.1401 0.055 20.642 0.000 1.032 1.248
C(focal)[T.11001009503] 0.7951 0.058 13.733 0.000 0.682 0.909
C(focal)[T.11001009504] 0.8400 0.057 14.639 0.000 0.728 0.952
C(focal)[T.11001009505] 0.9424 0.056 16.754 0.000 0.832 1.053
C(focal)[T.11001009507] 0.2838 0.064 4.430 0.000 0.158 0.409
C(focal)[T.11001009508] 1.0990 0.055 19.931 0.000 0.991 1.207
C(focal)[T.11001009509] 0.9857 0.056 17.503 0.000 0.875 1.096
C(focal)[T.11001009510] 1.0060 0.056 17.899 0.000 0.896 1.116
C(focal)[T.11001009511] -2.1957 0.151 -14.576 0.000 -2.491 -1.900
C(focal)[T.11001009601] 0.3426 0.063 5.448 0.000 0.219 0.466
C(focal)[T.11001009602] 0.9613 0.057 16.982 0.000 0.850 1.072
C(focal)[T.11001009603] 0.9446 0.057 16.653 0.000 0.833 1.056
C(focal)[T.11001009604] 0.3806 0.063 6.069 0.000 0.258 0.504
C(focal)[T.11001009700] 0.8008 0.058 13.825 0.000 0.687 0.914
C(focal)[T.11001009801] -0.0775 0.069 -1.126 0.260 -0.212 0.057
C(focal)[T.11001009802] 0.0909 0.067 1.363 0.173 -0.040 0.222
C(focal)[T.11001009803] 0.4934 0.061 8.147 0.000 0.375 0.612
C(focal)[T.11001009804] 0.4534 0.062 7.335 0.000 0.332 0.575
C(focal)[T.11001009807] 0.7525 0.059 12.848 0.000 0.638 0.867
C(focal)[T.11001009810] 0.4673 0.062 7.570 0.000 0.346 0.588
C(focal)[T.11001009811] 0.8018 0.058 13.862 0.000 0.688 0.915
C(focal)[T.11001009901] 0.4492 0.062 7.266 0.000 0.328 0.570
C(focal)[T.11001009902] 0.6242 0.060 10.366 0.000 0.506 0.742
C(focal)[T.11001009903] 0.3430 0.063 5.406 0.000 0.219 0.467
C(focal)[T.11001009904] 0.7123 0.059 12.032 0.000 0.596 0.828
C(focal)[T.11001009905] 0.7255 0.059 12.325 0.000 0.610 0.841
C(focal)[T.11001009906] 0.0922 0.067 1.375 0.169 -0.039 0.224
C(focal)[T.11001009907] 0.4389 0.061 7.186 0.000 0.319 0.559
C(focal)[T.11001010100] 0.5254 0.060 8.743 0.000 0.408 0.643
C(focal)[T.11001010201] 0.7889 0.058 13.695 0.000 0.676 0.902
C(focal)[T.11001010202] 0.5241 0.060 8.720 0.000 0.406 0.642
C(focal)[T.11001010300] 1.0289 0.056 18.216 0.000 0.918 1.140
C(focal)[T.11001010400] 0.8205 0.058 14.264 0.000 0.708 0.933
C(focal)[T.11001010500] 0.9609 0.056 17.143 0.000 0.851 1.071
C(focal)[T.11001010601] 0.6463 0.059 10.978 0.000 0.531 0.762
C(focal)[T.11001010602] 1.6623 0.052 31.919 0.000 1.560 1.764
C(focal)[T.11001010603] 0.6678 0.059 11.391 0.000 0.553 0.783
C(focal)[T.11001010700] -0.1056 0.069 -1.524 0.128 -0.241 0.030
C(focal)[T.11001010800] -0.5377 0.078 -6.860 0.000 -0.691 -0.384
C(focal)[T.11001010900] 0.3984 0.062 6.462 0.000 0.278 0.519
C(focal)[T.11001011001] 0.6856 0.059 11.707 0.000 0.571 0.800
C(focal)[T.11001011002] 0.3459 0.064 5.422 0.000 0.221 0.471
C(focal)[T.11001011100] 1.1431 0.055 20.863 0.000 1.036 1.250
C(focal)[T.11001980000] -2.6928 0.189 -14.268 0.000 -3.063 -2.323
C(neighbor)[T.11001000102] 3.1405 0.090 34.915 0.000 2.964 3.317
C(neighbor)[T.11001000201] 3.4788 0.089 38.903 0.000 3.304 3.654
C(neighbor)[T.11001000202] 2.8825 0.091 31.839 0.000 2.705 3.060
C(neighbor)[T.11001000300] 0.7810 0.107 7.327 0.000 0.572 0.990
C(neighbor)[T.11001000400] 1.4019 0.098 14.279 0.000 1.209 1.594
C(neighbor)[T.11001000501] 1.1098 0.102 10.902 0.000 0.910 1.309
C(neighbor)[T.11001000502] 0.3030 0.116 2.614 0.009 0.076 0.530
C(neighbor)[T.11001000600] 1.4758 0.098 15.134 0.000 1.285 1.667
C(neighbor)[T.11001000702] -0.8979 0.164 -5.466 0.000 -1.220 -0.576
C(neighbor)[T.11001000703] -1.4610 0.203 -7.208 0.000 -1.858 -1.064
C(neighbor)[T.11001000704] -0.6496 0.151 -4.314 0.000 -0.945 -0.354
C(neighbor)[T.11001000802] 0.6826 0.108 6.330 0.000 0.471 0.894
C(neighbor)[T.11001000803] 0.6293 0.109 5.755 0.000 0.415 0.844
C(neighbor)[T.11001000804] 1.0482 0.103 10.211 0.000 0.847 1.249
C(neighbor)[T.11001000902] 0.2614 0.118 2.218 0.027 0.030 0.492
C(neighbor)[T.11001000903] 2.2264 0.093 24.028 0.000 2.045 2.408
C(neighbor)[T.11001000904] 1.7597 0.095 18.479 0.000 1.573 1.946
C(neighbor)[T.11001001002] 2.1698 0.093 23.360 0.000 1.988 2.352
C(neighbor)[T.11001001003] -0.0969 0.127 -0.762 0.446 -0.346 0.152
C(neighbor)[T.11001001004] 1.8162 0.095 19.099 0.000 1.630 2.003
C(neighbor)[T.11001001100] 2.5451 0.091 27.853 0.000 2.366 2.724
C(neighbor)[T.11001001200] 1.6972 0.096 17.666 0.000 1.509 1.886
C(neighbor)[T.11001001301] -0.1614 0.131 -1.231 0.218 -0.418 0.096
C(neighbor)[T.11001001303] 1.3080 0.100 13.117 0.000 1.113 1.503
C(neighbor)[T.11001001304] 0.7163 0.109 6.591 0.000 0.503 0.929
C(neighbor)[T.11001001401] 0.2863 0.116 2.467 0.014 0.059 0.514
C(neighbor)[T.11001001402] 1.1226 0.102 11.003 0.000 0.923 1.323
C(neighbor)[T.11001001500] 0.6738 0.108 6.248 0.000 0.462 0.885
C(neighbor)[T.11001001600] 1.9502 0.094 20.746 0.000 1.766 2.134
C(neighbor)[T.11001001702] 1.3230 0.099 13.377 0.000 1.129 1.517
C(neighbor)[T.11001001803] -1.1571 0.185 -6.268 0.000 -1.519 -0.795
C(neighbor)[T.11001001804] -0.0656 0.126 -0.521 0.603 -0.313 0.181
C(neighbor)[T.11001001901] 1.8236 0.095 19.245 0.000 1.638 2.009
C(neighbor)[T.11001001902] 0.3818 0.115 3.321 0.001 0.156 0.607
C(neighbor)[T.11001002001] 0.3686 0.114 3.231 0.001 0.145 0.592
C(neighbor)[T.11001002002] 0.2859 0.116 2.463 0.014 0.058 0.513
C(neighbor)[T.11001002101] 1.0279 0.102 10.042 0.000 0.827 1.229
C(neighbor)[T.11001002102] 0.4883 0.111 4.381 0.000 0.270 0.707
C(neighbor)[T.11001002201] -0.1378 0.131 -1.051 0.293 -0.395 0.119
C(neighbor)[T.11001002202] -1.3496 0.193 -7.001 0.000 -1.727 -0.972
C(neighbor)[T.11001002301] -0.1764 0.130 -1.359 0.174 -0.431 0.078
C(neighbor)[T.11001002302] 3.5488 0.089 39.746 0.000 3.374 3.724
C(neighbor)[T.11001002400] 0.8305 0.106 7.811 0.000 0.622 1.039
C(neighbor)[T.11001002501] 0.7612 0.108 7.080 0.000 0.550 0.972
C(neighbor)[T.11001002503] 0.9627 0.103 9.320 0.000 0.760 1.165
C(neighbor)[T.11001002504] -0.3626 0.137 -2.649 0.008 -0.631 -0.094
C(neighbor)[T.11001002600] -0.4612 0.143 -3.228 0.001 -0.741 -0.181
C(neighbor)[T.11001002702] 0.7165 0.108 6.644 0.000 0.505 0.928
C(neighbor)[T.11001002703] 0.2396 0.117 2.041 0.041 0.010 0.470
C(neighbor)[T.11001002704] -0.3413 0.136 -2.501 0.012 -0.609 -0.074
C(neighbor)[T.11001002801] 0.0454 0.124 0.367 0.713 -0.197 0.288
C(neighbor)[T.11001002802] 1.7848 0.095 18.750 0.000 1.598 1.971
C(neighbor)[T.11001002900] 1.1559 0.101 11.460 0.000 0.958 1.354
C(neighbor)[T.11001003000] 0.1764 0.121 1.460 0.144 -0.060 0.413
C(neighbor)[T.11001003100] 0.9256 0.105 8.845 0.000 0.721 1.131
C(neighbor)[T.11001003200] 0.6225 0.110 5.649 0.000 0.407 0.838
C(neighbor)[T.11001003301] -0.1882 0.131 -1.440 0.150 -0.445 0.068
C(neighbor)[T.11001003302] 0.1624 0.122 1.334 0.182 -0.076 0.401
C(neighbor)[T.11001003400] 2.3611 0.092 25.633 0.000 2.181 2.542
C(neighbor)[T.11001003500] 1.6498 0.096 17.102 0.000 1.461 1.839
C(neighbor)[T.11001003600] 0.8822 0.105 8.383 0.000 0.676 1.089
C(neighbor)[T.11001003701] 0.2202 0.118 1.861 0.063 -0.012 0.452
C(neighbor)[T.11001003702] -0.5168 0.143 -3.603 0.000 -0.798 -0.236
C(neighbor)[T.11001003801] 1.4469 0.098 14.803 0.000 1.255 1.638
C(neighbor)[T.11001003802] 1.4812 0.097 15.204 0.000 1.290 1.672
C(neighbor)[T.11001003901] 0.7810 0.107 7.326 0.000 0.572 0.990
C(neighbor)[T.11001003902] 0.0168 0.125 0.134 0.893 -0.228 0.262
C(neighbor)[T.11001004001] 0.6790 0.108 6.285 0.000 0.467 0.891
C(neighbor)[T.11001004002] 2.0825 0.094 22.268 0.000 1.899 2.266
C(neighbor)[T.11001004100] 0.6405 0.109 5.892 0.000 0.427 0.854
C(neighbor)[T.11001004201] 1.6201 0.096 16.814 0.000 1.431 1.809
C(neighbor)[T.11001004202] 2.0009 0.094 21.324 0.000 1.817 2.185
C(neighbor)[T.11001004300] 1.7532 0.096 18.346 0.000 1.566 1.941
C(neighbor)[T.11001004401] 1.9006 0.094 20.125 0.000 1.716 2.086
C(neighbor)[T.11001004402] 1.6462 0.096 17.089 0.000 1.457 1.835
C(neighbor)[T.11001004600] 1.8362 0.095 19.355 0.000 1.650 2.022
C(neighbor)[T.11001004702] 2.7948 0.091 30.801 0.000 2.617 2.973
C(neighbor)[T.11001004703] 1.2719 0.100 12.750 0.000 1.076 1.467
C(neighbor)[T.11001004704] 0.6322 0.109 5.799 0.000 0.419 0.846
C(neighbor)[T.11001004801] 2.3305 0.092 25.267 0.000 2.150 2.511
C(neighbor)[T.11001004802] 1.8739 0.095 19.803 0.000 1.688 2.059
C(neighbor)[T.11001004901] 1.3118 0.099 13.210 0.000 1.117 1.506
C(neighbor)[T.11001004902] 2.1670 0.093 23.310 0.000 1.985 2.349
C(neighbor)[T.11001005001] 1.2092 0.100 12.032 0.000 1.012 1.406
C(neighbor)[T.11001005003] 1.2452 0.100 12.456 0.000 1.049 1.441
C(neighbor)[T.11001005004] -0.0184 0.125 -0.147 0.883 -0.264 0.227
C(neighbor)[T.11001005202] 1.8018 0.095 18.964 0.000 1.616 1.988
C(neighbor)[T.11001005203] 1.4601 0.098 14.953 0.000 1.269 1.651
C(neighbor)[T.11001005302] 1.1030 0.102 10.850 0.000 0.904 1.302
C(neighbor)[T.11001005303] 2.3299 0.092 25.266 0.000 2.149 2.511
C(neighbor)[T.11001005501] 3.7241 0.089 41.739 0.000 3.549 3.899
C(neighbor)[T.11001005502] 2.6177 0.091 28.621 0.000 2.438 2.797
C(neighbor)[T.11001005503] 2.4439 0.092 26.625 0.000 2.264 2.624
C(neighbor)[T.11001005601] 1.2134 0.101 12.067 0.000 1.016 1.410
C(neighbor)[T.11001005602] 2.1262 0.093 22.745 0.000 1.943 2.309
C(neighbor)[T.11001005801] 3.7204 0.089 41.713 0.000 3.546 3.895
C(neighbor)[T.11001005802] 5.0489 0.088 57.142 0.000 4.876 5.222
C(neighbor)[T.11001005900] 3.5709 0.089 39.970 0.000 3.396 3.746
C(neighbor)[T.11001006400] 0.6140 0.109 5.624 0.000 0.400 0.828
C(neighbor)[T.11001006500] 2.2768 0.093 24.556 0.000 2.095 2.459
C(neighbor)[T.11001006600] 1.7989 0.096 18.830 0.000 1.612 1.986
C(neighbor)[T.11001006700] 1.5624 0.097 16.064 0.000 1.372 1.753
C(neighbor)[T.11001006801] -0.6434 0.151 -4.251 0.000 -0.940 -0.347
C(neighbor)[T.11001006802] 0.1988 0.120 1.661 0.097 -0.036 0.433
C(neighbor)[T.11001006804] 0.4993 0.112 4.464 0.000 0.280 0.719
C(neighbor)[T.11001006900] 1.2565 0.100 12.562 0.000 1.060 1.453
C(neighbor)[T.11001007000] 1.9436 0.094 20.568 0.000 1.758 2.129
C(neighbor)[T.11001007100] 1.1957 0.101 11.843 0.000 0.998 1.394
C(neighbor)[T.11001007201] 2.2527 0.093 24.344 0.000 2.071 2.434
C(neighbor)[T.11001007202] 1.7101 0.096 17.830 0.000 1.522 1.898
C(neighbor)[T.11001007203] 2.4754 0.092 26.958 0.000 2.295 2.655
C(neighbor)[T.11001007301] 0.4872 0.113 4.305 0.000 0.265 0.709
C(neighbor)[T.11001007304] 0.7154 0.108 6.634 0.000 0.504 0.927
C(neighbor)[T.11001007401] 0.1873 0.120 1.564 0.118 -0.047 0.422
C(neighbor)[T.11001007403] -0.7936 0.160 -4.959 0.000 -1.107 -0.480
C(neighbor)[T.11001007404] -1.4870 0.206 -7.235 0.000 -1.890 -1.084
C(neighbor)[T.11001007406] -0.3352 0.136 -2.464 0.014 -0.602 -0.069
C(neighbor)[T.11001007407] -0.6157 0.151 -4.068 0.000 -0.912 -0.319
C(neighbor)[T.11001007408] -0.1540 0.131 -1.172 0.241 -0.412 0.104
C(neighbor)[T.11001007409] -0.3844 0.141 -2.721 0.007 -0.661 -0.108
C(neighbor)[T.11001007502] 0.1825 0.121 1.505 0.132 -0.055 0.420
C(neighbor)[T.11001007503] 1.3558 0.099 13.652 0.000 1.161 1.550
C(neighbor)[T.11001007504] -0.2861 0.134 -2.129 0.033 -0.549 -0.023
C(neighbor)[T.11001007601] 0.4427 0.113 3.921 0.000 0.221 0.664
C(neighbor)[T.11001007603] 0.2163 0.118 1.831 0.067 -0.015 0.448
C(neighbor)[T.11001007604] -0.6115 0.148 -4.119 0.000 -0.902 -0.321
C(neighbor)[T.11001007605] -0.3129 0.135 -2.314 0.021 -0.578 -0.048
C(neighbor)[T.11001007703] -0.3559 0.137 -2.600 0.009 -0.624 -0.088
C(neighbor)[T.11001007707] -1.3134 0.191 -6.891 0.000 -1.687 -0.940
C(neighbor)[T.11001007708] -1.4064 0.197 -7.122 0.000 -1.794 -1.019
C(neighbor)[T.11001007709] -1.0417 0.172 -6.066 0.000 -1.378 -0.705
C(neighbor)[T.11001007803] 1.4259 0.098 14.548 0.000 1.234 1.618
C(neighbor)[T.11001007804] 0.4094 0.113 3.611 0.000 0.187 0.632
C(neighbor)[T.11001007806] -0.3589 0.137 -2.621 0.009 -0.627 -0.091
C(neighbor)[T.11001007807] -1.7866 0.231 -7.745 0.000 -2.239 -1.335
C(neighbor)[T.11001007808] -0.0722 0.127 -0.570 0.568 -0.320 0.176
C(neighbor)[T.11001007809] -0.1307 0.128 -1.019 0.308 -0.382 0.121
C(neighbor)[T.11001007901] 0.5532 0.110 5.017 0.000 0.337 0.769
C(neighbor)[T.11001007903] -0.7730 0.156 -4.947 0.000 -1.079 -0.467
C(neighbor)[T.11001008001] 0.7019 0.107 6.530 0.000 0.491 0.913
C(neighbor)[T.11001008002] 0.6677 0.108 6.179 0.000 0.456 0.879
C(neighbor)[T.11001008100] 0.1855 0.119 1.561 0.118 -0.047 0.418
C(neighbor)[T.11001008200] 1.3867 0.098 14.093 0.000 1.194 1.580
C(neighbor)[T.11001008301] 1.3838 0.098 14.055 0.000 1.191 1.577
C(neighbor)[T.11001008302] 1.2911 0.099 12.984 0.000 1.096 1.486
C(neighbor)[T.11001008402] 0.8861 0.105 8.432 0.000 0.680 1.092
C(neighbor)[T.11001008410] 0.6217 0.109 5.703 0.000 0.408 0.835
C(neighbor)[T.11001008701] 0.7908 0.106 7.460 0.000 0.583 0.999
C(neighbor)[T.11001008702] 0.7120 0.107 6.640 0.000 0.502 0.922
C(neighbor)[T.11001008802] 0.4785 0.112 4.281 0.000 0.259 0.698
C(neighbor)[T.11001008803] 2.4652 0.092 26.893 0.000 2.286 2.645
C(neighbor)[T.11001008804] 1.0365 0.102 10.130 0.000 0.836 1.237
C(neighbor)[T.11001008903] -0.5685 0.146 -3.882 0.000 -0.856 -0.281
C(neighbor)[T.11001008904] 0.6911 0.108 6.413 0.000 0.480 0.902
C(neighbor)[T.11001009000] 1.3200 0.099 13.295 0.000 1.125 1.515
C(neighbor)[T.11001009102] 2.4634 0.092 26.843 0.000 2.283 2.643
C(neighbor)[T.11001009201] 1.5008 0.097 15.439 0.000 1.310 1.691
C(neighbor)[T.11001009203] -0.8475 0.161 -5.262 0.000 -1.163 -0.532
C(neighbor)[T.11001009204] 1.2979 0.100 13.026 0.000 1.103 1.493
C(neighbor)[T.11001009301] 1.2169 0.101 12.105 0.000 1.020 1.414
C(neighbor)[T.11001009302] 0.9005 0.105 8.602 0.000 0.695 1.106
C(neighbor)[T.11001009400] 1.2103 0.100 12.046 0.000 1.013 1.407
C(neighbor)[T.11001009503] -0.5120 0.144 -3.555 0.000 -0.794 -0.230
C(neighbor)[T.11001009504] 1.9549 0.094 20.785 0.000 1.771 2.139
C(neighbor)[T.11001009505] 1.5556 0.097 16.081 0.000 1.366 1.745
C(neighbor)[T.11001009507] -2.3383 0.302 -7.748 0.000 -2.930 -1.747
C(neighbor)[T.11001009508] 0.0917 0.121 0.757 0.449 -0.146 0.329
C(neighbor)[T.11001009509] -0.0641 0.127 -0.503 0.615 -0.314 0.186
C(neighbor)[T.11001009510] 0.1233 0.122 1.012 0.312 -0.116 0.362
C(neighbor)[T.11001009511] -1.6194 0.215 -7.533 0.000 -2.041 -1.198
C(neighbor)[T.11001009601] -0.2430 0.134 -1.819 0.069 -0.505 0.019
C(neighbor)[T.11001009602] 0.1581 0.122 1.295 0.195 -0.081 0.397
C(neighbor)[T.11001009603] 1.2977 0.100 12.946 0.000 1.101 1.494
C(neighbor)[T.11001009604] 0.1192 0.123 0.966 0.334 -0.123 0.361
C(neighbor)[T.11001009700] -0.3702 0.141 -2.630 0.009 -0.646 -0.094
C(neighbor)[T.11001009801] -1.3208 0.191 -6.930 0.000 -1.694 -0.947
C(neighbor)[T.11001009802] -2.0229 0.265 -7.632 0.000 -2.542 -1.503
C(neighbor)[T.11001009803] -1.0910 0.175 -6.249 0.000 -1.433 -0.749
C(neighbor)[T.11001009804] -0.1910 0.134 -1.425 0.154 -0.454 0.072
C(neighbor)[T.11001009807] 0.3633 0.117 3.110 0.002 0.134 0.592
C(neighbor)[T.11001009810] -1.9377 0.258 -7.509 0.000 -2.444 -1.432
C(neighbor)[T.11001009811] 0.5103 0.112 4.548 0.000 0.290 0.730
C(neighbor)[T.11001009901] 0.6655 0.109 6.085 0.000 0.451 0.880
C(neighbor)[T.11001009902] -1.7437 0.235 -7.409 0.000 -2.205 -1.282
C(neighbor)[T.11001009903] -0.7231 0.157 -4.600 0.000 -1.031 -0.415
C(neighbor)[T.11001009904] -0.3143 0.138 -2.273 0.023 -0.585 -0.043
C(neighbor)[T.11001009905] -1.5128 0.212 -7.148 0.000 -1.928 -1.098
C(neighbor)[T.11001009906] -1.9189 0.252 -7.626 0.000 -2.412 -1.426
C(neighbor)[T.11001009907] -0.5965 0.147 -4.055 0.000 -0.885 -0.308
C(neighbor)[T.11001010100] 4.7713 0.088 53.962 0.000 4.598 4.945
C(neighbor)[T.11001010201] 0.6789 0.108 6.296 0.000 0.468 0.890
C(neighbor)[T.11001010202] 3.6732 0.089 41.199 0.000 3.498 3.848
C(neighbor)[T.11001010300] 0.7257 0.108 6.711 0.000 0.514 0.938
C(neighbor)[T.11001010400] 2.0073 0.094 21.338 0.000 1.823 2.192
C(neighbor)[T.11001010500] 2.0285 0.094 21.659 0.000 1.845 2.212
C(neighbor)[T.11001010601] 3.5731 0.089 40.033 0.000 3.398 3.748
C(neighbor)[T.11001010602] 2.1431 0.093 23.045 0.000 1.961 2.325
C(neighbor)[T.11001010603] 3.3995 0.089 37.991 0.000 3.224 3.575
C(neighbor)[T.11001010700] 5.3072 0.088 60.130 0.000 5.134 5.480
C(neighbor)[T.11001010800] 3.9466 0.089 44.401 0.000 3.772 4.121
C(neighbor)[T.11001010900] 0.8750 0.105 8.352 0.000 0.670 1.080
C(neighbor)[T.11001011001] -1.2888 0.188 -6.837 0.000 -1.658 -0.919
C(neighbor)[T.11001011002] 0.3912 0.117 3.342 0.001 0.162 0.621
C(neighbor)[T.11001011100] 2.5300 0.092 27.645 0.000 2.351 2.709
C(neighbor)[T.11001980000] 4.6305 0.088 52.335 0.000 4.457 4.804
distance -1.954e-05 9.18e-07 -21.280 0.000 -2.13e-05 -1.77e-05
d.params[-1:]
array([-1.95256086e-05])
d_statsmodels.params[-1]
/var/folders/j8/5bgcw6hs7cqcbbz48d6bsftw0000gp/T/ipykernel_24509/3503717071.py:1: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`
  d_statsmodels.params[-1]
np.float64(-1.953566583722616e-05)
Fotheringham, A Stewart, and Morton E O’Kelly. 1989. Spatial Interaction Models: Formulations and Applications. Dordrecht: Kluwer Academic Publishers Dordrecht.
Getis, A. 1991. “Spatial Interaction and Spatial Autocorrelation: A Cross-Product Approach.” Environment and Planning A: Economy and Space 23 (9): 1269–77. https://doi.org/10.1068/a231269.
Glaeser, Edward L, Eric A Hanushek, and John M Quigley. 2004. “Opportunities, Race, and Urban Location: The Influence of John Kain.” Journal of Urban Economics 56 (1): 70–79. https://doi.org/10.1016/j.jue.2004.03.002.
Griffith, Daniel A., Yongwan Chun, and Bin Li. 2019. “Spatial Interaction Modeling.” In Spatial Regression Analysis Using Eigenvector Spatial Filtering, 141–66. Elsevier. https://doi.org/10.1016/B978-0-12-815043-6.00007-0.
Kain, John F. 1968. “Housing Segregation, Negro Employment, and Metropolitan Decentralization.” The Quarterly Journal of Economics 82 (2): 175–97. https://doi.org/10.2307/1885893.
———. 1992. “The Spatial Mismatch Hypothesis: Three Decades Later.” Housing Policy Debate 3 (2): 393–402. https://doi.org/10.1080/10511482.1992.9521100.
Liao, Mengyu, and Taylor M. Oshan. 2025. “A DataDriven Approach to Spatial Interaction Models of Migration: Integrating and Refining the Theories of Competing Destinations and Intervening Opportunities.” Geographical Analysis, March. https://doi.org/10.1111/gean.70001.
Oshan, Taylor M. 2016. “A Primer for Working with the Spatial Interaction Modeling {}SpInt{} Module in the Python Spatial Analysis Library {}PySAL{}.” REGION 3 (2): 11. https://doi.org/10.18335/region.v3i2.175.
———. 2021. “The Spatial Structure Debate in Spatial Interaction Modeling: 50 Years On.” Progress in Human Geography 45 (5): 925–50. https://doi.org/10.1177/0309132520968134.
Oshan, Taylor M., and Mengyu Liao. 2025. “Generalized Additive Spatial Smoothing (GASS): A Multiscale Regression Framework for Modeling Neighborhood Effects Across Spatial Supports.” Annals of the American Association of Geographers 115 (1): 110–30. https://doi.org/10.1080/24694452.2024.2401490.
Putman, S H, and S-H Chung. 1989. “Effects of Spatial System Design on Spatial Interaction Models. 1: The Spatial System Definition Problem.” Environment and Planning A: Economy and Space 21 (1): 27–46. https://doi.org/10.1068/a210027.
Rey, Sergio J., Luc Anselin, Pedro Amaral, Dani Arribas-Bel, Renan Xavier Cortes, James David Gaboardi, Wei Kang, et al. 2021. “The PySAL Ecosystem: Philosophy and Implementation.” Geographical Analysis, June, gean.12276. https://doi.org/10.1111/gean.12276.
Tobler, W. 1983. “An Alternative Formulation for Spatial-Interaction Modeling.” Environment and Planning A 15 (5): 693–703.
Wilson, A. G. 1967. “A Statistical Theory of Spatial Distribution Models.” Transportation Research 1 (3): 253–69. https://doi.org/10.1016/0041-1647(67)90035-4.