3 Creating network objects in R
Now that we have our edge lists and node lists, we want to create our first network object. We are going to start by making a one-mode network.
There are two popular network packages (and consequently, network object types) in R. igraph
generates a list object of class “igraph” and network
generates an list object of class “network”. We are going to be working primarily with network
objects, but I’d like to start by making both because you are likely to run into both of them along the way, and both are compatible with the ggraph
package that we will be using.
So, let’s read in our two network packages.
library(igraph)
library(network)
3.1 igraph
First, let’s make an igraph
object. igraph
generally seems to have more documentation/Stack Overflow resources than other network packages, so it might be tempting to start here. We can load in the igraph
package and use the graph_from_data_frame()
function to create our graph. Note that there are dozens of graph_from...
functions. Many of them sound (and are) intuitive. When dealing with edge and node lists, I prefer graph_from_data_frame()
over graph_from_edgelist()
because the former allows us to include the node list as an argument, whereas the latter does not.
For our one-mode networks we want to use the edges_1mode
and nodes_1mode
objects.
<- graph_from_data_frame(edges_1mode, vertices = nodes_1mode, directed = F) g1
We can take a look at a summary of the igraph object below. We see the number of nodes (139) and edges (475) summarized at top and our list of node attributes (followed by (v/[datatype])) and edges attributes (followed by (e/[datatype])).
summary(g1)
## IGRAPH a659ffa UN-- 139 475 --
## + attr: name (v/c), url (v/c), mode (v/n), org_type (v/c), Y1995_2009
## | (e/l), Y2010_2024 (e/l), before_1980 (e/l), Y1980_1994 (e/l)
The syntax for manipulating igraphs is demonstrated below. We use the V()
and E()
functions to call on either vertices or edges of our igraph, respective. hen can use the $
symbol to subset from those elements of the network.
# Subset the vertex attribute: the names of the vertices
head(V(g1)$name)
## [1] "Agricultural Coalitions: Landowners membership fees"
## [2] "Anchor QEA"
## [3] "Audubon Canyon Ranch"
## [4] "Bachand and Associates"
## [5] "BTS"
## [6] "CalFish"
# Subset the edge attribute: a logical value for whether a collaboration
# happened between 1995-2009
head(E(g1)$Y1995_2009)
## [1] TRUE FALSE FALSE FALSE FALSE FALSE
3.2 network
Personally, I find that the igraph
package has more limited statistical functionality than network
package (and its associated statnet
suite of packes), so I prefer network
objects. We initialize a network object with the network
function (network
really needs to get more creative in its naming approaches). Just like with igraph
, for our one-mode network we will use our projected edges and mode one nodes.
Note: You’ll often see folks converting igraphs to network objects using the intergraph
package.
library(intergraph)
<- asNetwork(g1) net1_convert
This conversion function can be very useful, but be sure to double check your work. Right now, with a relatively simple network (undirected and unweighted) the conversion works fine, but in other cases the default settings may require some attention. Because of this, personally I like to generate network objects directly from my edge and node lists.
Within the network
package we can use the network
function and read in our edge lists (as the x argument), vertices, and specify features of the network such as whether or not it is directed or bipartite.
<- network(x = edges_1mode,
net1 vertices = nodes_1mode,
bipartite = F,
directed = F)
When we print out a network object we get a different-looking summary, but it generally carries the same information:
net1
## Network attributes:
## vertices = 139
## directed = FALSE
## hyper = FALSE
## loops = FALSE
## multiple = FALSE
## bipartite = FALSE
## total edges= 475
## missing edges= 0
## non-missing edges= 475
##
## Vertex attribute names:
## mode name org_type url vertex.names
##
## Edge attribute names:
## before_1980 Y1980_1994 Y1995_2009 Y2010_2024
The syntax for manipulating network
objects is demonstrated below. First, we can use network
’s series of get.
functions to index components of the network. For node attributes, you can use get.vertex.attribute
:
head(get.vertex.attribute(net1, 'name'))
## [1] "Agricultural Coalitions: Landowners membership fees"
## [2] "Anchor QEA"
## [3] "Audubon Canyon Ranch"
## [4] "Bachand and Associates"
## [5] "BTS"
## [6] "CalFish"
For edge attributes, you can use get.edge.attribute
:
head(get.edge.attribute(net1, 'before_1980'))
## [1] FALSE FALSE FALSE FALSE FALSE FALSE
You can also use special operators, %v%
and %e%
, call on either vertices or edges of our network and then name the attribute in quotation marks
head(net1 %v% 'name')
## [1] "Agricultural Coalitions: Landowners membership fees"
## [2] "Anchor QEA"
## [3] "Audubon Canyon Ranch"
## [4] "Bachand and Associates"
## [5] "BTS"
## [6] "CalFish"
head(net1 %e% 'Y1995_2009')
## [1] TRUE FALSE FALSE FALSE FALSE FALSE
3.2.1 Preparing to work with network
For the remainder of this tutorial are going to stick to working with the network
package, even though the functions we will use for visualization are compatible with both objects. I propose using network objects because they are compatible with more advanced statistical analysis provided through the statnet
suite of packages.
Because we will be using exclusively network
objects, we want to detach igraph
before we continue further. This is because there are several commonly-used network functions in both igraph
and sna
that mask one another. For instance:
::degree()
sna::degree() igraph
The igraph
degree function will work only on igraph
objects and sna
degree
function will work only on network
objects. To avoid confusion and masking in R, we are going to detach the igraph
package and work only with network
objects and compatible packages like sna
.
detach("package:igraph", unload = TRUE)