2017-10-27 4 views
4

Ich habe Daten auf jeder Interaktion, die konnte und an einer Universität Club wöchentliche soziale Stunde passieren hatZeit variierenden Netzwerk in r

Eine Probe meiner Daten wird wie folgt

structure(list(from = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 2L, 
2L, 2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L, 3L, 3L), .Label = c("A", 
"B", "C"), class = "factor"), to = structure(c(2L, 3L, 2L, 3L, 
2L, 3L, 1L, 3L, 1L, 3L, 1L, 3L, 1L, 2L, 1L, 2L, 1L, 2L), .Label = c("A", 
"B", "C"), class = "factor"), timestalked = c(0L, 1L, 0L, 4L, 
1L, 2L, 0L, 1L, 0L, 2L, 1L, 0L, 1L, 2L, 1L, 0L, 0L, 0L), week = structure(c(1L, 
1L, 3L, 3L, 2L, 2L, 1L, 1L, 3L, 3L, 2L, 2L, 1L, 1L, 3L, 3L, 2L, 
2L), .Label = c("1/1/2010", "1/15/2010", "1/8/2010"), class = "factor")), .Names = c("from", 
"to", "timestalked", "week"), class = "data.frame", row.names = c(NA, 
-18L)) 

Ich versuche, zu berechnen Netzwerkstatistiken wie die Zentralität für A, B, C für jede einzelne Woche, die letzten zwei Wochen und seit Jahresbeginn. Die einzige Möglichkeit, dies zu erreichen, besteht darin, die Datei in der Zeiteinheit, die ich analysieren möchte, manuell aufzulösen, aber ich hoffe, dass es eine weniger mühsame Methode geben muss.

Wenn timestalked 0 ist dies sollte als keine Kante behandelt werden

Der Ausgang ein .csv mit folgendem erzeugt:

actor cent_week1 cent_week2 cent_week3 cent_last2weeks cent_yeartodate 
A  
B 
C 

mit cent_week1 wobei 1/1/2010 Zentralität; cent_last2weeks nur in Anbetracht 1/8/2010 und 1/15/2010; und cent_yeartodate werden alle Daten gleichzeitig berücksichtigt. Dies wird auf einen viel größeren Datensatz von Millionen von Beobachtungen angewendet.

+0

Beitrag, was Sie bisher versucht, das nicht funktioniert hat, und kopieren und die Ausgabe von 'dput (my_data) fügen Sie' statt, wie Sie es jetzt formatiert haben. – useR

+0

@useR Ich habe Tage damit verbracht, im Web zu suchen und Tutorials zu betrachten, ohne Glück. Ich griff auf die csv-Intro manuell Hunderte von Subdateien mit C++ brechen. Ich habe dann die benötigte Analyse durchgeführt. Es ist also alles getan, aber für den Abschluss denke ich, dass dies ein wichtiges Thema ist, auf das man sich konzentrieren muss. Ich verstehe, wenn niemand in der Gemeinde weiß, wie es geht. – CJ12

+0

Ich glaube nicht, dass diese Frage zu schwierig ist. Ich bin sicher, dass jemand es lösen kann. So haben Sie Ihre Daten formatiert, die es den Leuten schwer machen zu arbeiten (lesen Sie hierzu https://stackoverflow.com/a/5963610/5150629). Wenn Sie hilfreiche Antworten erhalten möchten, veröffentlichen Sie zumindest die Daten, mit denen die Leute arbeiten können, indem Sie die Ausgabe von 'dput (my_data)' kopieren und einfügen, und geben Sie an, wie die endgültige Ausgabe aussehen soll. – useR

Antwort

1

kann dies tun, indem Sie Ihre Fenster in einem anderen Tabelleneinstellung, dann durch Gruppenoperationen auf jedem der Fenster tun:

Datenaufbereitung:

# Load Data 
DT <- structure(list(from = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 2L, 
2L, 2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L, 3L, 3L), .Label = c("A", 
"B", "C"), class = "factor"), to = structure(c(2L, 3L, 2L, 3L, 
2L, 3L, 1L, 3L, 1L, 3L, 1L, 3L, 1L, 2L, 1L, 2L, 1L, 2L), .Label = c("A", 
"B", "C"), class = "factor"), timestalked = c(0L, 1L, 0L, 4L, 
1L, 2L, 0L, 1L, 0L, 2L, 1L, 0L, 1L, 2L, 1L, 0L, 0L, 0L), week = structure(c(1L, 
1L, 3L, 3L, 2L, 2L, 1L, 1L, 3L, 3L, 2L, 2L, 1L, 1L, 3L, 3L, 2L, 
2L), .Label = c("1/1/2010", "1/15/2010", "1/8/2010"), class = "factor")), .Names = c("from", 
"to", "timestalked", "week"), class = "data.frame", row.names = c(NA, 
-18L)) 

# Code 
library(igraph) 
library(data.table) 

setDT(DT) 

# setup events 
DT <- DT[timestalked > 0] 
DT[, week := as.Date(week, format = "%m/%d/%Y")] 

