|
1 | 1 | # data-raw/epigamesDiffNet.R |
2 | | -# Generating the dynamic diffnet object using netdiffuseR + collapse_timeframes() |
| 2 | +# Generating the daily diffnet object from epigames using collapse_timeframes() |
| 3 | +# Issue #75: Now includes vertex.dyn.attrs (mask, med, quarantine per day) |
| 4 | +# |
| 5 | +# Run after data-raw/epigames.R has built data/epigames.rda. |
3 | 6 |
|
4 | 7 | rm(list = ls()) |
5 | 8 | library(netdiffuseR) |
6 | 9 |
|
7 | | -# Load the base raw dataset created in data-raw/epigames.R (hourly resolution) |
| 10 | +# --------------------------------------------------------------------------- |
| 11 | +# 1. Load the base epigames dataset (with dynamic attrs) |
| 12 | +# --------------------------------------------------------------------------- |
8 | 13 | load("data/epigames.rda") |
9 | 14 |
|
10 | | -attrs <- epigames$attributes |
11 | | -edges <- epigames$edgelist |
| 15 | +attrs <- epigames$attributes # 594 x 6: id, toa, qyes_total, qno_total, mask_prop, med_prop |
| 16 | +edges <- epigames$edgelist # hourly edgelist: sender, receiver, time (0-338), weight |
| 17 | +dyn_long <- epigames$dyn_attrs # long format: id, hour (0-338), mask, med, quarantine |
12 | 18 |
|
13 | | -# Collapse hourly edgelist (hours 0-338) into daily windows (days 1-15) |
14 | | -source("R/collapse_timeframes.R") |
| 19 | +# --------------------------------------------------------------------------- |
| 20 | +# 2. Collapse hourly edgelist into 15 daily windows via collapse_timeframes() |
| 21 | +# --------------------------------------------------------------------------- |
| 22 | +WINDOW_SIZE <- 24 # hours per day |
| 23 | +N_DAYS <- 15 |
15 | 24 |
|
16 | 25 | daily_edgelist <- collapse_timeframes( |
17 | | - edgelist = edges, |
18 | | - ego = "sender", |
19 | | - alter = "receiver", |
20 | | - timevar = "time", |
21 | | - weightvar = "weight", |
22 | | - window_size = 24, |
23 | | - binarize = TRUE, |
24 | | - cumulative = TRUE, |
25 | | - symmetric = TRUE |
| 26 | + edgelist = edges, |
| 27 | + ego = "sender", |
| 28 | + alter = "receiver", |
| 29 | + timevar = "time", |
| 30 | + weightvar = "weight", |
| 31 | + window_size = WINDOW_SIZE, |
| 32 | + binarize = TRUE, |
| 33 | + cumulative = TRUE, |
| 34 | + symmetric = TRUE |
26 | 35 | ) |
27 | 36 |
|
28 | | -# Build daily adjacency matrices |
| 37 | +cat("Daily edgelist: ", nrow(daily_edgelist), "rows, time range:", |
| 38 | + range(daily_edgelist$time), "\n") |
| 39 | + |
| 40 | +# Build adjacency matrices |
29 | 41 | adjmat <- edgelist_to_adjmat( |
30 | 42 | daily_edgelist[, c("sender", "receiver")], |
31 | | - w = daily_edgelist$weight, |
32 | | - t0 = daily_edgelist$time, |
| 43 | + w = daily_edgelist$weight, |
| 44 | + t0 = daily_edgelist$time, |
33 | 45 | keep.isolates = TRUE, |
34 | 46 | multiple = TRUE |
35 | 47 | ) |
36 | 48 |
|
37 | | -max_t <- max(daily_edgelist$time, na.rm = TRUE) |
| 49 | +# --------------------------------------------------------------------------- |
| 50 | +# 3. Build vertex.dyn.attrs: one data.frame per day (15 total) |
| 51 | +# Each data.frame: 594 rows, columns: mask, med, quarantine (daily means) |
| 52 | +# --------------------------------------------------------------------------- |
| 53 | +# Map hourly data to day index (day d = hours [(d-1)*24 .. d*24-1]) |
| 54 | +dyn_long$day <- (dyn_long$hour %/% WINDOW_SIZE) + 1 # 1-based day |
| 55 | +dyn_long$day <- pmin(dyn_long$day, N_DAYS) # clamp hour 336-338 to day 15 |
| 56 | + |
| 57 | +vertex_dyn <- lapply(1:N_DAYS, function(d) { |
| 58 | + sub <- dyn_long[dyn_long$day == d, ] |
| 59 | + |
| 60 | + # Aggregate per node: mean within each 24-hour window |
| 61 | + # (proportion of hours in that day where behavior was active) |
| 62 | + agg <- aggregate( |
| 63 | + cbind(mask, med, quarantine) ~ id, |
| 64 | + data = sub, |
| 65 | + FUN = mean |
| 66 | + ) |
| 67 | + |
| 68 | + # Sort by id to match the node ordering in the diffnet object |
| 69 | + agg <- agg[order(agg$id), ] |
| 70 | + rownames(agg) <- NULL |
| 71 | + |
| 72 | + # Return only the behavior columns (not id — diffnet uses position) |
| 73 | + agg[, c("mask", "med", "quarantine")] |
| 74 | +}) |
| 75 | + |
| 76 | +# Sanity check: each element should be 594 rows x 3 cols |
| 77 | +stopifnot(all(sapply(vertex_dyn, nrow) == 594)) |
| 78 | +stopifnot(all(sapply(vertex_dyn, ncol) == 3)) |
| 79 | + |
| 80 | +cat("vertex.dyn.attrs built: ", N_DAYS, "data.frames of", |
| 81 | + nrow(vertex_dyn[[1]]), "rows x", ncol(vertex_dyn[[1]]), "cols\n") |
| 82 | +cat(" Day 1 — mean mask usage:", round(mean(vertex_dyn[[1]]$mask), 3), |
| 83 | + " mean quarantine:", round(mean(vertex_dyn[[1]]$quarantine), 3), "\n") |
| 84 | +cat(" Day 15 — mean mask usage:", round(mean(vertex_dyn[[15]]$mask), 3), |
| 85 | + " mean quarantine:", round(mean(vertex_dyn[[15]]$quarantine), 3), "\n") |
38 | 86 |
|
39 | | -# Prepare TOA vector: real adoption times from attrs, NA for non-adopters |
| 87 | +# --------------------------------------------------------------------------- |
| 88 | +# 4. Prepare TOA vector |
| 89 | +# --------------------------------------------------------------------------- |
40 | 90 | toa_vec <- stats::setNames(attrs$toa, as.character(attrs$id)) |
41 | 91 |
|
| 92 | +# --------------------------------------------------------------------------- |
| 93 | +# 5. Assemble diffnet object |
| 94 | +# --------------------------------------------------------------------------- |
42 | 95 | epigamesDiffNet <- as_diffnet( |
43 | 96 | adjmat, |
44 | 97 | toa = toa_vec, |
45 | 98 | vertex.static.attrs = attrs, |
| 99 | + vertex.dyn.attrs = vertex_dyn, |
46 | 100 | t0 = 1, |
47 | | - t1 = max_t |
| 101 | + t1 = N_DAYS |
48 | 102 | ) |
49 | 103 |
|
| 104 | +cat("\nepigamesDiffNet summary:\n") |
| 105 | +print(epigamesDiffNet) |
| 106 | + |
| 107 | +# --------------------------------------------------------------------------- |
| 108 | +# 6. Quick validation: dynamic exposure vs static exposure |
| 109 | +# --------------------------------------------------------------------------- |
| 110 | +cat("\nValidating exposure() with dynamic mask attrs...\n") |
| 111 | +expo_static <- exposure( |
| 112 | + epigamesDiffNet, |
| 113 | + attrs = matrix( |
| 114 | + rep(epigamesDiffNet$vertex.static.attrs$mask_prop, N_DAYS), |
| 115 | + nrow = 594, ncol = N_DAYS |
| 116 | + ) |
| 117 | +) |
| 118 | +expo_dynamic <- exposure(epigamesDiffNet, attrs = "mask") |
| 119 | + |
| 120 | +cor_val <- cor(as.vector(expo_static), as.vector(expo_dynamic), use = "complete.obs") |
| 121 | +cat(" Correlation static vs dynamic mask exposure:", round(cor_val, 4), "\n") |
| 122 | +cat(" (Should be < 1.0, confirming dynamic attrs add new information)\n") |
| 123 | + |
| 124 | +# --------------------------------------------------------------------------- |
| 125 | +# 7. Save |
| 126 | +# --------------------------------------------------------------------------- |
50 | 127 | usethis::use_data(epigamesDiffNet, overwrite = TRUE, compress = "xz") |
| 128 | +cat("\nSaved: data/epigamesDiffNet.rda\n") |
0 commit comments