3
votes

I want to map a number of relationship circles (consisting of a list of ids) into a large adjacency matrix. My data looks like this

circle_1 = c(1, 3, 5)
circle_2 = c(17, 22, 35, 49)
circle_3 = c(2, 9)
circle_4 = c(12, 28, 33)
circle_5 = c(1, 3, 8, 16, 40)

d_mat = matrix(ncol = 2)

for (i in 1:5) {
#extract id from list
dat = get(paste("circle", i, sep="_"))
#convert to edgelist, each pair is unique
dat_t = t(combn(dat, 2))
#rbind edge list together
edge_list <- rbind(d_mat, dat_t)
}

However, the output edge_list only returns the edge list of from the last iteration (circle_5) with the preceding three being overwritten.

Furthermore, suppose these five circles were drawn from a group of 50 persons, how can I map the values of such edge list to the corresponding cells of a 50 by 50 adjacency matrix? (I suppose make_graph and as_adjacency_matrix function in igraph should do the tricks, but I don't know how at the moment)

Also, for overlapping membership, such (1, 3) in circle_1 and circle_5, meaning that 1 and 3 are linked twice in this 50-person network. How can I aggregate this count frequency and convert the adjacency matrix into a weighted matrix?

2
Wow, that's very slick answer. Thanks a lot!Chris T.

2 Answers

2
votes

You can do it as you've started by combining the edge lists and then just create the matrix directly.

circle_1 = c(1, 3, 5)
circle_2 = c(17, 22, 35, 49)
circle_3 = c(2, 9)
circle_4 = c(12, 28, 33)
circle_5 = c(1, 3, 8, 16, 40)

# lets put all the circles in a list for convenience
circles <- list(circle_1, circle_2, circle_3,
                circle_4, circle_5)

# we will lapply along the list, get the complete set of 
# edges with combn, and then rbind all the resulting
# structures together
edge_list <- do.call(rbind, lapply(circles, function(circ){t(combn(circ, 2))}))

# we convert to a data.frame and set the factor levels
# such that R knows these are nodes from a set of 50 nodes
edge_list <- data.frame(from = factor(edge_list[,1], levels=1:50),
                        to = factor(edge_list[,2], levels=1:50))
# take a look
head(edge_list)
#>   from to
#> 1    1  3
#> 2    1  5
#> 3    3  5
#> 4   17 22
#> 5   17 35
#> 6   17 49
# we can just use table to make the adjacency matrix. R will create
# a row/column for each level of the factor. We look at the first
# 6x6 entries
table(edge_list)[1:6,1:6] # luckily entry (1,3) = 2 as we hoped
#>     to
#> from 1 2 3 4 5 6
#>    1 0 0 2 0 1 0
#>    2 0 0 0 0 0 0
#>    3 0 0 0 0 1 0
#>    4 0 0 0 0 0 0
#>    5 0 0 0 0 0 0
#>    6 0 0 0 0 0 0

This adjacency matrix is upper triangular. If you want the adjacency matrix to be symmetrical as reflecting an undirected graph you can set the upper and lower triangles of the matrix to be equal using adj.mat[lower.tri(adj.mat)] <- adj.mat[upper.tri(adj.mat)].

If you want the matrix to be just binary (and not record multiple links in different circles) just run it through an ifelse statement:

# to convert to purely binary
adj.mat <- table(edge_list)
adj.mat.bin <- ifelse(adj.mat>1, 1, adj.mat)
adj.mat.bin[1:6,1:6]
#>     to
#> from 1 2 3 4 5 6
#>    1 0 0 1 0 1 0
#>    2 0 0 0 0 0 0
#>    3 0 0 0 0 1 0
#>    4 0 0 0 0 0 0
#>    5 0 0 0 0 0 0
#>    6 0 0 0 0 0 0

Created on 2018-11-16 by the reprex package (v0.2.1)

1
votes

I borrow the list of vertices ('circles') from @gfgm and use igraph functions.

Loop over the list of vertices with lapply. For each set of vertices, create a full graph (make_full_graph), with number of vertices n equal to length of the vector. Set the name of the vertices (V(g)$name). Convert to 'edge list' (as_edgelist). rbind the resulting matrices.

library(igraph)
m <- do.call(rbind, lapply(circles, function(vert){
  g <- make_full_graph(n = length(vert))
  V(g)$name <- vert
  as_edgelist(g)
}))

Set factor levels of 'from' and 'to' vertices, and use table (similar to @gfgm)

tt <- table(factor(m[ , 1], levels = 1:50),
            factor(m[ , 2], levels = 1:50)) 

t[1:8, 1:16]
#   1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
# 1 0 0 2 0 1 0 0 1 0  0  0  0  0  0  0  1
# 2 0 0 0 0 0 0 0 0 1  0  0  0  0  0  0  0
# 3 0 0 0 0 1 0 0 1 0  0  0  0  0  0  0  1
# 4 0 0 0 0 0 0 0 0 0  0  0  0  0  0  0  0
# 5 0 0 0 0 0 0 0 0 0  0  0  0  0  0  0  0
# 6 0 0 0 0 0 0 0 0 0  0  0  0  0  0  0  0
# 7 0 0 0 0 0 0 0 0 0  0  0  0  0  0  0  0
# 8 0 0 0 0 0 0 0 0 0  0  0  0  0  0  0  1