How to add specific weights to some edges? - r

In a network I find out some specific nodes, for example 3, 4, 5 and an initial node 9. I want to add weights to those edges and I need to call in future.
More specific: I need to add weights to edge:(3,9), (4,9), (5,9). And lately I need to recall those weights to do some calculation, i.e. I need a="(3,9)'s weights" something like this.

Since you do not provide any data, I will use a simple example that has links like the ones you describe.
## A simple example
library(igraph)
set.seed(1234)
g = make_ring(10)
g = add_edges(g, c(3,9,4,9,5,9))
E(g)$weight = 1
LO = layout_nicely(g)
plot(g, layout=LO)
If you have the "Intitial Node" and the "Specific Nodes", you can identify the Special Edges.
## Get the ids of the special edges
InitialNode = 9
ConnectingNodes = c(3,4,5)
ENDS = as.vector(rbind(ConnectingNodes, InitialNode))
SpecialEdges = get.edge.ids(g, ENDS)
With the IDs of the special edges, you can adjust their weights.
## Add weight to the special edges
E(g)$weight[SpecialEdges] = c(2,4,6)
## plot to show the weights
plot(g, edge.width=E(g)$weight)
If you later need to do something with the weights, you can access the weights using:
E(g)$weight[SpecialEdges]
[1] 2 4 6

Related

Simulate ERGM with nodal attributes

