exposure: Ego exposure

View source: R/stats.R

exposureR Documentation

Ego exposure

Description

Calculates exposure to adoption over time via multiple different types of weight matrices. The basic model is exposure to adoption by immediate neighbors (outdegree) at the time period prior to ego’s adoption. This exposure can also be based on (1) incoming ties, (2) structural equivalence, (3) indirect ties, (4) network-metric weighted (e.g., central nodes have more influence), and (5) attribute-weighted (e.g., based on homophily or tie strength).

Usage

exposure(
  graph,
  cumadopt,
  attrs = NULL,
  alt.graph = NULL,
  outgoing = getOption("diffnet.outgoing", TRUE),
  valued = getOption("diffnet.valued", FALSE),
  normalized = TRUE,
  groupvar = NULL,
  self = getOption("diffnet.self"),
  lags = 0L,
  ...
)

Arguments

graph

A dynamic graph (see netdiffuseR-graphs).

cumadopt

n\times T matrix for single diffusion. n\times T \times Q array for Q diffusion processes. Cumulative adoption matrix obtained from toa_mat

attrs

Either a character scalar (if graph is diffnet), a numeric matrix of size n\times T, or an array of size n\times T \times Q (only for multi diffusion). Weighting for each time period (see details).

alt.graph

Either a graph that should be used instead of graph, or "se" (see details).

outgoing

Logical scalar. When TRUE, computed using outgoing ties.

valued

Logical scalar. When TRUE weights will be considered. Otherwise non-zero values will be replaced by ones.

normalized

Logical scalar. When TRUE, the exposure will be between zero and one (see details).

groupvar

Passed to struct_equiv.

self

Logical scalar. When TRUE autolinks (loops, self edges) are allowed (see details).

lags

Integer scalar. When different from 0, the resulting exposure matrix will be the lagged exposure as specified (see examples).

...

Further arguments passed to struct_equiv (only used when alt.graph="se").

Details

Exposure is calculated as follows:

% E_t = \left(S_t \times \left[x_t \circ A_t\right]\right) / (S_t \times x_t) %

Where S_t is the graph in time t, x_t is an attribute vector of size n at time t, A_t is the t-th column of the cumulative adopters matrix (a vector of length n with a_{ti}=1 if i has adopted at or prior to t), \circ is the kronecker product (element-wise), and \times is the matrix product.

By default the graph used for this calculation, S, is the social network. Alternatively, in the case of diffnet objects, the user can provide an alternative graph using alt.graph. An example of this would be using 1/SE, the element-wise inverse of the structural equivalence matrix (see example below). Furthermore, if alt.graph="se", the inverse of the structural equivalence is computed via struct_equiv and used instead of the provided graph. Notice that when using a valued graph the option valued should be equal to TRUE, this check is run automatically when running the model using structural equivalence.

If the alt.graph is static, then the function will warn about it and will recycle the graph to compute exposure at each time point.

An important remark is that when calculating structural equivalence the function assumes that this is to be done to the entire graph regardless of disconnected communities (as in the case of the medical innovations data set). Hence, structural equivalence for individuals for two different communites may not be zero. If the user wants to calculate structural equivalence separately by community, he should create different diffnet objects and do so (see example below). Alternatively, for the case of diffnet objects, by using the option groupvar (see struct_equiv), the user can provide the function with the name of a grouping variable–which should one in the set of static vertex attributes–so that the algorithm is done by group (or community) instead of in an aggregated way.

If the user does not specifies a particular weighting attribute in attrs, the function sets this as a matrix of ones. Otherwise the function will return an attribute weighted exposure. When graph is of class diffnet, attrs can be a character scalar specifying the name of any of the graph's attributes, both dynamic and static. See the examples section for a demonstration using degree.

When outgoing=FALSE, S is replaced by its transposed, so in the case of a social network exposure will be computed based on the incoming ties.

If normalize=FALSE then denominator, S_t \times x_t, is not included. This can be useful when, for example, exposure needs to be computed as a count instead of a proportion. A good example of this can be found at the examples section of the function rdiffnet.

Value

A matrix of size n\times T with exposure for each node.

Author(s)

George G. Vega Yon, Thomas W. Valente, and Aníbal Olivera M.

References

Burt, R. S. (1987). "Social Contagion and Innovation: Cohesion versus Structural Equivalence". American Journal of Sociology, 92(6), 1287. \Sexpr[results=rd]{tools:::Rd_expr_doi("10.1086/228667")}

Valente, T. W. (1995). "Network models of the diffusion of innovations" (2nd ed.). Cresskill N.J.: Hampton Press.

See Also

Other statistics: bass, classify_adopters(), cumulative_adopt_count(), dgr(), ego_variance(), hazard_rate(), infection(), moran(), struct_equiv(), threshold(), vertex_covariate_dist()

Examples

# Calculating lagged exposure -----------------------------------------------

set.seed(8)
graph <- rdiffnet(20, 4)

expo0 <- exposure(graph)
expo1 <- exposure(graph, lags = 1)

# These should be equivalent
stopifnot(all(expo0[, -4] == expo1[, -1])) # No stop!


# Calculating the exposure based on Structural Equivalence ------------------
set.seed(113132)
graph <- rdiffnet(100, 4)

