leifeld / btergm

Temporal Exponential Random Graph Models by Bootstrapped Pseudolikelihood
16 stars 10 forks source link

Problem with bipartite network where one of the modes has a single vertex. #29

Closed greg-fauerbach closed 2 years ago

greg-fauerbach commented 2 years ago

Hello,

I'm getting an error when I try to call btergm() on a list of two-mode networks where one of the modes has a single vertex.

The error I get is:

Error in nr[j] != nr.net[j] : 
  comparison of these types is not implemented

I'm almost certain the problem is occurring because R is converting each one-row sociomatrix into a numeric vector, which causes tergmprepare() to fail. When I call btergm() on a list of one-mode networks (whose sociomatrices have multiple rows and columns) it works fine.

Here's example code that reproduces the error.

node_vars <- data.frame(
        name = c("Actor 1", "Actor 1", "Actor 2", "Actor 2", "Actor 3", "Actor 3"),
        var1 = c("A", "A", "A", "A", "A", "B"),
        year = c(2000, 2001, 2000, 2001, 2000, 2001),
        type = c(TRUE, TRUE, FALSE, FALSE, FALSE, FALSE)
      )

        node_var_list <- node_vars %>%
          group_by(year) %>%
          group_split()

      edge_vars <- data.frame(
        name1 = c("Actor 1", "Actor 1", "Actor 1"),
        name2 = c("Actor 2", "Actor 2", "Actor 3"),
        year = c(2000, 2001, 2000)
      )

        edge_var_list <- edge_vars %>%
          group_by(year) %>%
          group_split()

      # Create bipartite networks
      test_net1_bp <- as.network(x = edge_var_list[[1]], vertices = node_var_list[[1]],
                             directed = FALSE, bipartite = TRUE, bipartite_col = "type")

      test_net2_bp <- as.network(x = edge_var_list[[2]], vertices = node_var_list[[2]],
                              directed = FALSE, bipartite = TRUE, bipartite_col = "type")

      test_nets_bp <- list(test_net1_bp, test_net2_bp)

      tergmprepare(test_nets_bp[1:2] ~ edges + b1nodematch("var1") ) # It doesn't work

      # Create one-mode networks
      test_net1 <- as.network(x = edge_var_list[[1]], vertices = node_var_list[[1]],
                                 directed = FALSE, bipartite = FALSE)

      test_net2 <- as.network(x = edge_var_list[[2]], vertices = node_var_list[[2]],
                                 directed = FALSE, bipartite = FALSE)

      test_nets <- list(test_net1, test_net2)

      tergmprepare(test_nets[1:2] ~ edges + nodematch("var1")) # It works

Do you have any suggestions for how to solve this issue?

Thank you.

leifeld commented 2 years ago

Thanks for reporting this issue.

Indeed, the problem occurs here. The list of networks is converted there into a list of matrices using as.matrix from the network package, and then nrow checks the number of rows of each matrix.

The problem seems to be that as.matrix does not actually return a matrix. We can verify this using your example:

class(as.matrix(test_net1_bp))

returns numeric instead of matrix, and

dim(as.matrix(test_net1_bp))

returns NULL.

My interpretation is that the as.matrix.network.adjacency function in the network package should, but doesn't, return a matrix (though I am not sure if this is the right one, given that you provided an edge list to begin with). So I'd play with the code there and see what you need to change in that function (or perhaps the other functions in that file) to get the desired effect of as.matrix with your network object. Perhaps worth reporting there as well as a potential bug that may need to be reviewed. Not sure what the problem is exactly, but my intuition tells me that if a function is called as.matrix and it doesn't return a matrix, something must be wrong.

That said, I have to admit that I did not pay particular attention to edge lists and their difficulties when I wrote btergm and tergmprepare. So my general advice would be to use bipartite matrices when dealing with data for TERGMs. They should have n rows and m columns, where n is the number of actors and m is the number of events. This is how I would approach the problem. Let me know if you do this and there is still some issue. Admittedly, support for bipartite networks was not tested very thoroughly, but it should work. If you do have a minimal and self-contained example for that usage scenario, I would be glad if you could post it here because I could use it as a unit test in order to ensure that future changes don't break the bipartite example. Thanks.

leifeld commented 2 years ago

I'll close the issue here and defer to the issue in the network package I referenced above.

leifeld commented 2 years ago

Should be fixed in https://github.com/statnet/network/commit/27c88579a799d5ae8dfd72980b5b00dc012e5a09.