I was wondering whether it is possible to simulate networks that come from an ERGM distribution in which the nodes have attributes. For example, if I wanted to simulate a network where triangles between nodes with similar attributes are more likely, I would do something like:
library(ergm)
g_sim = simulate(network(n, directed=FALSE) ~ triangles + nodematch,
nsim=1,
coef=thetas)
But the thing is that these kind of statistics that depend on node attributes (i.e. like nodematch) require parameters, which I don't have because the network doesn't exist beforehand (I'm trying to simulate it).
How could this be done?
Will something like this work?
library(ergm)
# Initialize an empty network with N nodes
N <- 50
g <- network(1, directed = FALSE)
add.vertices(g, N - network.size(g))
# Make up a node classification to go with nodematch
type <- rbinom(N, 1, .25)
g %v% "type" <- ifelse(type, "green", "blue")
# Set the parameters of the model.
# Use large coefficients to make the result clear.
# These coefficients should set the base density and the
# density of edges between nodes of the same type.
thetas <- c(-2.5, 2.5)
# Simulate one network
# I'm using edges instead of triangles because of the
# tendancy towards degeneracy with triangles (my first attempt
# had a density of 1.0)
g_sim <- simulate(
g ~ edges + nodematch("type"),
nsim = 1,
coef = thetas
)
# Plot to be sure. There should be many more edges between
# nodes of the same color than nodes of different colors.
plot(g_sim, vertex.col = g %v% "type")
# Are the coefficients similar to what they should be?
m <- ergm(g_sim ~ edges + nodematch("type"))
summary(m)

How to calculate the number of vertices contracted into one graph?

I have a few large igraph objects that represent social networks. All nodes have various attributes, among them sector which is a factor variable. I have contracted this large network into a small where vertices represent groups and edges have the sum of individual edges in the original network. The label attribute in the second network represents the sector attribute in the first.
groupnet <- contract(g, as.integer(as.factor(V(g)$sector)), "ignore")
E(groupnet)$weight <- 1
groupnet <- simplify(groupnet, edge.attr.comb = list(weight = "sum"))
V(groupnet)$label <- levels(as.factor(V(g)$sector))
I would like to add another attribute to the second object V(groupnet)$groupsize that represents the number of original vertices that were contracted into groupnet. I have tried it with the following code but it did not work:
V(groupnet)$groupsize <- length(V(g)$sector[V(g)$sector == V(groupnet)$label])
How can I do this properly?
table() could be helpful here. Try out:
set.seed(1234)
library(igraph)
g <- make_ring(1000)
V(g)$sector <- factor(sample(LETTERS, 100, replace = T))
V(g)$sector
## contracted network
groupnet <- contract(g, as.integer(as.factor(V(g)$sector)), "ignore")
E(groupnet)$weight <- 1
V(groupnet)$label <- levels(as.factor(V(g)$sector))
## number of original vertices that were contracted into groupnet
# the tip is to see that table(V(g)$sector) provides the number of vertices per sector and
# its output is also arranged like V(groupnet)
table(V(g)$sector)
V(groupnet)
# solution
V(groupnet)$groupsize <- as.numeric(table(V(g)$sector))

cluster walktrap returns three communities, but when plotting they are all on top of each other, with no visible clustering

I've been following documentation tutorials and even lecture tutorials step by step. But for some reason the output of my plot is like this:
The output doesn't make any sense to me. There clearly is no structure, or communities in this current plot, as you can see that the bigger circles are all overlapping. Shouldn't this, in this case, return only a single community? Additionally the modularity of my network is ~0.02 which would again, suggest there is no community structure. But why does it return 3 communities?
this is my code: (exactly same as in documentation, with different dataset)
m <- data.matrix(df)
g <- graph_from_adjacency_matrix(m, mode = "undirected")
#el <- get.edgelist(g)
wc <- cluster_walktrap(g)
modularity(wc)
membership(wc)
plot(wc,g)
my data set looks is a 500x500 adjacency matrix in the form of a csv, with a 1-500 column and index names corresponding to a person.
I tried understanding the community class and using different types of variables for the plot, e.g. membership(wc)[2] etc. My thought is that the coloring is simply wrong, but nothing Ive tried so far seems to fix the issue.
You can have inter-community connections. You're working with a graph of 500 nodes and they can have multiple connections. There will be a large number of connections between nodes of different communities, but if you conduct a random walk you're most likely to traverse connections between nodes of the same community.
If you separate the communities in the plot (using #G5W's code (igraph) Grouped layout based on attribute) you can see the different groups.
set.seed(4321)
g <- sample_gnp(500, .25)
plot(g, vertex.label = '', vertex.size = 5)
wc <- cluster_walktrap(g)
V(g)$community <- membership(wc)
E(g)$weight = 1
g_grouped = g
for(i in unique(V(g)$community)){
groupV = which(V(g)$community == i)
g_grouped = add_edges(g_grouped, combn(groupV, 2), attr=list(weight = 2))
}
l <- layout_nicely(g_grouped)
plot( wc,g, layout = l, vertex.label = '', vertex.size = 5, edge.width = .1)
Red edges are intercommunity connections and black edges are intracommunity edges

Add missing mutual edges, while not changing attributes of existing mutual edges in R (igraph)

I have a directed graph, G. Some of the edges in G are reciprocal, and some are not. For reciprocal edges, edge attributes may be different. That is E(v1,v2)$att may not equal E(v2,v1)$att.
I need to fill in all missing reciprocal edges (that is, if E(v2,v1) does not exist while E(v1,v2) does, I want to create E(v2, v1) and copy all attribute information from E(v1, v2)).
If the reciprocal edge does exist, I need to keep the unique edge attribute information.
There are a lot of edges and a lot of attributes, so I am trying to avoid a loop here. Currently, where g1 is the directed but incomplete graph, I:
#make undirected with loops for reciprocal friendships
g2 <- as.undirected(g1, mode = c("each"))
#force everything to be directed, create new edges
g <- as.directed(g2, mode = c("mutual"))
#get rid of the double loops.
gnew <- simplify(g, remove.multiple = TRUE,
edge.attr.comb = "random")
The only problem with this is edge.attr.comb = "random" That is, I override the pre-existing mutual edge attribute information. I am thinking that I can flag missing mutual edges from g1and add the necessary edges (and copy their attribute information) using which_mutual but am having a difficult time with the indexing of edges. I must be missing an easy solution. An example:
g <- graph_from_literal(A+-+B, A-+C)
E(g)$att1 <- c(1,2,3)
#I want (note the default order of vertices for igraph)
g2 <- graph_from_literal(A+-+B, A+-+C)
E(g2)$att1 <- c(1, 2, 3, 2)
Figured it out. Perhaps not the most eloquent solution, but it works.
As an example,
g <- graph_from_literal(10-+40, 10-+30, 20+-+40)
E(g)$att1 <- c(1,2,3, 4)
E(g)$att2 <- c(10, 11, 12, 13)
######################################################################
test <- which((which_mutual(g) == FALSE))
head <- head_of(g,test)
tail <- tail_of(g,test)
combine <- matrix(c(head,tail), ncol = length(test), byrow = TRUE)
combineV <- as.vector(combine)
attributes <- list(att1 = E(g)$att1[test],att2 = E(g)$att2[test])
gnew <- add_edges(g,combineV, attr = attributes)

How to complete a graph assigning 0 as weight attribute of new edges

Please consider the following graph
library(igraph)
g <- erdos.renyi.game(100, 2/100)
E(g)$weight <- sample(1:10, ecount(g), replace=TRUE)
I am interested in "completing" the graph by adding all missing edges (as a result each pair of vertices will be connected by an edge) but making sure the new edges are assign E(g)$weight = 0.
Is it possible?
This should work.
olde = E(g) # saving edges
g[V(g), V(g)] <- TRUE # adding all possible edges
E(g)$weight <- 0 # all weights is 0
E(g)[olde]$weight <- olde$weight # old weights is equal to old weights
g <- simplify(g) # removing loops
According to the comments, I would like to suggest more robust answer that is based on the extra attribute of edges,
please see below and give comments.
ids = E(g) # saving old ids
E(g)$oldids = ids # assigning to specific edge as extra attribute
olde = E(g) # saving edges
g[V(g), V(g)] <- TRUE # adding all possible edges
E(g)$weight <- 0 # all weights is 0
# Now it is more robust, because it matches oldids with the ids of old graph
E(g)[match(ids, oldids)]$weight <- olde$weight[ids] # old weights is equal to old weights

Resources