These functions calculate how core-like each node is, returning both a
continuous coreness score and a core/periphery split that
node_is_core(), node_by_core() and node_in_core() then use.
coreness_correlation() fits the network to an ideal core-periphery
pattern by correlation.
coreness_rich() ranks nodes by strength and cuts where the tie
weight to higher-ranked neighbours peaks.
coreness_transition() scores nodes with a transition function whose
sharpness and core size are free parameters.
coreness_hub() scores nodes by how well they send to and receive from
the core, which lets core and periphery differ by tie direction.
They differ in what they can use. coreness_rich() and
coreness_hub() read tie direction and tie weights directly.
coreness_correlation() and coreness_transition() compare the network
against a symmetric ideal, so they symmetrise a directed network first
and report that they have done so.
coreness_correlation(.data, direction = c("all", "out", "in"), starts = 5L)
coreness_rich(.data, direction = c("all", "out", "in"))
coreness_transition(
.data,
direction = c("all", "out", "in"),
alpha = seq(0.2, 0.8, 0.2),
beta = seq(0.2, 0.8, 0.2)
)
coreness_hub(.data, direction = c("all", "out", "in"))A network object of class stocnet, igraph, tbl_graph, network, or similar.
Internally any of these will be coerced to an efficient implementation.
For more information on possible coercions, see e.g. manynet::as_stocnet().
One of "all" (the default), "out", or "in". For a directed network, "out" scores nodes on the ties they send and "in" on the ties they receive. Ignored for undirected and two-mode networks.
Integer number of starting points for the search, at most 9. By default 5. The starting points are fixed rather than random, so that two calls on the same network return the same answer.
Numeric vector of boundary sharpness values between 0 and 1,
to aggregate over. By default seq(0.2, 0.8, 0.2).
Numeric vector of core size values between 0 and 1,
to aggregate over. By default seq(0.2, 0.8, 0.2).
A list with two elements:
coreness: a numeric vector between 0 and 1, one value per node,
for how core-like each node is.
core: a logical vector, one value per node, TRUE for the core.
coreness_hub() adds out_core and in_core, the two core sets that a
directed core-periphery structure distinguishes.
Borgatti and Everett's continuous model gives each node a coreness \(c_i\) between 0 and 1, and compares the network against the ideal pattern \(c_i c_j\) in which two nodes are tied to the extent that both are core: $$\rho = \text{cor}(A_{ij}, c_i c_j), i \neq j$$ The coreness vector that maximises \(\rho\) is the fitted model. Self-ties are excluded from the correlation, since no node is tied to itself and including the diagonal pulls every coreness toward zero.
The problem is not convex, so the search is run from several starting
points, ordered by degree, and the best fit is kept.
A weighted network is fitted to its weights, which means that the ideal
pattern is read as how strongly two core nodes should be tied.
To fit the pattern of ties instead of their weights,
use manynet::to_unweighted() first.
The search has one free value per node, so its cost grows quickly with
the size of the network. On a large network, lower starts, or use
coreness_rich(), which needs no search at all.
Ma and Mondragon rank the nodes by strength, from strongest to weakest, and give each node the total weight of its ties to nodes that rank above it: $$\sigma_i^+ = \sum_{j : r_j < r_i} w_{ij}$$ Walking down the ranking, \(\sigma^+\) rises while the nodes added are still tied to those already above them, and falls once they are not. The rank at which it peaks is the boundary of the rich core.
The method needs no parameters and no optimisation, and it reads tie weights and tie direction directly, which makes it the method this package uses by default for a weighted, directed, or two-mode network. For a two-mode network the nodes of both modes are ranked together, so the core may span both.
Note that the core it finds is one whose members are tied to each other.
Where a directed network instead has one set that sends and a different
set that receives, \(\sigma^+\) never rises, and the method returns a
core of one or two nodes. Use coreness_hub() for that structure, which
keeps the two sets apart rather than trying to merge them.
A rich core is not a rich club, which is why this method is not named for
one. A rich club requires the high-degree nodes to be densely tied to one
another, and net_by_richclub() measures that density. A rich core only
marks the rank at which nodes stop linking upward, so a network can have
a rich core whose members are not densely tied. The rich core also needs
no null model, where the rich-club coefficient does, since that
coefficient rises with degree even in a random network.
Rombach and colleagues score the node at rank \(m\) with a transition function $$C_m = \frac{1}{1 + \exp(-(m - N\beta)\tan(\pi\alpha/2))}$$ where \(\alpha\) sets how sharp the boundary between core and periphery is, from fuzziest at 0 to a clean step at 1, and \(\beta\) sets how large the core is, from every node at 0 to none at 1. The ordering that maximises the core quality \(R = \sum_{ij} A_{ij} C_i C_j\) is the fitted model.
No single \(\alpha\) and \(\beta\) is right for every network, so the score is aggregated over a grid of both, weighting each by the core quality it achieves, and scaled so that the most core-like node is 1.
In a directed network a node can be core in whom it reaches and peripheral in who reaches it. Elliott and colleagues therefore keep two core sets rather than one: an out-core of nodes that send to the core, and an in-core of nodes that receive from it.
The two are read from the hub and authority scores that
node_by_hub() and node_by_authority() already provide: a hub is a
node that points to good authorities, and an authority is a node that
good hubs point to, which is the same mutual definition the two core sets
have. Each set is then cut by the same rule the other methods use.
With direction = "all" the returned coreness is the geometric mean of
the two scores, and the core is the set of nodes in both.
Borgatti, Stephen P., and Martin G. Everett. 2000. "Models of core/periphery structures". Social Networks 21(4): 375-395. doi:10.1016/S0378-8733(99)00019-2
Lip, Sean Z. W. 2011. "A fast algorithm for the discrete core/periphery bipartitioning problem". doi:10.48550/arXiv.1102.5511
Ma, Athen, and Raul J. Mondragon. 2015. "Rich-cores in networks". PLoS ONE 10(3): e0119678. doi:10.1371/journal.pone.0119678
Rombach, Puck, Mason A. Porter, James H. Fowler, and Peter J. Mucha. 2017. "Core-periphery structure in networks (revisited)". SIAM Review 59(3): 619-646. doi:10.1137/17M1130046
Elliott, Andrew, Angus Chiu, Marya Bazzi, Gesine Reinert, and Mihai Cucuringu. 2020. "Core-periphery structure in directed networks". Proceedings of the Royal Society A 476(2241): 20190783. doi:10.1098/rspa.2019.0783
Other methods:
method_regularity
coreness_correlation(ison_adolescents)
#> $coreness
#> Betty Sue Alice Jane Dale Pam Carol Tina
#> 0.0650368 0.6515254 1.0000000 0.3979140 0.6172661 0.4120254 0.0000000 0.0000000
#>
#> $core
#> [1] FALSE TRUE TRUE FALSE TRUE FALSE FALSE FALSE
#>
coreness_rich(ison_networkers)
#> $coreness
#> Lin Freeman Doug White Ev Rogers Richard Alba
#> 1.0000000000 0.4009705248 0.0023364486 0.0990294752
#> Phipps Arabie Carol Barner-Barry Gary Coombs Russ Bernard
#> 0.0255212078 0.0630841121 0.0075485262 0.5174335011
#> John Boyd Ron Burt Pat Doreian Claude Fischer
#> 0.0832135155 0.1132278936 0.2640186916 0.0316319195
#> Brian Foster Mark Granovetter Maureen Hallinan Paul Holland
#> 0.0107836089 0.0318116463 0.0620057513 0.0774622574
#> Jack Hunter Davor Jedlicka Charles Kadushin Ed Laumann
#> 0.0742271747 0.0549964055 0.0239036664 0.0005391804
#> Sam Leinhardt Joel Levine Nan Lin Nick Mullins
#> 0.0057512581 0.0452911574 0.0136592380 0.2129762761
#> Don Ploch Nick Poushinsky Steve Seidman John Sonquist
#> 0.0210280374 0.0235442128 0.1083752696 0.0000000000
#> Barry Wellman Al Wolfe Sue Freeman Lee Sailer
#> 0.6252695902 0.1063982746 0.3738317757 0.3375269590
#>
#> $core
#> [1] TRUE TRUE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE
#> [13] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
#> [25] FALSE FALSE FALSE FALSE TRUE FALSE TRUE TRUE
#>
coreness_transition(ison_adolescents)
#> $coreness
#> [1] 0.3019575 0.9622348 1.0000000 0.6262096 0.8917447 0.7828835 0.3400829
#> [8] 0.0000000
#>
#> $core
#> [1] FALSE TRUE TRUE FALSE TRUE FALSE FALSE FALSE
#>
coreness_hub(ison_networkers)
#> $coreness
#> [1] 1.000000000 0.567671811 0.005634952 0.111812047 0.020660080 0.095994085
#> [7] 0.017708648 0.625318882 0.107039476 0.127999324 0.358597695 0.053456745
#> [13] 0.012309808 0.048695416 0.124465321 0.117969155 0.104618345 0.080756776
#> [19] 0.020806891 0.000000000 0.015220081 0.056388396 0.020431138 0.275129846
#> [25] 0.026231141 0.054356232 0.139529296 0.000000000 0.705799552 0.159437663
#> [31] 0.394717426 0.482473568
#>
#> $core
#> [1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
#> [13] TRUE TRUE TRUE TRUE TRUE TRUE TRUE FALSE TRUE TRUE TRUE TRUE
#> [25] TRUE TRUE TRUE FALSE TRUE TRUE TRUE TRUE
#>
#> $out_core
#> [1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
#> [13] TRUE TRUE TRUE TRUE TRUE TRUE TRUE FALSE TRUE TRUE TRUE TRUE
#> [25] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
#>
#> $in_core
#> [1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
#> [13] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
#> [25] TRUE TRUE TRUE FALSE TRUE TRUE TRUE TRUE
#>