How do we know whether a node is important in a network? As was discussed at the beginning of the lecture on Degree Centrality, one of the most popular concepts in network analysis is centrality. In that lecture, we covered how centrality can be measured by the number of edges incident on a node. But, that is not they only way that a node can be central. The lecture on Closeness Centrality discussed an alternative conceptualization, closeness, where important nodes are those who are “close” to other nodes in the network.
In this lab, we will examine how to calculate closeness centrality
and centralization scores in R using the closeness()
and
centralization()
functions in the sna
package.
Why are you learning this? Centrality scores are a common metric used in many network analysis projects. Being able to calculate these scores and compare them is an important tool for your skill set as a social network analyst!
How close is a node to other nodes?
In an undirected binary graph, closeness centrality measures how near a node is to the other nodes in the network. This is based on the inverse of the distance of each actor to every other actor.
Terminology:
The distance, \(d(n_i,n_j)\), is the length of the path between i and j. For example, suppose Sally is friends with Tom, Ulrica, and Violet; Violet is friends with Tom and Walter. What are the paths from Violet to Ulrica? Walter from Ulrica?
A geodesic is the shortest path between two nodes. What is the shortest path (i.e. geodesic) from Violet to Ulrica?
Closeness centrality is calculated as:
\[C_C(n_i) = [\sum\limits_{j=1}^g d(n_i,n_j)]^{-1}\]
or
\[\frac{1}{[\sum\limits_{j=1}^g d(n_i,n_j)]}\] Here is what the equation is doing:
first identify the distances between i and j (i.e. \(d(n_i,n_j)\)) and sum them.
Note that \(\sum\limits_{j=1}^g\) is indicating that for i, we want to sum over all the js in the graph, g.
then take the inverse of this quantity.
We can manually calculate the distance matrix using the
geodist()
function in the sna
package. Let’s
take a look:
# clear the workspace
rm( list = ls() )
# load the sna library
library( sna )
# now, take a look at the geodist() function
?geodist
Let’s go ahead and set up a simple matrix and examine the geodesics for that matrix.
# set up the matrix
u.mat <- rbind(
c( 0,1,0,0,0 ),
c( 1,0,1,0,0 ),
c( 0,1,0,1,1 ),
c( 0,0,1,0,1 ),
c( 0,0,1,1,0 ))
# now set the names
mat.names <- c( "Jen","Tom","Bob","Leaf","Jim" )
rownames( u.mat ) <- mat.names
colnames( u.mat ) <- mat.names
# let's look at what the geodist() function creates
u.mat.geodist <- geodist( u.mat )
class( u.mat.geodist )
## [1] "list"
## $counts
## [,1] [,2] [,3] [,4] [,5]
## [1,] 1 1 1 1 1
## [2,] 1 1 1 1 1
## [3,] 1 1 1 1 1
## [4,] 1 1 1 1 1
## [5,] 1 1 1 1 1
##
## $gdist
## [,1] [,2] [,3] [,4] [,5]
## [1,] 0 1 2 3 3
## [2,] 1 0 1 2 2
## [3,] 2 1 0 1 1
## [4,] 3 2 1 0 1
## [5,] 3 2 1 1 0
We can see that the function creates an object of class
list
. In the object, there are two arrays,
$counts
and $gdist
. The $counts
array is a matrix containing the number of geodesics between each pair
of vertices. The $gdist
array is a matrix containing the
geodesic distances between each pair of vertices.
To get the geodesic distances, we use the $
sign to
select a single array from the list:
## [,1] [,2] [,3] [,4] [,5]
## [1,] 0 1 2 3 3
## [2,] 1 0 1 2 2
## [3,] 2 1 0 1 1
## [4,] 3 2 1 0 1
## [5,] 3 2 1 1 0
# if we take the row sum of this object, we get the distances
distance <- rowSums( u.mat.geodist$gdist )
distance
## [1] 9 6 5 7 7
Now, let’s plot the graph so we can visualize what the distance score is showing. To make it easier to see, let’s add the centrality info to the labels and size the nodes by centrality. That will make it easier to visualize.
# create a vector of labels that combines the name with the distances
# use the paste() function to put characters and numbers together
names.dist <- paste(
mat.names, # the names of the vertices
", ", # add a comma to separate name from degree
round( distance, 0 ), # add the rounded distance
sep = "" ) # remove the space between the two inputs
# change the margins using the mar= argument
par( mar=c( 0.1, 0.5, 1, 0.1 ) )
# set the seed to reproduce the same layout
set.seed( 605 )
# render the plot
gplot(
u.mat,
gmode = "graph",
label = names.dist,
label.cex = 0.6,
vertex.col = "lightblue"
)
In this plot, we see that Jen has a distance score of 9. (She is so far away!) To see how we get that score, let’s do the calculation:
recall that \(d(n_i,n_j)\) is the length of the path from i to j
Jen -> Tom (\(d(Jen,Tom)\)) is 1
Jen -> Bob (\(d(Jen,Bob)\)) is 2
Jen -> Leaf (\(d(Jen,Leaf)\)) and Jen -> Jim (\(d(Jen,Jim)\)) are both 3
So that is \(\sum\limits_{Jen}^g d(Jen,Tom/Bob/Leaf/Jim) = 1+2+3+3=9\).
To get the closeness centrality score, we divide that quantity by 1.
## [1] 0.1111111 0.1666667 0.2000000 0.1428571 0.1428571
# we can calculate the standardized closeness centrality by multiplying by g-1
g <- dim( u.mat )[1]
close.cent.s <- ( g-1 ) * close.cent
close.cent.s
## [1] 0.4444444 0.6666667 0.8000000 0.5714286 0.5714286
# put it all together in a table
dist.close.table <- round( rbind( distance, close.cent, close.cent.s ), 2 )
rownames( dist.close.table ) <- c( "distance", "closeness", "stand.close" )
colnames( dist.close.table ) <- mat.names
dist.close.table
## Jen Tom Bob Leaf Jim
## distance 9.00 6.00 5.0 7.00 7.00
## closeness 0.11 0.17 0.2 0.14 0.14
## stand.close 0.44 0.67 0.8 0.57 0.57
Now, let’s take a look at this info in a series of plots. To render
these, let’s use a for
loop:
names.close <- paste(
mat.names, # the names of the vertices
", ", # add a comma to separate name from degree
round( close.cent, 2 ), # add the rounded closeness centrality score
sep = "" ) # remove the space between the two inputs
names.s.close <- paste(
mat.names, # the names of the vertices
", ", # add a comma to separate name from degree
round( close.cent.s, 2 ), # add the rounded closeness centrality score
sep = "" ) # remove the space between the two inputs
# create the inputs for the loop
titles <- c( "Distance", "Closeness", "Standardized Closeness")
cols <- c( "lightblue", "lightgreen", "orange" )
names <- rbind( names.dist, names.close, names.s.close )
# change the margins using the mar= argument
par(
mfrow=c( 2,2 ),
mar=c( 0.1, 0.5, 1, 0.1 )
)
for( i in 1:3 ){
# set the seed
set.seed( 605 )
# render the plot
gplot(
u.mat,
gmode = "graph",
label = names[i,],
label.cex = 0.6,
vertex.col = cols[i],
main = titles[i]
)
}
sna
PackageAlternatively, we could just use the closeness()
function in the sna
package. First, take a look at the
function using ?closeness
. Note that the standardized
closeness centrality is reported by default. If we want the
unstandardized closeness, we can just divide the result returned by
closeness()
by g-1.
## [1] 0.4444444 0.6666667 0.8000000 0.5714286 0.5714286
## [1] 0.1111111 0.1666667 0.2000000 0.1428571 0.1428571
We can also summarize the entire network, in terms of how close nodes are to each other. Group closeness centralization tells us how much variation there is in the closeness scores. As we saw in the lab for degree centrality, this measure is bound between 0 and 1 where a value of 0 indicates complete uniformity across nodes in there centrality scores and a value of 1 indicates that one node has the highest possible centrality score, and all others are at the minimum.
This is calculated as: \(C_C = \frac{\sum\limits_{i=1}^g[C'_C(n^*)-C'_C(n_i)]}{[(g-2)(g-1)]/(2g-3)}\).
Where \(C'_C(n^*)\) is the
maximum or largest standarized closeness centrality score. For a more
elaborate discussion of this equation, see Wasserman & Faust (1994:
191-192). To calculate the group closeness centrality, we can use the
centralization()
function in sna
and specify
closeness
in the FUN
argument.
## [1] 0.5518519
What does the centralization score of 0.55 tell us?
In a directed binary graph, closeness centrality has the same interpretation (i.e. it is the inverse of the average distance between nodes), but it takes into account the directional nature of the graph.
For example, consider two scenarios:
+ Suppose Laura sends a tie to Miguel and he sends a tie to Bruce
(i.e. Laura -> Miguel -> Bruce). Here, Laura is of distance 2 from
Bruce. + Now suppose Laura sends a tie to Miguel and Bruce sends a tie
to Miguel (i.e. Laura -> Miguel <- Bruce). How far is Laura
from Bruce now?
Let’s take a look at this using the network from the Closeness Centrality lecture.
# Build the object
d.mat <- rbind(
c( 0,1,0,0,0 ),
c( 0,0,1,0,0 ),
c( 0,0,0,1,1 ),
c( 0,0,1,0,1 ),
c( 0,0,1,1,0 )
)
# name the rows and columns
rownames( d.mat ) <- c( "Jen","Tom","Bob","Leaf","Jim" )
colnames( d.mat ) <- c( "Jen","Tom","Bob","Leaf","Jim" )
# define g
g <- dim( d.mat )[1]
We can manually calculate the distance matrix using the
geodist()
function in the sna
package as we
did above.
# calculate distances
distances <- geodist( d.mat )
# get the geodesics
geodesics <- distances$gdist
# take a look
geodesics
## [,1] [,2] [,3] [,4] [,5]
## [1,] 0 1 2 3 3
## [2,] Inf 0 1 2 2
## [3,] Inf Inf 0 1 1
## [4,] Inf Inf 1 0 1
## [5,] Inf Inf 1 1 0
Something look different?
Let’s recode those Inf
values to be zero and chug
on.
## [,1] [,2] [,3] [,4] [,5]
## [1,] 0 1 2 3 3
## [2,] 0 0 1 2 2
## [3,] 0 0 0 1 1
## [4,] 0 0 1 0 1
## [5,] 0 0 1 1 0
## [1] 0.1111111 0.2000000 0.5000000 0.5000000 0.5000000
## [1] 0.4444444 0.8000000 2.0000000 2.0000000 2.0000000
sna
PackageAlternatively, we could (again) just use the closeness()
function in the sna
package. Remember that the standardized
closeness centrality is reported by default. If we want the
unstandardized closeness, we can just divide the result returned by
closeness()
by g-1.
## [1] 0.4444444 0.0000000 0.0000000 0.0000000 0.0000000
## [1] 0.1111111 0.0000000 0.0000000 0.0000000 0.0000000
As discussed in Wasserman & Faust (1994: 200-201), the
denominator is not defined for closeness centralization for directed
graphs. Yet, score can be computed using the
centralization()
function.
## [1] 0.5555556
What does the centralization score of 0.56 tell us?
The Prison Inmate Networks Study (PINS) examines the social networks of prison inmates in a state correctional institution. The study was unique in that it was the first in nearly a century to collection sociometric data in a prison. The researchers collected data on several types of networks. There are two we want to look at here:
The get along with network was created by asking individuals whom they “get along with” on the unit. We can think of this as “friends” in a prison setting. (People don’t really have “friends” in prison, but there are people they “get along with”)
The power and influence network was created by asking individuals whom they believed was “powerful and influential” on the unit.
Let’s examine the closeness centrality scores for both of these networks. These data are available in the SNA Textbook data folder.
For the get along with network, individuals could have asymmetric nominations. That is, i could nominate j and j didn’t necessarily nominate i. But, we are going to symmetrize the network by only taking ties for which both i and j indicated that the get along with the other person. This will give us an undirected network.
# set the location for the file
loc <- "https://github.com/jacobtnyoung/sna-textbook/raw/main/data/data-PINS-getalong-w1-adj.csv"
# read in the .csv file
gaMat <- as.matrix(
read.csv(
loc,
as.is = TRUE,
header = TRUE,
row.names = 1
)
)
# use the symmetrize() function to create an undirected matrix
gaMatU <- symmetrize( gaMat, rule = "strong" )
# create the network object
gaNetU <- as.network( gaMatU, directed = FALSE )
Now, we have created an undirected network where ties represent “get along with” nominations from both individuals.
Before we calculate the closeness scores, recall that in a graph with multiple components (i.e. disconnected subgraphs) individuals who cannot be reached will have a closeness score of zero. So, what do we do? Call it a day and go home? (We could, but we have some options)
What often happens in practice when we have multiple components in a network is that researchers will take the “first component” of and analyze the closeness scores for that graph. The first component is the largest subgraph in a graph. We can see this visually in the following plot:
In the plot above, the first component (i.e. the largest subgraph) is
colored green. To get the closeness centrality scores, we can use a
function called get.inducedSubgraph()
in the
sna
package to extract a subgraph that meets a condition.
In this case, we want to take those cases who are in the first
component. Let’s walk through the pieces.
# find the component membership
cd <- component.dist( as.matrix( gaNetU ), connected="weak" )
# find which component is the largest
sort( table( cd$membership ) )
##
## 1 2 3 5 6 7 8 9 10 12 13 14 16 17 19 20 21 22 23 25
## 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
## 26 27 29 30 31 32 33 34 35 36 38 40 41 42 43 44 45 47 49 50
## 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
## 51 52 53 55 56 58 60 61 63 64 65 66 67 68 69 70 71 73 74 76
## 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
## 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
## 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
## 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 114 115 116 117
## 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
## 119 120 121 122 123 124 125 126 127 128 129 18 28 39 46 48 57 59 75 113
## 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2
## 118 15 37 54 72 11 24 62 4
## 2 3 3 3 3 4 4 4 50
# we can see that group number 4 is the largest group. This is the first component.
# so, we can assign the membership in the first component
firstComp <- cd$membership
firstComp[ cd$membership != 4 ] <- 0
firstComp[ cd$membership == 4 ] <- 1
# now we set this as a network attribute
gaNetU %v% "firstComp" <- firstComp
# Now, remove those not in the first component by using the get.inducedSubgraph() function.
# Specifically, we stipulate in the v= argument that we only want vertices that are in the first component.
gaNetUcomp <- get.inducedSubgraph(
gaNetU, # the network
v = which( gaNetU %v% "firstComp" == 1 ) # the condition
)
# Now, take a look at the plot.
gplot(
gaNetUcomp,
gmode = "graph",
edge.col="grey40",
vertex.col="#9cde18",
main = "First Component of Get\n Along With Network (Undirected)" )
Now, let’s calculate our closeness scores:
# get the number of nodes
n.nodes <- dim( as.matrix( gaNetUcomp ) )[1]
# unstandardized closeness
closeness( gaNetUcomp, gmode="graph" ) / ( n.nodes - 1 )
## [1] 0.003533569 0.004545455 0.005524862 0.004854369 0.003039514 0.004184100
## [7] 0.005208333 0.005681818 0.005917160 0.004608295 0.004524887 0.004975124
## [13] 0.005076142 0.004545455 0.005102041 0.004629630 0.005128205 0.003584229
## [19] 0.004651163 0.005025126 0.003745318 0.003184713 0.004464286 0.002652520
## [25] 0.004219409 0.004629630 0.003021148 0.004975124 0.003759398 0.003076923
## [31] 0.005813953 0.003802281 0.005076142 0.004166667 0.003891051 0.003690037
## [37] 0.005405405 0.004484305 0.002680965 0.003496503 0.004629630 0.004000000
## [43] 0.003745318 0.006535948 0.005714286 0.004566210 0.005681818 0.004149378
## [49] 0.003058104 0.004032258
## [1] 0.1731449 0.2227273 0.2707182 0.2378641 0.1489362 0.2050209 0.2552083
## [8] 0.2784091 0.2899408 0.2258065 0.2217195 0.2437811 0.2487310 0.2227273
## [15] 0.2500000 0.2268519 0.2512821 0.1756272 0.2279070 0.2462312 0.1835206
## [22] 0.1560510 0.2187500 0.1299735 0.2067511 0.2268519 0.1480363 0.2437811
## [29] 0.1842105 0.1507692 0.2848837 0.1863118 0.2487310 0.2041667 0.1906615
## [36] 0.1808118 0.2648649 0.2197309 0.1313673 0.1713287 0.2268519 0.1960000
## [43] 0.1835206 0.3202614 0.2800000 0.2237443 0.2784091 0.2033195 0.1498471
## [50] 0.1975806
## [1] 0.214429
# define the rescale function
rescale <- function( nchar, low, high ){
min_d <- min( nchar )
max_d <- max( nchar )
rscl <- ( ( high - low )*( nchar - min_d ) ) / ( max_d - min_d ) + low
rscl
}
# now, take a look at the plot
gplot(
gaNetUcomp,
gmode = "graph",
edge.col="grey40",
vertex.col="#9cde18",
vertex.cex = rescale( closeness( gaNetUcomp, gmode="graph" ), 0.4, 3 ),
main = "First Component of Get\n Along With Network (Undirected)",
sub = "node sized by closeness centrality"
)
For the power and influence network, individuals could have asymmetric nominations. That is, i could nominate j and j didn’t necessarily nominate i. We will keep this asymmetry so that we can treat the network as directed.
# set the location for the file
loc <- "https://github.com/jacobtnyoung/sna-textbook/raw/main/data/data-PINS-power-w1-adj.csv"
# read in the .csv file
piMat <- as.matrix(
read.csv(
loc,
as.is = TRUE,
header = TRUE,
row.names = 1
)
)
# create the network object
piNetD <- as.network( piMat, directed = TRUE )
Now, we have created a directed network where ties represent “power and influence” nominations from i to j.
As before, we need to extract the first component:
In the plot above, the first component (i.e. the largest subgraph) is
shown in red. Now, let’s again use the
get.inducedSubgraph()
function in the sna
package to extract a subgraph that meets the first component
condition.
# find the component membership
cd <- component.dist( as.matrix( piNetD ), connected="weak" )
# find which component is the largest
sort( table( cd$membership ) )
##
## 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
## 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
## 22 23 24 25 26 27 28 29 30 31 32 33 34 36 37 38 39 40 41 42
## 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
## 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
## 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
## 63 64 65 66 67 68 69 71 72 73 74 75 76 77 78 79 80 81 82 83
## 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
## 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
## 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
## 104 105 106 107 108 35 70 1
## 1 1 1 1 1 2 3 95
# we can see that group number 1 is the largest group. This is the first component.
# so, we can assign the membership in the first component
firstComp <- cd$membership
firstComp[ cd$membership != 1 ] <- 0
firstComp[ cd$membership == 1 ] <- 1
# now we set this as a network attribute
piNetD %v% "firstComp" <- firstComp
# Now, remove those not in the first component by using the get.inducedSubgraph() function.
# Specifically, we stipulate in the v= argument that we only want vertices that are in the first component.
piNetDcomp <- get.inducedSubgraph(
piNetD, # the network
v = which( piNetD %v% "firstComp" == 1 ) # the condition
)
# Now, take a look at the plot.
gplot(
piNetDcomp,
gmode = "digraph",
edge.col="grey40",
vertex.col="#ab163b",
main = "First Component of Power\n Network (Directed)" )
Now, let’s calculate our closeness scores. Note a slight change
though. In the closeness()
function, there is the
gmode=
argument where we specify whether the graph is
directed (i.e. "digraph"
or undirected
"graph"
. If we use gmode = "digraph"
we will
get all zeros because it is using the directionality of the network. For
our purposes here, we will set it to gmode = "graph"
so we
can actually get values:
# get the number of nodes
n.nodes <- dim( as.matrix( piNetDcomp ) )[1]
#unstandardized closeness.
closeness( piNetDcomp, gmode="graph" ) / ( n.nodes - 1 )
## [1] 0.003367003 0.003891051 0.002857143 0.002824859 0.003311258 0.002531646
## [7] 0.003215434 0.002652520 0.002932551 0.002544529 0.002941176 0.002958580
## [13] 0.002531646 0.003831418 0.003215434 0.001754386 0.002659574 0.002666667
## [19] 0.003968254 0.003154574 0.002439024 0.002659574 0.003030303 0.002881844
## [25] 0.002793296 0.002994012 0.002985075 0.002237136 0.003311258 0.003571429
## [31] 0.002617801 0.004149378 0.002994012 0.003802281 0.003448276 0.002824859
## [37] 0.002881844 0.002127660 0.002604167 0.002331002 0.003289474 0.003030303
## [43] 0.002127660 0.003436426 0.003174603 0.002217295 0.002770083 0.002857143
## [49] 0.002531646 0.003205128 0.002985075 0.003436426 0.002237136 0.003649635
## [55] 0.002881844 0.003816794 0.002531646 0.002793296 0.003546099 0.002336449
## [61] 0.002570694 0.001754386 0.003460208 0.002976190 0.002898551 0.002217295
## [67] 0.002320186 0.002092050 0.003460208 0.003484321 0.003076923 0.003937008
## [73] 0.003389831 0.002341920 0.004048583 0.003745318 0.003533569 0.003984064
## [79] 0.002976190 0.002127660 0.002881844 0.002392344 0.002531646 0.002433090
## [85] 0.002057613 0.002985075 0.002824859 0.004132231 0.003436426 0.002985075
## [91] 0.002564103 0.003058104 0.002777778 0.002857143 0.003472222
## [1] 0.3164983 0.3657588 0.2685714 0.2655367 0.3112583 0.2379747 0.3022508
## [8] 0.2493369 0.2756598 0.2391858 0.2764706 0.2781065 0.2379747 0.3601533
## [15] 0.3022508 0.1649123 0.2500000 0.2506667 0.3730159 0.2965300 0.2292683
## [22] 0.2500000 0.2848485 0.2708934 0.2625698 0.2814371 0.2805970 0.2102908
## [29] 0.3112583 0.3357143 0.2460733 0.3900415 0.2814371 0.3574144 0.3241379
## [36] 0.2655367 0.2708934 0.2000000 0.2447917 0.2191142 0.3092105 0.2848485
## [43] 0.2000000 0.3230241 0.2984127 0.2084257 0.2603878 0.2685714 0.2379747
## [50] 0.3012821 0.2805970 0.3230241 0.2102908 0.3430657 0.2708934 0.3587786
## [57] 0.2379747 0.2625698 0.3333333 0.2196262 0.2416452 0.1649123 0.3252595
## [64] 0.2797619 0.2724638 0.2084257 0.2180974 0.1966527 0.3252595 0.3275261
## [71] 0.2892308 0.3700787 0.3186441 0.2201405 0.3805668 0.3520599 0.3321555
## [78] 0.3745020 0.2797619 0.2000000 0.2708934 0.2248804 0.2379747 0.2287105
## [85] 0.1934156 0.2805970 0.2655367 0.3884298 0.3230241 0.2805970 0.2410256
## [92] 0.2874618 0.2611111 0.2685714 0.3263889
## [1] 0.2273318
# Now, take a look at the plot.
gplot(
piNetDcomp,
gmode = "digraph",
edge.col="grey40",
vertex.col="#ab163b",
vertex.cex = rescale( closeness( piNetDcomp, gmode="graph" ), 0.4, 3 ),
main = "First Component of Power\n Network (Directed)",
sub = "node sized by closeness centrality"
)
A few questions:
Centrality scores are a common metric used in many network analysis
projects. In this lab, we examined how to calculate closeness
centrality and centralization scores in R using the
closeness()
and centralization()
functions in
the sna
package.