How to remove children of children in data frame to plot network in R?

Viewed 94

I want to plot a network with R. The problem, however, is that my data frame, which contains the relationship data, also contains children of children. It looks like the following:

parent <- c("A","A","A","B","B","E")
child <-  c("B","C","D","C","D","D")
df <- data.frame(parent,child)

I would like to remove the children of children in df so that I can use igraph to plot my network. So basically, I want my data to look like df_net:

parent <- c("A","B","B","E")
child <-  c("B","C","D","D")
df_net <- data.frame(parent,child)
net <- graph_from_data_frame(df_net,directed = T)
plot(net)

Figure of plot(net)

What is the best way to (automatically) remove the unnecessary rows of df? (I have several data frames with up to 100 rows - removing the rows by hand is therefore not an option.)

My first idea was to use a while loop to find the parents in each hierarchical step. I thought I could us this to filter the rows in df. But I don't think I'm on the right track here. Any ideas are appreciated!

`%notin%` <- Negate(`%in%`)
i <- nrow(df)
y <- list()
z <- list()
j <- 1
while (i > 0) {
  v <- unique(df$parent[!(df$parent %in% df$child)]) # find mismatch (only in parent, not in child)
  df <- df %>% filter(parent %notin% v)
  print(v)
  y[[j]] <- v
  z[[j]] <- df
  i = nrow(df)
  j = j+1
}
2 Answers

How about using igraph to determine the paths between individuals, and if there are more than 1, remove that connection?

library(igraph)
parent <- c("A","A","A","B","B","E")
child <-  c("B","C","D","C","D","D")
df <- data.frame(parent,child)
net <- graph_from_data_frame(df,directed = T)
df <- df[apply(df,1,function(x){length(all_simple_paths(net,x[1],x[2]))}) == 1,]
df
  parent child
1      A     B
4      B     C
5      B     D
6      E     D

I fear this may be pretty slow on extremely large graphs, so if anyone has a data.table solution, that might be better.

This is a dplyr solution:

library(dplyr)

# get data
parent <- c("A","A","A","B","B","E")
child <-  c("B","C","D","C","D","D")
df <- data.frame(parent,child, stringsAsFactors = FALSE)

# remove rows that are not directly related
new_df <- anti_join(df,
          left_join(df,df,by=c("child"="parent")) %>% 
  select(parent,child=child.y) %>% 
  na.omit()) 

new_df
  parent child
1      A     B
2      B     C
3      B     D
4      E     D
Related