These functions are similar to the create_* functions, but include some element of randomisation. They are particularly useful for creating a distribution of networks for exploring or testing network properties.

  • generate_random() generates a random network with ties appearing at some probability.

  • generate_degree() generates a random network consistent with a given degree distribution, as the random counterpart of create_degree(). generate_configuration() is an alias, since this is the configuration model.

  • generate_man() generates a random network conditional on the dyad census of Mutual, Asymmetric, and Null dyads, respectively.

  • generate_utilities() generates the utility that each node finds in each other node, as a signed and weighted network.

These functions can create either one-mode or two-mode networks. To create a one-mode network, pass the main argument n a single integer, indicating the number of nodes in the network. To create a two-mode network, pass n a vector of two integers, where the first integer indicates the number of nodes in the first mode, and the second integer indicates the number of nodes in the second mode. As an alternative, an existing network can be provided to n and the number of modes, nodes, and directedness will be inferred.

generate_random(n, p = 0.5, directed = FALSE, with_attr = TRUE)

generate_degree(n, p = 1, directed = FALSE, outdegree = NULL, indegree = NULL)

generate_configuration(
  n,
  p = 1,
  directed = FALSE,
  outdegree = NULL,
  indegree = NULL
)

generate_man(n, p = NULL, directed = NULL, ...)

generate_utilities(
  n,
  p = 1,
  directed = TRUE,
  form = c("normal", "uniform", "relative"),
  steps = 1,
  volatility = 0.1,
  inertia = 0
)

Arguments

n

Given:

  • A single integer, e.g. n = 10, a one-mode network will be created.

  • A vector of two integers, e.g. n = c(5,10), a two-mode network will be created.

  • A manynet-compatible object, a network of the same dimensions will be created.

p

The main probability of the model, which is what makes a network of it more or less random. It always follows n, and what it is the probability of depends on the model. For generate_random(), it is the proportion of possible ties in the network that are realised or, if an integer greater than 1, the number of ties in the network, by default 0.5. For generate_degree(), it is the share of the ties that are switched with one another, by default 1, so that 0 returns the network as it was. For generate_man(), it is a vector of three: the proportions of Mutual, Asymmetric, and Null dyads, which is inferred from n if that is a network and is otherwise c(0.25, 0.5, 0.25). For generate_utilities(), it is the share of the utilities that are ties, by default 1.

directed

Logical whether the network should be directed. By default directed = FALSE, but for the functions that the usage above shows another default for. A network given as n sets the direction instead. If the opposite direction is desired, use to_redirected() on the output of these functions. In two-mode networks, the directed argument is ignored.

with_attr

Logical whether any attributes of the object should be retained. By default TRUE.

outdegree

Numeric scalar or vector indicating the desired outdegree distribution. Note that a scalar (single number) will result in a k-regular graph. By default NULL. If n is an existing network object and the outdegree is not specified, then the outdegree distribution will be inferred from that of the network. If only the indegree is specified, then in one-mode networks the outdegree will mirror it, and in two-mode networks the same number of ties will be spread as evenly as possible across the nodes in the first mode. If neither is specified, the sparsest connected structure is created: a cycle in one-mode networks, and in two-mode networks one in which the larger mode is 1-regular.

indegree

Numeric vector indicating the desired indegree distribution. By default NULL but not required unless a directed network is desired. If n is an existing directed network object and the indegree is not specified, then the indegree distribution will be inferred from that of the network. Otherwise it is filled in from the outdegree as described above.

...

Arguments under the names they had in earlier versions, which still work: man for p in generate_man().

form

How the utilities are distributed between -1 and 1.

  • "normal" (the default) draws them from a normal distribution around 0, so that most nodes are close to indifferent about most others and only a few are much liked or much disliked.

  • "uniform" draws every utility between -1 and 1 as likely as any other.

  • "relative" draws them from a normal distribution and then divides each node's utilities by the largest of them, whether liked or disliked, so that each node's utilities are relative to the node it feels most strongly about.

steps

Number of moments at which to return the utilities. By default 1. If more than 1, the utilities change from each moment to the next by as much as volatility allows, and a longitudinal network with a wave for each moment is returned.

