Following this answer, I ended up doing a graph decomposition on the forest, then finding which vertices had an out-degree equal to 0, thus determining the root node for each tree (doing the same for in-degree yields which vertices are terminal, although I realized I didn't need this information -- as a result I'm not marking this as the answer).
library(igraph)
library(dplyr)
df <- data.frame(id = 1:8, parent = c(NA, NA, 1, 1, 3, 4, NA, 7))
edgelist_df <- na.omit(df)
g <- graph_from_data_frame(edgelist_df)
tree_to_df <- function(graph, forest_edgelist){
# for a directed tree, find its root and assign that root to every
# node in the tree's edgelist
# `dplyr::filter` fails on the subset below, so we use base R
tree_dat <- forest_edgelist[forest_edgelist$id %in% V(graph)$name,]
root <- which(degree(graph, v = V(graph), mode = 'out') == 0, useNames = T)
tree_dat$root <- names(root)
return(tree_dat)
}
root_dat <-
decompose.graph %>% # find connected subgraphs
lapply(tree_to_df, forest_edgelist = edgelist_df) %>%
bind_rows