SE <- lapply(struct_equiv(graph), "[[", "SE")
SE <- lapply(SE, function(x) {
   x <- 1/x
   x[!is.finite(x)] <- 0
   x
})


# These three lines are equivalent to:
expo_se2 <- exposure(graph, alt.graph="se", valued=TRUE)
# Notice that we are setting valued=TRUE, but this is not necesary since when
# alt.graph = "se" the function checks this to be setted equal to TRUE

# Weighted Exposure using degree --------------------------------------------
eDE <- exposure(graph, attrs=dgr(graph))

# Which is equivalent to
graph[["deg"]] <- dgr(graph)
eDE2 <- exposure(graph, attrs="deg")

# Comparing using incoming edges -------------------------------------------
eIN <- exposure(graph, outgoing=FALSE)

# Structral equivalence for different communities ---------------------------
data(medInnovationsDiffNet)

# Only using 4 time slides, this is for convenience
medInnovationsDiffNet <- medInnovationsDiffNet[, , 1:4]

# METHOD 1: Using the c.diffnet method:

# Creating subsets by city
cities <- unique(medInnovationsDiffNet[["city"]])

diffnet <- medInnovationsDiffNet[medInnovationsDiffNet[["city"]] == cities[1]]
diffnet[["expo_se"]] <- exposure(diffnet, alt.graph="se", valued=TRUE)

for (v in cities[-1]) {
   diffnet_v <- medInnovationsDiffNet[medInnovationsDiffNet[["city"]] == v]
   diffnet_v[["expo_se"]] <- exposure(diffnet_v, alt.graph="se", valued=TRUE)
   diffnet <- c(diffnet, diffnet_v)
}

# We can set the original order (just in case) of the data
diffnet <- diffnet[medInnovationsDiffNet$meta$ids]
diffnet

# Checking everything is equal
test <- summary(medInnovationsDiffNet, no.print=TRUE) ==
   summary(diffnet, no.print=TRUE)

stopifnot(all(test[!is.na(test)]))

# METHOD 2: Using the 'groupvar' argument
# Further, we can compare this with using the groupvar
diffnet[["expo_se2"]] <- exposure(diffnet, alt.graph="se",
   groupvar="city", valued=TRUE)

# These should be equivalent
test <- diffnet[["expo_se", as.df=TRUE]] == diffnet[["expo_se2", as.df=TRUE]]
stopifnot(all(test[!is.na(test)]))

# METHOD 3: Computing exposure, rbind and then adding it to the diffnet object
expo_se3 <- NULL
for (v in unique(cities))
   expo_se3 <- rbind(
     expo_se3,
     exposure(
       diffnet[diffnet[["city"]] == v],
       alt.graph = "se", valued=TRUE
     ))

# Just to make sure, we sort the rows
expo_se3 <- expo_se3[diffnet$meta$ids,]

diffnet[["expo_se3"]] <- expo_se3

test <- diffnet[["expo_se", as.df=TRUE]] == diffnet[["expo_se3", as.df=TRUE]]
stopifnot(all(test[!is.na(test)]))


# METHOD 4: Using the groupvar in struct_equiv
se <- struct_equiv(diffnet, groupvar="city")
se <- lapply(se, "[[", "SE")
se <- lapply(se, function(x) {
   x <- 1/x
   x[!is.finite(x)] <- 0
   x
})

diffnet[["expo_se4"]] <- exposure(diffnet, alt.graph=se, valued=TRUE)

test <- diffnet[["expo_se", as.df=TRUE]] == diffnet[["expo_se4", as.df=TRUE]]
stopifnot(all(test[!is.na(test)]))


# Examples for multi-diffusion ---------------------------

# Running a multi-diffusion simulation, with q=2 behaviors
set.seed(999)
n <- 40; t <- 5; q <- 2;
graph <- rgraph_ws(n, t, p=.3)
seed_prop_adopt <- rep(list(0.1), q)

diffnet <- rdiffnet(seed.graph = graph, t = t, seed.p.adopt = seed_prop_adopt)

# Getting the cumulative adoption array of dims n x T x q
cumadopt_2 <- diffnet$cumadopt  # list of matrices
cumadopt_2 <- array(unlist(cumadopt_2), dim = c(n, t, q))

expo2 <- exposure(diffnet$graph, cumadopt = cumadopt_2)

# With an attribute --

X <- matrix(runif(n * t), nrow = n, ncol = t) # matrix n x T
ans3 <- exposure(diffnet$graph, cumadopt = cumadopt_2, attrs=X)

X <- array(runif(n * t * q), dim = c(n, t, q)) # array n x T x q
ans4 <- exposure(diffnet$graph, cumadopt = cumadopt_2, attrs=X)

# Exposure based on Structural Equivalence --

diffnet_1 <- split_behaviors(diffnet)[[1]]
se <- struct_equiv(diffnet)
se <- lapply(se, function(x) {
  ans <- methods::as(x$SE, "dgCMatrix")
    ans@x <- 1/(ans@x + 1e-20)
      ans
      })
ans6 <- exposure(diffnet, cumadopt = cumadopt_2, alt.graph = se, valued=TRUE)


srdyal/diffusiontest documentation built on Dec. 9, 2024, 1:14 a.m.