Remove edges by specifying endpoints - r

How can I delete edges from a graph by naming their endpoints?
delete_edges expects edge numbers, and it's not clear to me the mapping between endpoints and edge numbers.
library(igraph)
g = make_ring(10)
Say I wanted to remove the vertices between nodes 7&8 and nodes 9&10.
A hackish way to do so is:
g = delete_edges(g, c(7, 9))
But I had to inspect the output of E(g) closely before figuring out that those edges are numbered 7 & 9.
I tried looking for how the print methods assign the node mapping to E(g) but it looks like quite the rabbit hole.

It looks like you can do this with a string argument -- see the second example in ?delete_edges.
g = delete_edges(g, c("7|8", "9|10"))
g
# IGRAPH U--- 10 8 -- Ring graph
# + attr: name (g/c), mutual (g/l), circular (g/l)
# + edges:
# [1] 1-- 2 2-- 3 3-- 4 4-- 5 5-- 6 6-- 7 8-- 9 1--10
Apparently c("7|8", "9|10") also counts as an "edge sequence" as described in the edges argument.

Nota that:
get.edge.ids(g, c(7,8, 9, 10))
will return edge ids 7, 9. Therefore
delete_edges(g, get.edge.ids(g, c(7,8, 9, 10)))
produces the desired result:
1] 1-- 2 2-- 3 3-- 4 4-- 5 5-- 6 6-- 7 8-- 9 1--10

Related

Contract verticies by attribute with igraph

I am working on a graph, where each node has an attribute "group" of the following: "Baby Product", "Book" "CE" "DVD" "Music" "Software" "Toy" "Video" "Video Games".
I would like to know how to plot a graph reppresenting those communities: there shall be 9 verticies, one for each group, and a link (possibly weighted) each time two nodes of two categories are connected.
I have tried using the igraph contract function, but this is the result:
> contract(fullnet, mapping=as.factor(products$group), vertex.attr.comb = products$group)
Error in FUN(X[[i]], ...) :
Unknown/unambigous attribute combination specification
Inoltre: Warning message:
In igraph.i.attribute.combination(vertex.attr.comb) :
Some attributes are duplicated
I guess I have misunderstood what this function is used for.
Now I am thinking about creating a new edgelist, made like the one before but instead of the Id of each vertex the name of the group. Sadly, I do not know how to do this in a fast way on an edgelist of over 1200000 elements.
Thank you very much in advance.
I think using contract() should be correct. In the example code below, I added an anonymous function to vertex.attr.comb to combine the vertices by group. Then, simplify() removes loop edges and calculate the sum of edge weight.
# Create example graph
set.seed(1)
g <- random.graph.game(10, 0.2)
V(g)$group <- rep(letters[1:3], times = c(3, 3, 4))
E(g)$weight <- 1:length(E(g))
E(g)
# + 9/9 edges from 7017c6a:
# [1] 2-- 3 3-- 4 4-- 7 5-- 7 5-- 8 7-- 8 3-- 9 2--10 9--10
E(g)$weight
# [1] 1 2 3 4 5 6 7 8 9
# Contract graph by `group` attribute of vertices
g1 <- contract(g, factor(V(g)$group),
vertex.attr.comb = function(x) levels(factor(x)))
# Remove loop edges and compute the sum of edge weight by group
g1 <- simplify(g1, edge.attr.comb = "sum")
E(g1)
# + 3/3 edges from a852397:
# [1] 1--2 1--3 2--3
E(g1)$weight
# [1] 2 15 12

Recuperate maximum bipartite matching from maxFlowFordFulkerson in R

I want to find the maximum bipartite matching, so I'll use Flow Ford Fulkerson's algorithm, as explained here.
But when I implement the function, I only get the value of the maximum flow, but what interests me is the flow itself, so that I can find the matching.
Can anybody help me?
I used the function maxFlowFordFulkerson in R.
There is no way to do that using only the output of the function you've found. Besides the value of the maximum flow, it does also provide a minimum cut, which provides some additional information but still not what you're looking for.
Using the example from the page you refer to (reproduced below for ease of reference):
> library("optrees")
> vertices <- 1:14
> edges <- matrix(c(1,2,1, 1,3,1, 1,4,1, 1,5,1, 1,6,1, 1,7,1, 2,9,1, 2,10,1, 4,8,1, 4,11,1, 5,10,1, 6,11,1, 7,13,1, 8,14,1, 9,14,1, 10,14,1, 11,14,1, 12,14,1, 13,14,1), byrow = TRUE, ncol = 3)
> maxFlowFordFulkerson(vertices, edges, source.node = 1, sink.node = 14)
$s.cut
[1] 1 3
$t.cut
[1] 2 4 5 6 7 8 9 10 11 12 13 14
$max.flow
[1] 5
Here, the vertices in the two partitions are 2:7 and 8:13 respectively, so this tells us that vertex 3, i.e. the second vertex from the top in the left partition, remains unmatched, but other than that it tells you nothing about the matching.
If you want to stick to igraph, you can use maximum.bipartite.matching to get what you want. As this one operates on bipartite graphs directly, we don't have to mess with the auxiliary source/sink vertices at all. With the example from above:
> library("igraph")
> A <- matrix(c(0,1,1,0,0,0, 0,0,0,0,0,0, 1,0,0,1,0,0, 0,0,1,0,0,0, 0,0,1,1,0,0, 0,0,0,0,0,1), byrow = T, ncol = 6)
> g <- graph.incidence(A)
> maximum.bipartite.matching(g)
$matching_size
[1] 5
$matching_weight
[1] 5
$matching
[1] 8 NA 7 9 10 12 3 1 4 5 NA 6
Here, the left partition is represented by 1:6, and the right partition by 7:12. From $matching, we read that the 6 vertices in the left partition are matched with 8, nothing, 7, 9, 10, and 12 respectively.

