Exponential Random Graph Models (ERGMs)

WEN, Tzai-Hung (NTU Geography)

Source: McFarland, Daniel, et.al. 2010. “Social Network Analysis Labs in R.” Stanford University.
library(ergm)

1. Load network data

data(studentnets.ergm173, package = "NetData")

ls()
## [1] "edges" "nodes"
head(nodes, n=10)
##    std_id gnd grd rce per_cap_inc
## 1  104456   2  10   4        4342
## 2  113211   2  10   1       13452
## 3  114144   1  10   4       13799
## 4  114992   1  10   4       13138
## 5  118466   1  10   2        8387
## 6  118680   2  10   4        9392
## 7  122713   2  10   4       12471
## 8  122714   1  10   1       10391
## 9  122723   1  10   4       17524
## 10 125522   1  10   4       12145
head(edges, n=10)
##    ego_id alter_id sem1_friend sem2_friend sem1_wtd_dicht_seat
## 1  104456   104456           0           1                   0
## 2  104456   114992           0           1                   0
## 3  104456   118680           0           1                   0
## 4  104456   122713           0           1                   0
## 5  104456   122723           0           1                   1
## 6  104456   125522           1           1                   0
## 7  104456   126101           0           1                   0
## 8  104456   126784           0           1                   0
## 9  104456   132942           0           1                   1
## 10 104456   138966           0           1                   1

2. Create new edge-list file for ERGM

# Create 22 unique and sequenced IDs
id <- seq(1,22,1)
# Join these IDs to the nodes data (cbind = column bind), and reassign this object to 'nodes'
nodes<-cbind(id, nodes)
nodes
##    id std_id gnd grd rce per_cap_inc
## 1   1 104456   2  10   4        4342
## 2   2 113211   2  10   1       13452
## 3   3 114144   1  10   4       13799
## 4   4 114992   1  10   4       13138
## 5   5 118466   1  10   2        8387
## 6   6 118680   2  10   4        9392
## 7   7 122713   2  10   4       12471
## 8   8 122714   1  10   1       10391
## 9   9 122723   1  10   4       17524
## 10 10 125522   1  10   4       12145
## 11 11 126101   2  10   1        8622
## 12 12 126784   2  10   3       17524
## 13 13 128033   2  10   4       11651
## 14 14 128041   1  10   4       10116
## 15 15 132942   2  10   4       12452
## 16 16 134494   1  10   4        5255
## 17 17 138966   2  10   3        7427
## 18 18 139441   2  10   3       11933
## 19 19 139596   2  10   4        8509
## 20 20 140270   1  10   4       12145
## 21 21 140271   2  10   4        9121
## 22 22 140442   1  10   3        7949
edges2<-merge(nodes[,1:2], edges, by.x = "std_id", by.y="alter_id")
head(edges2, n=10)
##    std_id id ego_id sem1_friend sem2_friend sem1_wtd_dicht_seat
## 1  104456  1 132942           0           1                   1
## 2  104456  1 114992           1           1                   0
## 3  104456  1 126784           0           1                   0
## 4  104456  1 104456           0           1                   0
## 5  104456  1 139596           1           1                   0
## 6  113211  2 132942           1           1                   0
## 7  113211  2 126784           0           1                   0
## 8  113211  2 126101           0           1                   1
## 9  114144  3 118680           1           1                   0
## 10 114144  3 139596           0           1                   0
nrow(edges2) # 144 records
## [1] 144
# Change the 1st col name
names(edges2)[1]<-"alter_id"
names(edges2)[2]<-"alter_R_id"

edges3<- merge(nodes[,1:2], edges2, by.x = "std_id", by.y="ego_id")
names(edges3)[1]<-"ego_id"
names(edges3)[2]<-"ego_R_id"
head(edges3, n=10)
##    ego_id ego_R_id alter_id alter_R_id sem1_friend sem2_friend
## 1  104456        1   125522         10           1           1
## 2  104456        1   126784         12           0           1
## 3  104456        1   139596         19           1           1
## 4  104456        1   104456          1           0           1
## 5  104456        1   122713          7           0           1
## 6  104456        1   126101         11           0           1
## 7  104456        1   132942         15           0           1
## 8  104456        1   139441         18           0           1
## 9  104456        1   118680          6           0           1
## 10 104456        1   122723          9           0           1
##    sem1_wtd_dicht_seat
## 1                    0
## 2                    0
## 3                    0
## 4                    0
## 5                    0
## 6                    0
## 7                    1
## 8                    1
## 9                    0
## 10                   1

