These functions offer tools for projecting manynet-consistent data:
to_mode() projects a two-mode network to a one-mode network
of the node set given by the mode argument, which accepts either the
index of the mode or its name.
to_mode1() projects a two-mode network to a one-mode network
of the first node set's (e.g. rows) joint affiliations to nodes in the second node set (columns).
to_mode2() projects a two-mode network to a one-mode network
of the second node set's (e.g. columns) joint affiliations to nodes in the first node set (rows).
to_linegraph() projects a network to its line graph,
where the ties become nodes and incident nodes become their ties.
to_hypergraph() reformats one-mode or two-mode network data as hypergraph data,
where ties can connect more than two nodes.
to_simplicial() projects network data into a simplicial complex,
such as the maximal cliques of a one-mode network.
to_mode1(
.data,
similarity = c("count", "jaccard", "rand", "pearson", "yule", "match", "overlap",
"crossmin", "maxcrossmin", "sqdiff", "covariance", "bonacich", "ochiai", "ochiai2",
"czekanowski", "sokalsneath", "hamann", "rogerstanimoto", "euclidean", "manhattan",
"hamming", "cosine", "spearman", "kendall", "ruzicka")
)
to_mode2(
.data,
similarity = c("count", "jaccard", "rand", "pearson", "yule", "match", "overlap",
"crossmin", "maxcrossmin", "sqdiff", "covariance", "bonacich", "ochiai", "ochiai2",
"czekanowski", "sokalsneath", "hamann", "rogerstanimoto", "euclidean", "manhattan",
"hamming", "cosine", "spearman", "kendall", "ruzicka")
)
to_mode(
.data,
mode = 1,
similarity = c("count", "jaccard", "rand", "pearson", "yule", "match", "overlap",
"crossmin", "maxcrossmin", "sqdiff", "covariance", "bonacich", "ochiai", "ochiai2",
"czekanowski", "sokalsneath", "hamann", "rogerstanimoto", "euclidean", "manhattan",
"hamming", "cosine", "spearman", "kendall", "ruzicka")
)
to_linegraph(.data)
to_hypergraph(.data)
to_simplicial(.data)An object of a {manynet}-consistent class:
adjacency or incidence matrix from {base} R
edgelist data.frame from {base} R or tbl/tbl_df from {tibble}
stocnet stocnet, from the {manynet} package
igraph igraph, from the {igraph} package
network network, from the {network} package
tidygraph tbl_graph, from the {tidygraph} package
Method for establishing ties in the projection, "count" by default.
The measures are grouped below by what they are sensitive to. Within a group they are monotone transformations of one another, and so rank dyads identically, differing only in their scale. Choosing between the groups therefore matters rather more than choosing within one.
Measures defined for valued as well as binary data:
"count" counts the coinciding ties, the cross-product \(XX'\).
For valued data it sums the products of tie strengths.
Interpret it as the degree of opportunity between two nodes.
This is the default, and the quickest, since it can use
igraph::bipartite_projection() directly.
"match" counts the cells in which two nodes hold exactly the same value, joint absences included. For binary data this is "rand" multiplied by the number of nodes in the other mode, but for valued data it is the more general measure, since it registers agreement at any tie strength. Use it where the level of involvement is meaningful in itself.
"crossmin" sums the smaller of each pair of tie strengths. Interpret it as the capacity two nodes could jointly bring to bear. For binary data it reduces to "count".
"overlap" divides "crossmin" by the smaller of the two nodes' total tie strength, the Szymkiewicz-Simpson or overlap coefficient, and so lies in \([0,1]\) for non-negative data. Use it where one node is much more active than the other, and the less active node's rarity should not depress the score. For binary data it is the count over the smaller degree. xUCINET keeps that count for valued data too, where it can exceed 1 and is no longer the coefficient.
"ruzicka" divides "crossmin" by the two nodes' combined tie strength less than shared, Ruzicka's weighted Jaccard coefficient, and so also lies in \([0,1]\). For binary data it is "jaccard", so use it where "jaccard" is wanted but the tie strengths should be kept.
"maxcrossmin" takes the largest such minimum rather than their sum, so that a single strong shared affiliation stands for the pair. For binary data it collapses to an indicator of any shared affiliation, and so is of little use there.
"sqdiff" inverts the sum of squared differences in tie strength, as \(1/(1+d)\), so that identical rows give 1 and larger values mean more alike, as for every other measure here. Recover the raw sum of squared differences as \(1/x - 1\).
"pearson" gives Pearson's product-moment correlation and "covariance" its unstandardised counterpart. Use "covariance" where the variance in involvement is itself of interest, and "pearson" where it is not.
"spearman" and "kendall" are the rank counterparts of "pearson". Use them where tie strengths order the affiliations reliably but their spacing does not, as with ordinal ratings.
"cosine" gives the cosine of the angle between two nodes' rows. It differs from "pearson" in not centring them first, so that it reads two nodes as alike where their involvements are proportional rather than where they depart from the average in the same direction. For binary data it agrees with "ochiai", except that a node with no ties at all is reported as no more similar to another than any other node, where "ochiai" would divide by zero.
"euclidean" and "manhattan" invert the straight-line and the city-block distance between two rows, again as \(1/(1+d)\). "manhattan" sums the absolute differences in tie strength, so that a large discrepancy on one affiliation counts no more than the same total spread over several; "euclidean" penalises the concentrated discrepancy more heavily, as "sqdiff" does. Recover either raw distance as \(1/x - 1\).
Measures defined for binary data only, where a valued network is dichotomised at zero with a warning. Writing \(a\) for the cells in which both nodes are present, \(b\) and \(c\) for those in which just one is, and \(d\) for those in which neither is:
Sensitive to co-presence, ignoring joint absence: "jaccard" is \(a/(a+b+c)\), opportunity weighted by participation; "czekanowski" (the Dice or Sorensen coefficient) is \(2a/(2a+b+c)\), which double-weights co-presence; and "sokalsneath" is \(a/(a+2(b+c))\), which instead double-weights mismatch. Use these where joint non-participation says nothing, as in a sparse affiliation network with many events. For valued data, "ruzicka" is the counterpart of "jaccard" that keeps the tie strengths.
Sensitive to matching, counting joint absence as evidence: "rand", the Simple Matching Coefficient, is \((a+d)/(a+b+c+d)\); "hamann" is \(((a+d)-(b+c))/(a+b+c+d)\), the same quantity rescaled onto \([-1,1]\) so that its sign reports whether matches outnumber mismatches; and "rogerstanimoto" is \((a+d)/(a+2(b+c)+d)\), which double-weights mismatch. Interpret these as the degree of behavioural mirroring between two nodes, and use them where not attending is as informative as attending.
Sensitive to association, through the odds ratio \(ad/bc\): "yule" is Yule's Q, \((ad-bc)/(ad+bc)\), which has a straightforward reading as a rescaled odds ratio; and "bonacich" is \(\sqrt{ad}/(\sqrt{ad}+\sqrt{bc})\), which is Yule's Y rescaled onto \([0,1]\). Both saturate at 1 wherever \(b\) or \(c\) is zero.
Geometric: "ochiai" is \(a/\sqrt{(a+b)(a+c)}\), the cosine of the angle between two nodes' affiliation vectors, and "ochiai2" (also known as Sokal and Sneath's fifth measure) is \(ad/\sqrt{(a+b)(a+c)(d+b)(d+c)}\), its counterpart including joint absence. Neither is monotone in any of the above, so both are worth trying alongside them.
"hamming" inverts the Hamming distance, the number of cells in which the two nodes differ, as \(1/(1+d)\). It is a monotone transformation of "rand", and so ranks dyads identically, but states the disagreement as a count rather than as a proportion of agreement.
Which mode to project the network to,
as an index, 1 or 2, as FALSE or TRUE, or as the name of the mode.
Mode 1 is the first node set, e.g. the rows, and is the default.
FALSE is the first mode and TRUE the second,
as the modes of an unnamed two-mode network are marked.
A name is matched against the names of the modes,
which mode_names() returns and add_info() sets.
The match ignores case, plurals, and any other words in the name,
so that a network whose modes are named "women" and "social events"
can be projected with either "social events", "events", or "event".
Where a name matches both modes, as "events" would where they are named
"social events" and "work events", the function reports the ambiguity
and asks for a name that tells them apart, or an index.
The network must have two modes. Projecting one mode of a network of three or more would need a second mode to project through, which this function does not yet accept, so it reports the modes it found instead.
An object of the same class as the function was given, modified as explained in the function description, details, or section. Functions that split a network return a list of such objects.
Not all functions have methods available for all object classes. Below are the currently implemented S3 methods:
| Category | Feature | manynet::to_mode1()/to_mode2() | igraph::bipartite_projection() | network/sna manual |
| Input | Dedicated function | yes | yes | no |
| Accepted input classes | igraph, network, tidygraph, matrix, edgelist | igraph only | any (manual extraction) | |
| Detects mode membership from | mode node attribute | type vertex attribute | bipartite network attr (positional) | |
| Projection | Returns both projections at once | no — one per call | yes — list of two | two manual calls |
| Projects mode 1 (actors) | to_mode1() | which = "true" | A %*% t(A) | |
| Projects mode 2 (events) | to_mode2() | which = "false" | t(A) %*% A | |
| Weights | Raw co-membership counts | yes | yes (multiplicity = TRUE) | yes |
| Binary (unweighted) output | yes | yes (multiplicity = FALSE) | threshold manually | |
| Jaccard normalisation | yes | no | code manually | |
| Cosine normalisation | yes | no | code manually | |
| Other similarity measures | 25 in all, see similarity | no | code manually | |
| Attributes | Retains node attributes | yes | yes | no — lost in matrix round-trip |
| Retains edge attributes | weight only | weight only | no | |
| Removes self-loops automatically | yes | yes | diag(P) <- 0 manually | |
| Output | Output class matches input | yes | no | no |
| Directed projection support | limited | no — undirected only | yes — asymmetric matrix | |
| Usability | Lines of code (basic case) | 1 | 1 | 4–6 |
| Lines of code (Jaccard weights) | 1 | ~8 manual | ~8 manual | |
| Pipe-friendly | yes | with wrappers | no |
A hypergraph is a network in which a tie, a hyperedge, can connect any
number of nodes, such as the people at a meeting or the authors of a paper.
to_hypergraph() reformats one-mode or two-mode network data as
hypergraph data and returns the class it was given.
Nothing is lost either way.
For two-mode networks, each node of the second mode becomes a hyperedge
that connects the nodes of the first mode tied to it.
The attributes of the second-mode nodes become attributes of the
hyperedges, and the attributes of the ties,
such as their weights, become attributes of each node's membership.
to_twomode() returns the two-mode network.
For one-mode networks, each tie becomes a hyperedge of its two nodes,
and keeps its attributes.
Where the ties are directed, the hyperedges are too:
the sender is on the 'from' side and the receiver on the 'to' side.
to_mode() returns the one-mode network.
A 'stocnet' object holds each hyperedge as one row of its ties,
which lists the hyperedge's members in a with column
(see the Hypergraphs section of make_stocnet()).
Other classes have no hyperedges of their own,
so they hold each hyperedge as a node of a second mode,
and mark that they do so, so that is_hypergraph() recognises them and
coercion back to a 'stocnet' object returns the hyperedges.
A 'network' object is the exception, since {network} has hyperedges.
A simplicial complex is a hypergraph in which every subset of a hyperedge
is a hyperedge too, so that it is described in full by its largest
hyperedges, or faces.
to_simplicial() projects network data into the largest faces of a
simplicial complex, and marks the result as one.
For one-mode networks, the faces are the maximal cliques of the network,
since every subset of a clique is a clique.
The direction, weights, and other attributes of the ties are not carried.
to_mode() returns the one-mode network that the cliques cover.
For two-mode networks and hypergraphs, the faces are the hyperedges that are not a subset of another hyperedge.
Borgatti, Stephen P., and Daniel S. Halgin. 2011. "Analyzing affiliation networks". In The SAGE Handbook of Social Network Analysis, 417-433. London: SAGE.
Bonacich, Phillip. 1972. "Technique for analyzing overlapping memberships". Sociological Methodology 4: 176-185. doi:10.2307/270732
to_proximity(), which applies these same measures to a one-mode
network, comparing nodes on their ties to one another rather than on
their affiliations to a second mode.
to_cosine(), which takes the cosine over the columns of a
matrix without projecting it.
Other modifications:
modif_backbone,
modif_concepts,
modif_direction,
modif_from_parts,
modif_from_ternary,
modif_labels,
modif_levels,
modif_miss,
modif_motifs,
modif_paths,
modif_permutation,
modif_plexity,
modif_proximity,
modif_scope,
modif_split,
modif_weight
Other projections:
modif_concepts
to_mode1(ison_southern_women)
#>
#> ── # Projection of Southern Women Data ─────────────────────────────────────────
#> # A labelled, weighted, undirected network of 18 nodes and 139 participation
#> ties
#> # Transformed by projection: mode 1 (count)
#>
#> ── Nodes
#> # A tibble: 18 × 4
#> label Surname Title active
#> <chr> <chr> <chr> <lgl>
#> 1 Evelyn Jefferson Mrs TRUE
#> 2 Laura Mandeville Miss TRUE
#> 3 Theresa Anderson Miss TRUE
#> 4 Brenda Rogers Miss TRUE
#> 5 Charlotte McDowd Miss TRUE
#> 6 Frances Anderson Miss TRUE
#> # ℹ 12 more rows
#>
#> ── Ties
#> # A tibble: 139 × 3
#> from to weight
#> <int> <int> <dbl>
#> 1 1 2 6
#> 2 1 4 6
#> 3 1 3 7
#> 4 1 5 3
#> 5 1 6 4
#> 6 1 7 3
#> # ℹ 133 more rows
#>
to_mode2(ison_southern_women)
#> ── # Projection of Southern Women Data ─────────────────────────────────────────
#> # A labelled, weighted, undirected network of 14 nodes and 66 participation
#> ties
#> # Transformed by projection: mode 2 (count)
#>
#> ── Nodes
#> # A tibble: 14 × 4
#> label Surname Title active
#> <chr> <chr> <chr> <lgl>
#> 1 E1 6/27 NA FALSE
#> 2 E2 3/2 NA FALSE
#> 3 E3 4/12 NA FALSE
#> 4 E4 9/26 NA FALSE
#> # ℹ 10 more rows
#>
#> ── Changes
#> # A tibble: 14 × 4
#> time node var value
#> <date[1d]> <int> <chr> <list>
#> 1 1936-02-23 11 active TRUE<lgl>
#> 2 1936-02-25 5 active TRUE<lgl>
#> 3 1936-03-02 2 active TRUE<lgl>
#> 4 1936-03-15 7 active TRUE<lgl>
#> # ℹ 10 more rows
#>
#> ── Ties
#> # A tibble: 66 × 3
#> from to weight
#> <int> <int> <dbl>
#> 1 1 2 2
#> 2 1 3 3
#> 3 1 4 2
#> 4 1 5 3
#> # ℹ 62 more rows
#>
to_mode(ison_southern_women, 2)
#> ── # Projection of Southern Women Data ─────────────────────────────────────────
#> # A labelled, weighted, undirected network of 14 nodes and 66 participation
#> ties
#> # Transformed by projection: mode 2 (count)
#>
#> ── Nodes
#> # A tibble: 14 × 4
#> label Surname Title active
#> <chr> <chr> <chr> <lgl>
#> 1 E1 6/27 NA FALSE
#> 2 E2 3/2 NA FALSE
#> 3 E3 4/12 NA FALSE
#> 4 E4 9/26 NA FALSE
#> # ℹ 10 more rows
#>
#> ── Changes
#> # A tibble: 14 × 4
#> time node var value
#> <date[1d]> <int> <chr> <list>
#> 1 1936-02-23 11 active TRUE<lgl>
#> 2 1936-02-25 5 active TRUE<lgl>
#> 3 1936-03-02 2 active TRUE<lgl>
#> 4 1936-03-15 7 active TRUE<lgl>
#> # ℹ 10 more rows
#>
#> ── Ties
#> # A tibble: 66 × 3
#> from to weight
#> <int> <int> <dbl>
#> 1 1 2 2
#> 2 1 3 3
#> 3 1 4 2
#> 4 1 5 3
#> # ℹ 62 more rows
#>
to_mode(ison_southern_women, "events")
#> ── # Projection of Southern Women Data ─────────────────────────────────────────
#> # A labelled, weighted, undirected network of 14 nodes and 66 participation
#> ties
#> # Transformed by projection: mode 2 (count)
#>
#> ── Nodes
#> # A tibble: 14 × 4
#> label Surname Title active
#> <chr> <chr> <chr> <lgl>
#> 1 E1 6/27 NA FALSE
#> 2 E2 3/2 NA FALSE
#> 3 E3 4/12 NA FALSE
#> 4 E4 9/26 NA FALSE
#> # ℹ 10 more rows
#>
#> ── Changes
#> # A tibble: 14 × 4
#> time node var value
#> <date[1d]> <int> <chr> <list>
#> 1 1936-02-23 11 active TRUE<lgl>
#> 2 1936-02-25 5 active TRUE<lgl>
#> 3 1936-03-02 2 active TRUE<lgl>
#> 4 1936-03-15 7 active TRUE<lgl>
#> # ℹ 10 more rows
#>
#> ── Ties
#> # A tibble: 66 × 3
#> from to weight
#> <int> <int> <dbl>
#> 1 1 2 2
#> 2 1 3 3
#> 3 1 4 2
#> 4 1 5 3
#> # ℹ 62 more rows
#>
to_linegraph(ison_adolescents)
#> IGRAPH 80e2a24 UN-- 10 20 -- Line graph
#> + attr: name (g/c), name (v/c)
#> + edges from 80e2a24 (vertex names):
#> [1] Betty-Sue --Sue-Alice Sue-Alice --Alice-Jane Betty-Sue --Sue-Dale
#> [4] Sue-Alice --Sue-Dale Sue-Dale --Alice-Dale Sue-Alice --Alice-Dale
#> [7] Alice-Jane--Alice-Dale Sue-Dale --Jane-Dale Alice-Dale--Jane-Dale
#> [10] Alice-Jane--Jane-Dale Betty-Sue --Sue-Pam Sue-Alice --Sue-Pam
#> [13] Sue-Dale --Sue-Pam Sue-Pam --Alice-Pam Sue-Alice --Alice-Pam
#> [16] Alice-Jane--Alice-Pam Alice-Dale--Alice-Pam Sue-Pam --Pam-Carol
#> [19] Alice-Pam --Pam-Carol Pam-Carol --Carol-Tina
to_hypergraph(ison_southern_women)
to_simplicial(ison_adolescents)
#> ── # The Adolescent Society ────────────────────────────────────────────────────
#> # A labelled, two-mode network of 8 nodes and 6 hyperedges and 15 ties
#>
#> ── Nodes
#> # A tibble: 14 × 2
#> name type
#> <chr> <lgl>
#> 1 Betty FALSE
#> 2 Sue FALSE
#> 3 Alice FALSE
#> 4 Jane FALSE
#> 5 Dale FALSE
#> 6 Pam FALSE
#> # ℹ 8 more rows
#>
#> ── Ties
#> # A tibble: 15 × 2
#> from to
#> <int> <int>
#> 1 1 9
#> 2 2 9
#> 3 7 10
#> 4 8 10
#> 5 6 11
#> 6 7 11
#> # ℹ 9 more rows
#>