knitr::opts_chunk$set( collapse = TRUE, comment = "#>", out.width = '100%', fig.width=7, fig.height=5, dpi=150 )
# To install a package use `install.packages('package-name')` library(dymiumCore) library(data.table) library(R6) library(dplyr) library(ggplot2) library(patchwork) set.seed(728) knitr::opts_chunk$set(echo = TRUE)
# Import individual and household data ind_data <- toy_individuals # Create an Individual object with attribute data Ind <- Individual$new(.data = ind_data, id_col = "pid") # show data Ind$get_data()
All agents will be randomly assigned a group number to them this is to create sub markets. Sub markets are defined such that only agents within the same sub market can interact with each other. This maybe used to mimic agents' social network, geographical boundary, etc.
n_groups <- 2 # randomly assign group numbers to all agents Ind$get_data(copy = FALSE)[, group := sample(paste0("Group_", 1:n_groups), size = .N, replace = TRUE)]
Ind$get_data() %>% ggplot(data = ., aes(x = age, fill = sex)) + geom_density() + facet_grid(group ~ sex) + labs(title = "Distribution of age by gender and group.")
New matching market can be extended from the available matching market classes
which are MatchingMarketStochastic
and MatchingMarketOptimal
. In every matching
problems there are two sides of the market, we call them A and B. Scoring functions
need to be defined for each side of the market manually by implementing matching_score_A
and matching_score_B
. matching_score_A
represent how agents in one side of
the market evaluate the candidates of the opposite side, and vice versa for
matching_score_B
. The user is expected to change the function but the three
main argument for both the scoring functions must remain the same. self$matching_problem
allows the function to access the variables given when the class was created.
The rule that all agents follow is simple, they want to find a match that has
the least age difference, as expressed in the scoring functions matching_score_A
and matching_score_B
.
$$ MatchingScore_x = \frac{1}{1+|age_x - age_y|}$$
require(lattice) x <- seq(-10, 10, length.out = 15) y <- x f <- function(x,y) { 1 / (1 + abs(x-y)) } z <- outer(x, y, f) wireframe(z, drape=T, col.regions=rainbow(100), zlab = "Score", xlab = "age_x", y = "age_y")
MateMatchingStochastic <- R6::R6Class( classname = "StochasticCohabitationMarket", inherit = MatchingMarketStochastic, public = list( matching_score_A = function(matching_problem = self$matching_problem, idx_A, idx_B) { scores <- 1 / (1 + abs( matching_problem$agentset_A[["age"]][idx_A] - matching_problem$agentset_B[["age"]][idx_B] )) }, matching_score_B = function(matching_problem = self$matching_problem, idx_B, idx_A) { scores <- 1 / (1 + abs( matching_problem$agentset_B[["age"]][idx_B] - matching_problem$agentset_A[["age"]][idx_A] )) } ) )
MateMatchingOptimal <- R6::R6Class( classname = "MateMatchingOptimal", inherit = MatchingMarketOptimal, public = list( matching_score_A = function(matching_problem = self$matching_problem, idx_A, idx_B) { outer(X = matching_problem$agentset_B[["age"]][idx_B], # reviewers, rows Y = matching_problem$agentset_A[["age"]][idx_A], # proposers, columns function(x, y) { 1 / (1 + abs(x - y)) }) }, matching_score_B = function(matching_problem = self$matching_problem, idx_B, idx_A) { outer(X = matching_problem$agentset_A[["age"]][idx_A], # reviewers, rows Y = matching_problem$agentset_B[["age"]][idx_B], # proposers, columns function(x, y) { 1 / (1 + abs(x - y)) }) } ) )
# using dplyr's filter agentset_A <- Ind$get_data() %>% dplyr::filter(age > 20 & age < 60 & sex == 'male') %>% data.table::setDT(.) # convert back to data.table # using data.table syntax for filtering agentset_B <- Ind$get_data() %>% .[age %between% c(20, 60) & sex == 'female'] # define id column id_col_A <- id_col_B <- 'pid' # create a market object using its constructor StochasticMatching <- MateMatchingStochastic$new(agentset_A, agentset_B, id_col_A, id_col_B, grouping_vars = c('group')) OptimalMatching <- MateMatchingOptimal$new(agentset_A, agentset_B, id_col_A, id_col_B, grouping_vars = c('group'))
stochastic_matching_result <- StochasticMatching$simulate(n_choices = 10, # number of potential partners each agent evaluates method = 'pweighted', # weighted probability by_group = TRUE) # segments the whole population into by markets by their group optimal_matching_result <- OptimalMatching$simulate(method = "one-to-one", # each agent only has one match. one_sided = FALSE, # agents from both sides of the market have preferences towards each other optimal_A = TRUE, # optimal for A by_group = TRUE) # segments the whole population into by markets by their group
agediff_range <- c(-20, 20) stochastic_matching_quality <- na.omit(stochastic_matching_result) %>% merge(x = ., y = Ind$get_data()[, .(pid, age)], by.x = 'id_A', by.y = 'pid') %>% merge(x = ., y = Ind$get_data()[, .(pid, age)], by.x = 'id_B', by.y = 'pid', suffixes = c('_A', '_B')) %>% .[, age_diff := age_A - age_B] p_1 <- ggplot(data = stochastic_matching_quality, aes(age_diff)) + geom_density(color = "black", fill = "steelblue") + theme_bw() + scale_x_continuous(limits = agediff_range) + labs(title = "Stochastic market") optimal_matching_quality <- na.omit(optimal_matching_result) %>% merge(x = ., y = Ind$get_data()[, .(pid, age)], by.x = 'id_A', by.y = 'pid') %>% merge(x = ., y = Ind$get_data()[, .(pid, age)], by.x = 'id_B', by.y = 'pid', suffixes = c('_A', '_B')) %>% .[, age_diff := age_A - age_B] p_2 <- ggplot(data = optimal_matching_quality, aes(age_diff)) + geom_density(color = "black", fill = "salmon") + theme_bw() + scale_x_continuous(limits = agediff_range) + labs(title = "Optimal market") p_1 + p_2 + plot_annotation(title = 'A comparison of two age-difference density plots', theme = theme(plot.title = element_text(size = 18, face = "bold")))
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.