2017-11-11 1 views
2

Ich möchte eine Funktion "f" in R erstellen, die in einem data.frame von Kanten zwischen Individuen und einer Person (genannt A2 zum Beispiel) und die zurückgibt ein weiterer Datenrahmen mit nur "Vorfahren" und "Kindern" von A2 und auch Vorfahren von Vorfahren und Kindern von Kindern!Funktion in R, die Vorfahren und Kinder in einem Netzwerk zurückgibt

Zu meiner komplizierten Frage veranschaulichen:

library(visNetwork) 
nodes <- data.frame(id = c(paste0("A",1:5),paste0("B",1:3)), 
       label = c(paste0("A",1:5),paste0("B",1:3))) 
edges <- data.frame(from = c("A1","A1","A2","A3","A4","B1","B2"), 
       to = c("A2","A3","A4","A4","A5","B3","B3")) 
visNetwork(nodes, edges) %>% 
    visNodes(font = list(size=45)) %>% 
    visHierarchicalLayout(direction = "LR", levelSeparation = 500) 

enter image description here

In diesem Beispiel enthält die data.frame 2 verschiedene unabhängige Netzwerke: 1 Netzwerk mit "A" s und einem anderen mit "B" s .

Ich möchte eine Funktion f (data = Kanten, indiv = "A2") implementieren, die eine data.frame kehrt die alle Zeilen data.frame Kanten mit dem Netz von "A" s betroffenen enthält:

f (Kanten, „A2“) zurückkehren würde dieser Extrakt von data.frame

head(f(edges,"A2")) 
# from to 
#1 A1 A2 
#2 A1 A3 
#3 A2 A4 
#4 A3 A4 
#5 A4 A5 

Kanten ich hoffe, es ist klar genug für Sie, mir zu helfen.

Vielen Dank!

+0

Was haben Sie versucht? Was ist der Algorithmus, den Sie implementieren möchten? –

+0

Nicht sicher, genau zu verstehen, was Sie wollen, aber das Ziel ist in der Tat, für jeden einzelnen seine Vorfahren und Kinder und die Kinder ihrer Kinder und Vorfahren der Vorfahren zurückzukehren. Und bevor ich Zeit (sicherlich Stunden) damit verbrachte, Code zu schreiben, wollte ich wissen, ob es eine wohlbekannte Funktion/ein Paket dafür gibt, weil es mir scheint, dass es eine ziemlich einfache Frage für Leute (im Gegensatz zu mir) sein könnte arbeite mit Netzwerken. Aber ich habe im Internet noch nichts befriedigendes gefunden (nur für Bäume), also wollte ich noch mehr Spezialisten fragen! Danke – antuki

+0

Ich bin kein Grafik-Analyst, aber vielleicht könnte dies helfen: http://igraph.org/r/doc/components.html – romles

Antwort

1

Ich habe einen einfachen Algorithmus geschrieben, um die ganze Familie zu finden, die mit einer Person verbunden ist (und ich bin mir sicher, dass sie verbessert werden kann). Wie @romles vorgeschlagen hat, können Sie das gleiche mit einigen R-Paketen wie igraph machen. In diesem Fall scheint meine Funktion jedoch etwas leistungsfähiger zu sein als die Option "igraph".

edges <- data.frame(from = c("A1","A1","A2","A3","A4","B1","B2"), 
        to = c("A2","A3","A4","A4","A5","B3","B3"), 
        stringsAsFactors = FALSE) 
f <- function(data, indiv){ 
    children_ancestors <- function(indiv){ 
     # Find children and ancestors of an indiv 
     c(data[data[,"from"]==indiv,"to"],data[data[,"to"]==indiv,"from"]) 
    } 
    family <- indiv 
    new_people <- children_ancestors(indiv) # New people to inspect 
    while(length(diff_new_p <- setdiff(new_people,family)) > 0){ 
     # if the new people aren't yet in the family : 
     family <- c(family, diff_new_p) 
     new_people <- unlist(sapply(diff_new_p, children_ancestors)) 
     new_people <- unique(new_people) 
    } 
    data[(data[,1] %in% family) | (data[,2] %in% family),] 
} 

f(edges, "A2") gibt das erwartete Ergebnis. Vergleicht man mit der Grafikfunktion:

library(igraph) 
library(microbenchmark) 
edges2 <- graph_from_data_frame(edges, directed = FALSE) 
microbenchmark(simple_function = f(edges,"A2"), 
       igraph_option = as_data_frame(subgraph.edges(edges2, subcomponent(edges2, 'A2', 'in'))) 
       ) 
#Unit: microseconds 
#   expr  min  lq  mean median  uq  max neval 
# simple_function 874.411 968.323 1206.037 1123.515 1325.075 2957.931 100 
# igraph_option 1239.896 1451.364 1802.341 1721.227 1984.380 3907.089 100 
+0

Vielen Dank an Sie drei für Ihre Antworten, alles sehr nützlich, um den Algorithmus zu verstehen, den ich brauche und das igraph-Paket. Ich werde Zeit nehmen, um alle Lösungen zu verstehen, die du angeboten hast! – antuki

1

Dies funktioniert für mich:

library(igraph) 
g <- graph_from_literal(A1--A2, A1--A3, A2--A4, A3--A4, A4--A5, B1--B3, B2--B3) 
sg_a2 <- subcomponent(g, 'A2', 'in') 
as_data_frame(subgraph.edges(g, sg_a2)) 

Es gibt:

# from to 
#1 A1 A2 
#2 A1 A3 
#3 A2 A4 
#4 A3 A4 
#5 A4 A5 
+0

Vielen Dank an Sie drei für Ihre Antworten, alle sehr nützlich, um den Algorithmus zu verstehen Ich brauche und das igraph-Paket. Ich werde Zeit nehmen, um alle Lösungen zu verstehen, die du angeboten hast! – antuki

2

Sie könnten versuchen, und nur die Knoten filtern, die auf A2 verbunden sind (dh Abstand zu Inf nicht gleich

library(tidygraph) 
edges <- data.frame(from = c("A1","A1","A2","A3","A4","B1","B2"), 
        to = c("A2","A3","A4","A4","A5","B3","B3")) 
as_tbl_graph(edges) %>% 
    filter(is.finite(node_distance_to(name=="A2", mode="all"))) 

was gibt

# A tbl_graph: 5 nodes and 5 edges 
# 
# A directed acyclic simple graph with 1 component 
# 
# Node Data: 5 x 1 (active) 
    name 
    <chr> 
1 A1 
2 A2 
3 A3 
4 A4 
5 A5 
# 
# Edge Data: 5 x 2 
    from to 
    <int> <int> 
1  1  2 
2  1  3 
3  2  4 
# ... with 2 more rows 
+0

Vielen Dank an Sie drei für Ihre Antworten, alles sehr nützlich, um den Algorithmus zu verstehen, den ich brauche und das igraph-Paket. Ich werde Zeit nehmen, um alle Lösungen zu verstehen, die du angeboten hast! – antuki

Verwandte Themen