# setup windows, edit as needed 
date_ranges <- data.table(label = c("cent_week_1","cent_week_2","cent_last2weeks","cent_yeartodate"), 
          week_from = as.Date(c("2010-01-01","2010-01-08","2010-01-08","2010-01-01")), 
          week_to = as.Date(c("2010-01-01","2010-01-08","2010-01-15","2010-01-15")) 
) 

# find all events within windows 
DT[, JA := 1] 
date_ranges[, JA := 1] 
graph_base <- merge(DT, date_ranges, by = "JA", allow.cartesian = TRUE)[week >= week_from & week <= week_to] 

Hier ist jetzt die von Gruppencode, der zweite Linie ist ein bisschen grob, offen für Ideen, wie das Doppel Anruf

graph_base <- graph_base[, .(graphs = list(graph_from_data_frame(.SD))), by = label, .SDcols = c("from", "to", "timestalked")] # create graphs 
graph_base <- graph_base[, .(vertex = names(eigen_centrality(graphs[[1]])$vector), ec = eigen_centrality(graphs[[1]])$vector), by = label] # calculate centrality 

dcast für die endgültige Formatierung zu vermeiden:

dcast(graph_base, vertex ~ label, value.var = "ec") 
    vertex cent_last2weeks cent_week_1 cent_week_2 cent_yeartodate 
1:  A  1.0000000 0.7071068 0.8944272  0.9397362 
2:  B  0.7052723 0.7071068 0.4472136  0.7134685 
3:  C  0.9008487 1.0000000 1.0000000  1.0000000 
+0

das ist super. (1) Ich habe gedacht, dass die beste Ausgabe würde Spalten wäre 'Vertex'Datum' 'cent_this_week'' cent_last_two_Weeks' und 'cent_yeartodate' Dies würde den Code tragbarer machen und ich wäre Ihnen dankbar, wenn Sie einen Weg zur Umsetzung wüssten diese Ausgabe in einer solchen Form. (2) Ist es möglich, den 'dcast' in '.csv' im 'wd' auszugeben? Ich habe mich in der letzten Stunde mit wenig bis keinem Fortschritt für mich selbst bemüht. Danke – CJ12

+0

Auch das reale Dataset hat Tausende von Daten, so dass sie nicht von Hand eingegeben werden müssen – CJ12

+0

@ CJ12 (1) Ich bin mir nicht sicher, wie man Datum in Ihre Ausgabe einbaut, da die Spaltendefinitionen bestimmte Datumsbereiche sind. Was bedeutet Datum in diesem Fall? (2) benutze 'write.csv()', es funktioniert mit dem dcasted Wert (3) Du kannst diese Tabelle wahrscheinlich programmatisch aus deinen Daten generieren - was hast du bisher versucht? – Chris

1

Kann nicht kommentieren, also schreibe ich eine "Antwort". Wenn Sie einige mathematische Operation auf timestalked auszuführen und Werte zu erhalten, indem die from (keine Variable gefunden actor in Ihrem Beispiel genannt), ist hier ein data.table Ansatz, das hilfreich sein kann:

dat <- as.data.table(dat) # or add 'data.table' to the class parameter 
dat$week <- as.Date(dat$week, format = "%m/%d/%Y") 
dat[, .(cent = mean(timestalked)), by = list(from, weeknum = week(week))] 

Dies gibt die unten Ausgang:

dat [(Cent = Mittelwert (timestalked)), durch list = (ab, WEEKNUM = Woche (Woche)).]

from weeknum cent 
1: A  1 0.5 
2: A  2 2.0 
3: A  3 1.5 
4: B  1 0.5 
5: B  2 1.0 
6: B  3 0.5 
7: C  1 1.5 
8: C  2 0.5 
9: C  3 0.0 

Weisen Sie dies new_dat zu. Sie können nach der Woche einfach mit new_dat[weeknum %in% 2:3] oder was auch immer andere Variation Sie wollen oder sum im Laufe des Jahres. Zusätzlich können Sie auch sortieren/bestellen wie gewünscht.

Hoffe, das hilft!

1

Wie wäre:

library(dplyr) 
centralities <- tmp  %>% 
    group_by(week)   %>% 
    filter(timestalked > 0) %>% 
    do(
    week_graph=igraph::graph_from_edgelist(as.matrix(cbind(.$from, .$to))) 
)      %>% 
    do(
    ecs = igraph::eigen_centrality(.$week_graph)$vector 
)      %>% 
    summarise(ecs_A = ecs[[1]], ecs_B = ecs[[2]], ecs_C = ecs[[3]]) 

Sie summarise_all verwenden können, wenn Sie eine Menge Schauspieler haben. Es in ein langes Format zu setzen, bleibt als Übung übrig.

+0

@ dah2 Loading im Dataset aus der Frage erzeugen, erhalte ich den folgenden Fehler mit Ihrem Code: 'Fehler in eval (lhs, Eltern, Eltern): Objekt 'tmp' nicht gefunden – CJ12

+0

Offensichtlich müssen Sie die 'Struktur' in Ihre Frage in das Objekt' tmp' laden. – dash2

+0