3. Create the network file and assign attributes for nodes and edges

net<-network(edges3[,c("ego_R_id", "alter_R_id")])

# Assign edge-level attributes - dyad attributes
set.edge.attribute(net, "ego_R_id", edges3[,2])
set.edge.attribute(net, "alter_R_id", edges3[,4])

# Assign node-level attributes to actors in "net"
net %v% "gender" <- nodes[,3]
net %v% "grade" <- nodes[,4]
net %v% "race" <- nodes[,5]
net %v% "pci" <- nodes[,6]

summary(net)
## Network attributes:
##   vertices = 22
##   directed = TRUE
##   hyper = FALSE
##   loops = FALSE
##   multiple = FALSE
##   bipartite = FALSE
##  total edges = 144 
##    missing edges = 0 
##    non-missing edges = 144 
##  density = 0.3116883 
## 
## Vertex attributes:
## 
##  gender:
##    integer valued attribute
##    22 values
## 
##  grade:
##    integer valued attribute
##    22 values
## 
##  pci:
##    integer valued attribute
##    22 values
## 
##  race:
##    integer valued attribute
##    22 values
##   vertex.names:
##    character valued attribute
##    22 valid vertex names
## 
## Edge attributes:
## 
##  alter_R_id:
##    numeric valued attribute
##    attribute summary:
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    1.00    9.00   12.50   12.49   17.00   22.00 
## 
##  ego_R_id:
##    numeric valued attribute
##    attribute summary:
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    1.00    7.75   12.00   11.97   16.25   22.00 
## 
## Network edgelist matrix:
##        [,1] [,2]
##   [1,]    1   10
##   [2,]    1   12
##   [3,]    1   19
##   [4,]    1    1
##   [5,]    1    7
##   [6,]    1   11
##   [7,]    1   15
##   [8,]    1   18
##   [9,]    1    6
##  [10,]    1    9
##  [11,]    1   17
##  [12,]    1    4
##  [13,]    1   22
##  [14,]    2   11
##  [15,]    2    7
##  [16,]    2   15
##  [17,]    3   11
##  [18,]    3    6
##  [19,]    3   19
##  [20,]    3    3
##  [21,]    4    4
##  [22,]    4    1
##  [23,]    4    7
##  [24,]    4   11
##  [25,]    4   19
##  [26,]    4   21
##  [27,]    5    5
##  [28,]    5   14
##  [29,]    5   18
##  [30,]    5   12
##  [31,]    5   16
##  [32,]    6    3
##  [33,]    6    6
##  [34,]    6   12
##  [35,]    7    9
##  [36,]    7    7
##  [37,]    8    8
##  [38,]    8   11
##  [39,]    8   13
##  [40,]    8   16
##  [41,]    9   11
##  [42,]    9   10
##  [43,]    9   16
##  [44,]    9   15
##  [45,]    9    9
##  [46,]    9   17
##  [47,]    9   19
##  [48,]    9    7
##  [49,]   10   10
##  [50,]   10   19
##  [51,]   10   13
##  [52,]   10    9
##  [53,]   10   17
##  [54,]   10   20
##  [55,]   11   11
##  [56,]   11    8
##  [57,]   11   18
##  [58,]   11   16
##  [59,]   11   15
##  [60,]   11    2
##  [61,]   11    9
##  [62,]   11   17
##  [63,]   12    1
##  [64,]   12   13
##  [65,]   12    7
##  [66,]   12    9
##  [67,]   12   10
##  [68,]   12   19
##  [69,]   12   17
##  [70,]   12    6
##  [71,]   12   16
##  [72,]   12    2
##  [73,]   12    5
##  [74,]   12   15
##  [75,]   12   21
##  [76,]   13   21
##  [77,]   13   13
##  [78,]   13   10
##  [79,]   13    9
##  [80,]   13    8
##  [81,]   14   17
##  [82,]   14    5
##  [83,]   14   11
##  [84,]   14   19
##  [85,]   14   16
##  [86,]   15   19
##  [87,]   15    1
##  [88,]   15   15
##  [89,]   15   11
##  [90,]   15    9
##  [91,]   15    2
##  [92,]   15   18
##  [93,]   15   21
##  [94,]   15   12
##  [95,]   15    7
##  [96,]   15   17
##  [97,]   16   12
##  [98,]   16   16
##  [99,]   16   15
## [100,]   16    9
## [101,]   16   11
## [102,]   16   18
## [103,]   16   13
## [104,]   16   14
## [105,]   16   17
## [106,]   16   20
## [107,]   16    8
## [108,]   16    5
## [109,]   17   22
## [110,]   17   17
## [111,]   18   16
## [112,]   18   11
## [113,]   18   22
## [114,]   18   18
## [115,]   18   17
## [116,]   18   15
## [117,]   18    5
## [118,]   19    7
## [119,]   19    3
## [120,]   19   10
## [121,]   19   19
## [122,]   19    1
## [123,]   19   15
## [124,]   19   16
## [125,]   19    9
## [126,]   20   18
## [127,]   20   16
## [128,]   20   20
## [129,]   20   19
## [130,]   20   11
## [131,]   20   10
## [132,]   20   21
## [133,]   21   20
## [134,]   21   12
## [135,]   21   15
## [136,]   21   13
## [137,]   22   18
## [138,]   22   11
## [139,]   22    5
## [140,]   22    9
## [141,]   22   19
## [142,]   22   17
## [143,]   22   15
## [144,]   22   22
plot(net,displaylabels=TRUE)

