-
-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathprojections.R
133 lines (118 loc) · 4.3 KB
/
projections.R
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#' Projections of a Country-Product Network
#'
#' @description \code{projections()} computes two graphs that are particularly
#' useful to visualize product-product and country-country similarity.
#'
#' @details The current implementation follows
#' \insertCite{atlas2014}{economiccomplexity} to create simplified graphs
#' that correspond to a simplification of the proximity matrices. The result is
#' obtained by iterating and reducing links until the desired average number of
#' links per node is obtained, or a spaning tree after the strongest links is
#' returned when is not possible to return the desired network.
#'
#' @return A list of two graphs.
#'
#' @param proximity_country (Type: matrix) the output from
#' \code{proximity()}) or an equivalent arrangement.
#' @param proximity_product (Type: matrix) the output from
#' \code{proximity()}) or an equivalent arrangement.
#' @param avg_links average number of connections for the projections.
#' By default this is set to \code{5}.
#' @param tolerance tolerance for proximity variation on each iteration until
#' obtaining the desired average number of connections.
#' By default this is set to \code{0.05}.
#' @param compute (Type: character) the proximity to compute. By default this is
#' \code{"both"} (both projections) but it can also be \code{"country"}
#' or \code{"product"}.
#'
#' @examples
#' net <- projections(
#' economiccomplexity_output$proximity$proximity_country,
#' economiccomplexity_output$proximity$proximity_product,
#' avg_links = 10,
#' tolerance = 0.1
#' )
#'
#' # partial view of projections
#' n <- seq_len(5)
#' igraph::E(net$network_country)[n]
#' igraph::E(net$network_product)[n]
#'
#' @references
#' For more information see:
#'
#' \insertRef{atlas2014}{economiccomplexity}
#'
#' and the references therein.
#'
#' @keywords functions
#'
#' @export
projections <- function(proximity_country, proximity_product,
avg_links = 5, tolerance = 0.05, compute = "both") {
# sanity checks ----
if (!(any(class(proximity_country) %in% "matrix") == TRUE) |
!(any(class(proximity_product) %in% "matrix") == TRUE)) {
stop("'proximity_country' and 'proximity_product' must be matrix")
}
if (!is.numeric(avg_links)) {
stop("'avg_links' must be numeric")
}
if (!any(compute %in% c("both", "country", "product"))) {
stop("'compute' must be 'both', 'country' or 'product'")
}
trim_network <- function(proximity_mat, proximity_avg) {
# this -1 is because the book by Hausmann mentions "maximum spanning tree"
proximity_mat <- (-1) * proximity_mat
g <- graph_from_adjacency_matrix(proximity_mat, weighted = TRUE,
mode = "undirected", diag = FALSE)
g_mst <- mst(g, algorithm = "prim")
threshold <- 0
avg_links_n <- FALSE
while (avg_links_n == FALSE) {
if (threshold < 1) {
message(sprintf("%s threshold...", threshold))
g_not_in_mst <- delete.edges(g, which(abs(E(g)$weight) <= threshold))
g_not_in_mst <- graph.difference(g_not_in_mst, g_mst)
g <- graph.union(g_mst, g_not_in_mst)
E(g)$weight <- pmin(E(g)$weight_1, E(g)$weight_2, na.rm = TRUE)
g <- remove.edge.attribute(g, "weight_1")
g <- remove.edge.attribute(g, "weight_2")
avg_links_n <- ifelse(mean(degree(g)) <= avg_links, TRUE, FALSE)
threshold <- threshold + tolerance
if (avg_links_n == TRUE) {
message(sprintf("%s threshold achieves the avg number of connections",
threshold))
E(g)$weight <- (-1) * E(g)$weight
return(g)
}
} else {
warning(paste("no threshold achieves the avg number of connections",
"returning maximum spanning tree"))
avg_links_n <- TRUE
E(g_mst)$weight <- (-1) * E(g_mst)$weight
return(g_mst)
}
}
}
if (any(compute == "country" || compute == "both") == TRUE) {
message("computing country projection...")
message(rep("-", 50))
xg <- trim_network(proximity_country, avg_links)
} else {
xg <- NULL
}
if (any(compute == "product" || compute == "both") == TRUE) {
message("computing product projection...")
message(rep("-", 50))
yg <- trim_network(proximity_product, avg_links)
} else {
yg <- NULL
}
return(
list(
network_country = xg,
network_product = yg
)
)
}