volatility

How much the utilities change between moments. At each step a new set of utilities is drawn as form describes, multiplied by volatility, and added to those there are. By default 0.1, so that a utility changes by a tenth of a new draw.

inertia

The share of utilities that keep their value at each step, from 0 to 1. These are the utilities that would have changed the least, so that with some inertia utilities stay as they are until a change large enough comes along, rather than all drifting a little at every step. By default 0, so that every utility changes at every step.

Value

A stocnet object is returned, which can be coerced into other types of objects using as_edgelist(), as_matrix(), as_tidygraph(), as_igraph(), or as_network(). create_ring(), create_lattice(), generate_random(), generate_smallworld(), and generate_scalefree() return a tbl_graph or igraph object for now, since the released versions of the packages built on this one expect one from them.

By default, most networks are created as undirected. This can be overruled with the argument directed = TRUE. This will return a directed network in which the arcs are out-facing or equivalent. This direction can be swapped using to_redirected(). In two-mode networks, the directed argument is ignored.

Details

generate_degree() keeps the degree of every node and is random in which nodes are tied. The degrees are those of the network given as n, or those given as outdegree and indegree, as for create_degree(). It then switches the ends of pairs of ties, which changes who is tied to whom but not how many ties anyone has. With p = 1, the default, a network is drawn anew from those degrees. With a lower p only that share of the ties are switched, so that the result is in part the network it started from.

For generate_man(), counts such as p = c(10, 0, 20) are read as relative weights and normalised, so the dyad census is reproduced in expectation rather than exactly. The default is the dyad distribution of a random (Erdős-Rényi) digraph in which each arc is present with probability 0.5. The network is directed unless there are no asymmetric dyads, as with p = c(0.1, 0, 0.1), since it then has no direction to speak of. directed overrules this either way, and where an undirected network is asked for from asymmetric dyads, a dyad is tied where it would have been mutual or asymmetric. The same holds for two-mode networks, whose ties are undirected, so only the sum of the mutual and asymmetric dyads is consequential there.

A utility is how much a node gains or loses from a tie to another node, from -1 for the most it could lose to 1 for the most it could gain. generate_utilities() returns these as the weights of a signed network. In a one-mode network every node has a utility for every other node. In a two-mode network each node of the first mode has a utility for each node of the second mode.

Utilities say what ties nodes would like, not what ties there are, so they can serve as the basis for a model of how ties come about. The examples show two such models. Where a node can tie to another without its consent, the ties are the positive utilities. Where a tie needs the consent of both nodes, the ties are those where the lower of the two utilities is positive.

With p below 1, a node is indifferent to the utilities closest to 0, and only the share p of them that are furthest from 0 are ties, whether positive or negative. With directed = FALSE, the two nodes of a pair find the same in each other, and the network is undirected.

Where there is more than one step, how far from 0 a utility must be to be a tie is set at the first moment and kept, so a tie can come and go as a utility crosses it. A utility cannot rise above 1 or fall below -1, and one that a change would take further stays at that limit until a change brings it back. Over many steps the utilities therefore spread out towards the limits, and more of them are far enough from 0 to be ties than at the start.

References

On random networks

Erdos, Paul, and Alfred Renyi. 1959. "On Random Graphs I" Publicationes Mathematicae. 6: 290–297.

On configuration models

Bollobas, Bela. 1980. "A Probabilistic Proof of an Asymptotic Formula for the Number of Labelled Regular Graphs". European Journal of Combinatorics 1: 311-316.

On dyad-census conditioned networks

Holland, Paul W., and Samuel Leinhardt. 1976. “Local Structure in Social Networks.” In D. Heise (Ed.), Sociological Methodology, pp 1-45. San Francisco: Jossey-Bass.

Examples