4. Run the ERGM

m1<-ergm(net ~ edges + mutual + nodematch("gender") + absdiff("pci"),burnin=15000,MCMCsamplesize=30000,verbose=FALSE)
## Warning in control.ergm.toplevel(control, ...): Passing burnin to ergm(...)
## is deprecated and may be removed in a future version. Specify it as
## control.ergm(MCMC.burnin=...) instead.
## Warning in control.ergm.toplevel(control, ...): Passing MCMCsamplesize to
## ergm(...) is deprecated and may be removed in a future version. Specify it
## as control.ergm(MCMC.samplesize=...) instead.
## Starting maximum likelihood estimation via MCMLE:
## Iteration 1 of at most 20: 
## The log-likelihood improved by 0.0003606 
## Step length converged once. Increasing MCMC sample size.
## Iteration 2 of at most 20: 
## The log-likelihood improved by 0.0002192 
## Step length converged twice. Stopping.
## 
## This model was fit using MCMC.  To examine model diagnostics and check for degeneracy, use the mcmc.diagnostics() function.
#mcmc.diagnostics(m1)
summary(m1)
## 
## ==========================
## Summary of model fit
## ==========================
## 
## Formula:   net ~ edges + mutual + nodematch("gender") + absdiff("pci")
## 
## Iterations:  2 out of 20 
## 
## Monte Carlo MLE Results:
##                    Estimate Std. Error MCMC %  p-value    
## edges            -2.316e+00  2.205e-01      0  < 1e-04 ***
## mutual            2.413e+00  3.537e-01      0  < 1e-04 ***
## nodematch.gender  1.457e-02  1.752e-01      0 0.933756    
## absdiff.pci       1.115e-04  3.061e-05      0 0.000299 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
##      Null Deviance: 640.5  on 462  degrees of freedom
##  Residual Deviance: 468.6  on 458  degrees of freedom
##  
## AIC: 476.6    BIC: 493.1    (Smaller is better.)
# show the exp() for the ERGM coefficients
lapply(m1[1],exp)
## $coef
##            edges           mutual nodematch.gender      absdiff.pci 
##       0.09870989      11.16682098       1.01467728       1.00011154