Offensichtlich erwartete ich eine vollständige Antwort mit den gelieferten Daten. Das ist in Ordnung, wenn Sie die Ausgabe wie in der Frage beschrieben erstellen können, bin ich glücklich, sie zu akzeptieren – CJ12

0

Diese Analyse folgt dem allgemeinen Split-Apply-Combine-Ansatz, bei dem die Daten nach Woche geteilt, Graphfunktionen angewendet und anschließend die Ergebnisse kombiniert werden. Dafür gibt es mehrere Tools, aber unten verwendet Base R und data.table.

Base-R

erster Satz Daten-Klasse für Ihre Daten, so dass Begriff der letzten zwei Wochen Bedeutung hat.

# Set date class and order 
d$week <- as.Date(d$week, format="%m/%d/%Y") 
d <- d[order(d$week), ] 
d <- d[d$timestalked > 0, ] # remove edges // dont need to do this is using weights 

Dann Split und Grafik anwenden Funktionen

# split data and form graph for eack week 
g1 <- lapply(split(seq(nrow(d)), d$week), function(i) 
                graph_from_data_frame(d[i,])) 
# you can then run graph functions to extract specific measures 
(grps <- sapply(g1, function(x) eigen_centrality(x, 
              weights = E(x)$timestalked)$vector)) 

# 2010-01-01 2010-01-08 2010-01-15 
# A 0.5547002 0.9284767 1.0000000 
# B 0.8320503 0.3713907 0.7071068 
# C 1.0000000 1.0000000 0.7071068 

# Aside: If you only have one function to run on the graphs, 
# you could do this in one step 
# 
# sapply(split(seq(nrow(d)), d$week), function(i) { 
#    x = graph_from_data_frame(d[i,]) 
#    eigen_centrality(x, weights = E(x)$timestalked)$vector 
#   }) 

Sie dann in der Analyse auf alle Daten kombinieren müssen - wie Sie nur zwei weitere Diagramme bauen müssen, ist dies nicht der zeit- Teil verbrauchen.

fun1 <- function(i, name) { 
      x = graph_from_data_frame(i) 
      d = data.frame(eigen_centrality(x, weights = E(x)$timestalked)$vector) 
      setNames(d, name) 
    } 


a = fun1(d, "alldata") 
lt = fun1(d[d$week %in% tail(unique(d$week), 2), ], "lasttwo") 

# Combine: could use `cbind` in this example, but perhaps `merge` is 
# safer if there are different levels between dates 
data.frame(grps, lt, a) # or 
Reduce(merge, lapply(list(grps, a, lt), function(x) data.frame(x, nms = row.names(x)))) 

# nms X2010.01.01 X2010.01.08 X2010.01.15 alldata lasttwo 
# 1 A 0.5547002 0.9284767 1.0000000 0.909899  1.0 
# 2 B 0.8320503 0.3713907 0.7071068 0.607475  0.5 
# 3 C 1.0000000 1.0000000 0.7071068 1.000000  1.0 

data.table

Es ist wahrscheinlich, dass der zeitaufwendige Schritt ausdrücklich geteilt ausübe wird die Funktion über die Daten. data.table sollte hier einige Vorteile bieten, besonders wenn die Daten groß werden und/oder es mehr Gruppen gibt.

# function to apply to graph 
fun <- function(d) { 
    x = graph_from_data_frame(d) 
    e = eigen_centrality(x, weights = E(x)$timestalked)$vector 
    list(e, names(e)) 
} 

library(data.table) 
dcast(
    setDT(d)[, fun(.SD), by=week], # apply function - returns data in long format 
    V2 ~ week, value.var = "V1") # convert to wide format 

# V2 2010-01-01 2010-01-08 2010-01-15 
# 1: A 0.5547002 0.9284767 1.0000000 
# 2: B 0.8320503 0.3713907 0.7071068 
# 3: C 1.0000000 1.0000000 0.7071068 

Dann führen Sie einfach die Funktion über die gesamten Daten/letzten zwei Wochen wie zuvor.

Es gibt Unterschiede zwischen den Antworten, die darauf zurückzuführen sind, wie wir das Argument weights bei der Berechnung der Zentralität verwenden, während die anderen die Gewichte nicht verwenden.


d=structure(list(from = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 2L, 
2L, 2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L, 3L, 3L), .Label = c("A", 
"B", "C"), class = "factor"), to = structure(c(2L, 3L, 2L, 3L, 
2L, 3L, 1L, 3L, 1L, 3L, 1L, 3L, 1L, 2L, 1L, 2L, 1L, 2L), .Label = c("A", 
"B", "C"), class = "factor"), timestalked = c(0L, 1L, 0L, 4L, 
1L, 2L, 0L, 1L, 0L, 2L, 1L, 0L, 1L, 2L, 1L, 0L, 0L, 0L), week = structure(c(1L, 
1L, 3L, 3L, 2L, 2L, 1L, 1L, 3L, 3L, 2L, 2L, 1L, 1L, 3L, 3L, 2L, 
2L), .Label = c("1/1/2010", "1/15/2010", "1/8/2010"), class = "factor")), .Names = c("from", 
"to", "timestalked", "week"), class = "data.frame", row.names = c(NA, 
-18L))