generate_random(12, 0.4)
#> IGRAPH cb1accc U--- 12 28 -- Erdos-Renyi (gnp) graph
#> + attr: name (g/c), type (g/c), loops (g/l), p (g/n)
#> + edges from cb1accc:
#>  [1] 1-- 2 1-- 3 2-- 3 1-- 4 4-- 5 3-- 6 4-- 6 1-- 7 3-- 7 4-- 7 6-- 7 2-- 8
#> [13] 5-- 8 2-- 9 3-- 9 5-- 9 7-- 9 4--10 7--10 8--10 4--11 6--11 8--11 1--12
#> [25] 5--12 6--12 8--12 9--12
# generate_random(c(6, 6), 0.4)
generate_degree(12, outdegree = 3)
#> 
#> ── # Configuration network ─────────────────────────────────────────────────────
#> # A undirected network of 12 nodes and 18 ties
#> 
#> ── Ties 
#> # A tibble: 18 × 2
#>    from    to
#>   <int> <int>
#> 1     1     2
#> 2     1     7
#> 3     1    10
#> 4     2     3
#> 5     2     4
#> 6     3     7
#> # ℹ 12 more rows
#> 
generate_degree(create_core(12), p = 0.25)
#> ── # Configuration network ─────────────────────────────────────────────────────
#> # A undirected network of 12 nodes and 51 ties
#> 
#> ── Ties 
#> # A tibble: 51 × 2
#>    from    to
#>   <int> <int>
#> 1     1     2
#> 2     1     3
#> 3     1     4
#> 4     1     5
#> 5     1     6
#> 6     1     7
#> # ℹ 45 more rows
#> 
generate_man(6)
#> ── # Dyad census network ───────────────────────────────────────────────────────
#> # A directed network of 6 nodes and 15 arcs
#> 
#> ── Ties 
#> # A tibble: 15 × 2
#>    from    to
#>   <int> <int>
#> 1     1     3
#> 2     1     4
#> 3     1     5
#> 4     2     1
#> 5     2     6
#> 6     3     2
#> # ℹ 9 more rows
#> 
generate_man(6, p = c(0.3, 0, 0.7))
#> ── # Dyad census network ───────────────────────────────────────────────────────
#> # A undirected network of 6 nodes and 7 ties
#> 
#> ── Ties 
#> # A tibble: 7 × 2
#>    from    to
#>   <int> <int>
#> 1     1     2
#> 2     1     3
#> 3     2     3
#> 4     1     4
#> 5     1     5
#> 6     4     6
#> # ℹ 1 more row
#> 
generate_man(c(4, 6))
#> ── # Dyad census network ───────────────────────────────────────────────────────
#> # A two-mode network of 4 FALSEs and 6 TRUEs and 20 ties
#> 
#> ── Nodes 
#> # A tibble: 10 × 1
#>   mode 
#>   <chr>
#> 1 FALSE
#> 2 FALSE
#> 3 FALSE
#> 4 FALSE
#> 5 TRUE 
#> 6 TRUE 
#> # ℹ 4 more rows
#> 
#> ── Ties 
#> # A tibble: 20 × 2
#>    from    to
#>   <int> <int>
#> 1     1     5
#> 2     1     6
#> 3     1     7
#> 4     1     9
#> 5     2     5
#> 6     2     6
#> # ℹ 14 more rows
#> 
(utils <- generate_utilities(6))
#> ── # Utilities network ─────────────────────────────────────────────────────────
#> # A signed, weighted, directed network of 6 nodes and 30 arcs
#> 
#> ── Ties 
#> # A tibble: 30 × 3
#>    from    to  weight
#>   <int> <int>   <dbl>
#> 1     1     2  0.250 
#> 2     1     3  0.0156
#> 3     1     4 -0.104 
#> 4     1     5  0.465 
#> 5     1     6 -0.493 
#> 6     2     1  0.610 
#> # ℹ 24 more rows
#> 
generate_utilities(6, p = 0.25)
#> ── # Utilities network ─────────────────────────────────────────────────────────
#> # A signed, weighted, directed network of 6 nodes and 8 arcs
#> 
#> ── Ties 
#> # A tibble: 8 × 3
#>    from    to weight
#>   <int> <int>  <dbl>
#> 1     3     1  0.475
#> 2     3     2  0.427
#> 3     4     3 -0.991
#> 4     5     3  0.506
#> 5     5     6 -0.412
#> 6     6     1 -0.462
#> # ℹ 2 more rows
#> 
generate_utilities(6, directed = FALSE)
#> ── # Utilities network ─────────────────────────────────────────────────────────
#> # A signed, weighted, undirected network of 6 nodes and 15 ties
#> 
#> ── Ties 
#> # A tibble: 15 × 3
#>    from    to  weight
#>   <int> <int>   <dbl>
#> 1     1     2 -0.454 
#> 2     1     3 -0.454 
#> 3     1     4 -0.301 
#> 4     1     5 -0.0818
#> 5     1     6 -0.0227
#> 6     2     3 -0.229 
#> # ℹ 9 more rows
#> 
generate_utilities(c(4, 6), form = "uniform")
#> ── # Utilities network ─────────────────────────────────────────────────────────
#> # A signed, weighted, two-mode network of 4 FALSEs and 6 TRUEs and 24 ties
#> 
#> ── Nodes 
#> # A tibble: 10 × 1
#>   mode 
#>   <chr>
#> 1 FALSE
#> 2 FALSE
#> 3 FALSE
#> 4 FALSE
#> 5 TRUE 
#> 6 TRUE 
#> # ℹ 4 more rows
#> 
#> ── Ties 
#> # A tibble: 24 × 3
#>    from    to  weight
#>   <int> <int>   <dbl>
#> 1     1     5  0.231 
#> 2     2     5  0.859 
#> 3     3     5  0.963 
#> 4     4     5 -0.0679
#> 5     1     6  0.776 
#> 6     2     6  0.969 
#> # ℹ 18 more rows
#> 
generate_utilities(6, steps = 3)
#> ── # Utilities network ─────────────────────────────────────────────────────────
#> # A longitudinal, signed, weighted, directed network of 6 nodes and 90 arcs
#> over 3 waves
#> 
#> ── Ties 
#> # A tibble: 90 × 4
#>    from    to  weight  time
#>   <int> <int>   <dbl> <int>
#> 1     1     2  0.550      1
#> 2     1     3  0.368      1
#> 3     1     4  0.103      1
#> 4     1     5  0.384      1
#> 5     1     6 -0.157      1
#> 6     2     1 -0.0695     1
#> # ℹ 84 more rows
#> 
generate_utilities(6, steps = 3, volatility = 0.5, inertia = 0.8)
#> ── # Utilities network ─────────────────────────────────────────────────────────
#> # A longitudinal, signed, weighted, directed network of 6 nodes and 90 arcs
#> over 3 waves
#> 
#> ── Ties 
#> # A tibble: 90 × 4
#>    from    to  weight  time
#>   <int> <int>   <dbl> <int>
#> 1     1     2  0.260      1
#> 2     1     3  0.242      1
#> 3     1     4 -0.914      1
#> 4     1     5 -0.0883     1
#> 5     1     6 -0.443      1
#> 6     2     1 -0.139      1
#> # ℹ 84 more rows
#> 
# the ties that one node wants
to_unsigned(utils, keep = "positive")
#> ── # Utilities network ─────────────────────────────────────────────────────────
#> # A weighted, directed network of 6 nodes and 17 arcs
#> # Transformed by exclusion: negative ties (13 ties excluded)
#> 
#> ── Ties 
#> # A tibble: 17 × 3
#>    from    to weight
#>   <int> <int>  <dbl>
#> 1     1     2 0.250 
#> 2     1     3 0.0156
#> 3     1     5 0.465 
#> 4     2     1 0.610 
#> 5     2     5 0.348 
#> 6     2     6 0.259 
#> # ℹ 11 more rows
#> 
# the ties that both nodes want
to_unsigned(to_undirected(utils, rule = "min"), keep = "positive")
#> # A weighted, undirected network of 6 nodes and 6 ties
#> # Transformed by symmetrisation: min and exclusion: negative ties
#> 
#> ── Ties 
#> # A tibble: 6 × 3
#>    from    to weight
#>   <int> <int>  <dbl>
#> 1     1     2 0.250 
#> 2     1     3 0.0156
#> 3     2     5 0.154 
#> 4     2     6 0.0388
#> 5     3     4 0.115 
#> 6     5     6 0.0204
#>