Combine community detection with connected components grouping igraph R

I use igraph cluster_spinglass to detect compartments (communities) in a directed network but that only works for connected components
g <- graph_from_literal( 1 -+ 4 -+ 7,2 -+ 5 -+ 9, 4+-5,
3 -+ 6,5 -+8, 8-+ 9, simplify = FALSE)
m<-cluster_spinglass(g)
Gives an error, the solution is to extract the connected component
dg <- components(g)
g1 <- induced_subgraph(g, which(dg$membership == which.max(dg$csize)))
m<-cluster_spinglass(g1)
I get the memberships of the nodes (vertices) with
m$membership
But here I don't have all the nodes of the original network g, I would like to add another group with these nodes so I have all the original nodes clasified in different groups.
You can just transfer this into your original graph g.
In your example, I think that you just want the vertices in the
other connected component to be another community, it suffices to assign all nodes in the second component to group 3.
V(g)$membership = 3
V(g)[V(g1)$name]$membership = m$membership
V(g)$membership
[1] 1 1 1 2 2 2 3 3 2
But in a more general example, there might be multiple components and those components might break up into multiple communities.
To cover that, you can loop through all components, compute the communities and then transfer those back to the original graph.
V(g)$membership = 0
for(comp in unique(dg$membership)) {
g1 <- induced_subgraph(g, which(dg$membership == comp))
m<-cluster_spinglass(g1)
V(g)[V(g1)$name]$membership = m$membership + max(V(g)$membership)
}
V(g)$membership
[1] 1 1 1 2 2 2 3 3 2

Extract edges between community nodes and other nodes

Suppose we have a simple weighted network on which we perform some sort of community detection. Next we extract particular community and the final task is to extract all edges between nodes of this community and all other nodes.
Below I pasted the toy code.
# Create toy graph
library(igraph)
set.seed(12345)
g <- make_graph("Zachary")
# Add weights to edges
E(g)$weight <- sample(x = 1:10, size = ecount(g), replace = TRUE)
# Run community detection
cl <- cluster_louvain(g)
There are 5 nodes which belong to community #1, 12 nodes which belong to community #2, etc.
> table(membership(cl))
1 2 3 4
5 12 2 15
Now we extract community #1:
g1 <- induced_subgraph(g, which(cl$membership == 1))
Question: how to find edges which connect nodes in community #1 with all other nodes (excluding edges which define community #1)?
Start by getting all edges based in your community:
all_edges <- E(g)[inc(V(g)[membership(cl) == 1])]
all_edges
+ 10/78 edges:
[1] 1-- 5 1-- 6 1-- 7 1--11 5-- 7 5--11 6-- 7 6--11 6--17 7--17
Then, filter out the ones that are completely internal (both vertices are in the community):
all_edges_m <- get.edges(g, all_edges) #matrix representation
all_edges[!(
all_edges_m[, 1] %in% V(g)[membership(cl) == 1] &
all_edges_m[, 2] %in% V(g)[membership(cl) == 1]
)] # filter where in col1 and col2
+ 4/78 edges:
[1] 1-- 5 1-- 6 1-- 7 1--11

R: Calculating adjacent vertex after deletion of nodes

I'm very new to R and trying to calculate the adjacent vertices of a graph, which is obtained from deleting certain nodes from an original graph.
However, the output of the result doesn't match with the plot of the graph.
For example:
library(igraph)
g <- make_ring(8)
g <- add_edges(g, c(1,2, 2,7, 3,6, 4,5, 8,2, 6,2))
V(g)$label <- 1:8
plot(g)
h <- delete.vertices(g, c(1,2))
plot(h)
If I compute:
adjacent_vertices(h,6)= 5
However, I want the output to be 3,5,7 as the plot shows. The problem lies in the fact that it doesn't know I'm trying to find the adjacent vertices of node labelled 6.
Could someone please help. Thanks.
The issue here is that when you delete the vertices, the indices for the remaining vertices are shifted down to [0,6]:
> V(h)
+ 6/6 vertices:
[1] 1 2 3 4 5 6
To find the neighbors, using the original vertex names, you could then simply offset the values by the number of vertices removed, e.g.:
> neighbors(h, 6 - offset) + offset
+ 3/6 vertices:
[1] 3 5 7
A better approach, however, would be to refer to the vertex labels instead of using the indices:
> V(g)$label
[1] 1 2 3 4 5 6 7 8
> V(h)$label
[1] 3 4 5 6 7 8
> V(h)[V(h)$label == 6]
+ 1/6 vertex:
[1] 4
To get the neighbors of your vertex of interest, you can modify your code to look like:
> vertex_of_interest <- V(h)[V(h)$label == 6]
> neighbors(h, vertex_of_interest)$label
[1] 3 5 7

Resources