1

I have a data.frame that has 4 columns (sender, receiver, year and value). I want to create a list which has for each year an adjacency matrix of the sender and the receiver containing the value.

A MVE would be

df = data.frame(sender = c("a","a","b","c","d","d","d","b","e","e"), 
                receiver = c("b","d","a","a","b","a","c","e","c","a"), 
                value = 1:10,
                year= c(2000,2000,2001,2002,2002,2002,2003,2003,2003,2004))

Also I have a country list I need it to match with

country_list = data.frame(country = c("a","b","c","d","e")

What I have tried looks like this. My problem is that not the correct values are shown in the subsequent adjacency matrix.

transfer_list <- list()

for (t in 2000:2004){
  
  matrix<-matrix(0,5,5)
  rownames(matrix)<-country_list[1:5,1]
  colnames(matrix)<-country_list[1:5,1]
  
  year=which(df[,4]==t)
  dyad=df[year,c(1,2)]
  
  for (i in 1:dim(dyad)[1]){
    
    partner1<-which(country_list[,1]==dyad[i,1])
    partner2<-which(country_list[,1]==dyad[i,2])
    
    matrix[partner1, partner2]<-df[i,3]
    
  }
  
  transfer_list[[t-1999]]=matrix
  
}

The result for 2004 should be a 10 for the transfer from e to a but is:

> transfer_list[[5]]
  a b c d e
a 0 0 0 0 0
b 0 0 0 0 0
c 0 0 0 0 0
d 0 0 0 0 0
e 1 0 0 0 0

What is my error?

ThomasIsCoding
  • 96,636
  • 9
  • 24
  • 81

3 Answers3

1

One approach might be the igraph package.

We can use igraph::graph_from_data_frame to create a graph for each year. We can include all of the possible vertices using the vertices = argument. Otherwise, only vertices with edges will be included.

Once we have created the weighted graph, we can use as_adj with attr = "value" to create the adjacency matrix with the values in the matrix. sparse = FALSE gets you 0s in the other positions.

library(igraph)

result <- lapply(unique(df$year), function(x) {
    g <- graph_from_data_frame(df[df$year == x,-4],
                               vertices = unique(country_list))
    as_adj(g, attr = "value", sparse = FALSE)})

names(result) <- unique(df$year)
result$`2004`
#   a b c d e
#a  0 0 0 0 0
#b  0 0 0 0 0
#c  0 0 0 0 0
#d  0 0 0 0 0
#e 10 0 0 0 0
Ian Campbell
  • 23,484
  • 14
  • 36
  • 57
1

You can try the code below

library(igraph)
library(dplyr)

lapply(
  split(df[setdiff(names(df), "year")], df$year),
  function(x) {
    x %>%
      graph_from_data_frame(vertices = country_list$country) %>%
      as_adj(attr = "value", sparse = FALSE)
  }
)

which gives

$`2000`
  a b c d e
a 0 1 0 2 0
b 0 0 0 0 0
c 0 0 0 0 0
d 0 0 0 0 0
e 0 0 0 0 0

$`2001`
  a b c d e
a 0 0 0 0 0
b 3 0 0 0 0
c 0 0 0 0 0
d 0 0 0 0 0
e 0 0 0 0 0

$`2002`
  a b c d e
a 0 0 0 0 0
b 0 0 0 0 0
c 4 0 0 0 0
d 6 5 0 0 0
e 0 0 0 0 0

$`2003`
  a b c d e
a 0 0 0 0 0
b 0 0 0 0 8
c 0 0 0 0 0
d 0 0 7 0 0
e 0 0 9 0 0

$`2004`
   a b c d e
a  0 0 0 0 0
b  0 0 0 0 0
c  0 0 0 0 0
d  0 0 0 0 0
e 10 0 0 0 0
ThomasIsCoding
  • 96,636
  • 9
  • 24
  • 81
  • 1
    @IanCampbThanks for feedback. Yes, you are right. I followed my habit with `set_edge_attr` but there is no need here. I updated my answer. – ThomasIsCoding Apr 19 '21 at 22:04
0

Change this section:

      dyad=df[year,c(1,2,3)]
      
      for (i in 1:dim(dyad)[1]){
        partner1<-which(country_list[,1]==dyad[i,1])
        partner2<-which(country_list[,1]==dyad[i,2])
        matrix[partner1, partner2]<- dyad[i,3]
        
      }
SmokeyShakers
  • 3,372
  • 1
  • 7
  • 18