Framework containing agent-based models for the analysis of attribute influence on polarization observed in the system.
It allows testing of effectiveness of different kinds of attributes in two scenarios: -destabilization of the polarized system -preventing of the forming of the polarized system.
It allows to replicate results used to generate figures from the not yet published pre-print.
This framework is authored by Piotr J Górski.
This code base is using the Julia Language (1.6.4) and DrWatson to make a reproducible scientific project.
We are using DrWatson
--- a package making scientific collaboration easier.
Therefore, after cloning the project, open julia
terminal in the project folder and write
using DrWatson
quickactivate(@__DIR__, "PolarizationFramework")
using PolarizationFramework
(To do the above you might need to ] add DrWatson
first.)
And you can start using the package. See examples in scripts folder or see instructions below.
The folder scripts
contain simulation examples that allow to obtain results that were used for the Preprint.
Here, I will describe one of the files and the way to analyze the results.
(see this file)
Import package
using DrWatson
quickactivate(@__DIR__)
using PolarizationFramework
Set model structure parameters (in one simulation parameters may have only a single value, but this script allows to perform a series of simulations):
# Number of nodes
ns = [5, 9]
# Number of repetitions for numbers of nodes given above
reps = [100, 100]
reps_dict = Dict(zip(ns, reps))
# Considered numbers of attributes.
gs = [1:2:21..., 25, 29, 33, 37, 41, 45, 49, 55, 61, 67, 73, 81, 89, 97]
# If one wants to test it in a shorter simulation it might be better just to:
# gs = [1:2:21...]
threshold = 0.5
# Number of categories considered. For BinaryAttributes it does not matter.
# When OrderedAttributes are chosen, then 1000 categories gives a continuous attribute.
vs = [4, @onlyif("attr_types" == "OA", 1000)] #includes CA
# Abbreviations of considered attributes.
# Mind that definition of `vs` above will allow to consider 5 cases:
# BinaryAttributes, OrderedAttributes, UnorderedAttributes,
# UnorderedPositiveAttributes and (approx.) continuous attributes.
attr_types = ["BA", "UA", "OA", "UPA"]
# Considered coupling strengths.
gammas = [0.5, 1.5, 4]
Creating sets of parameters to be simulated:
all_params = @strdict(ns, gs, threshold, vs, attr_types)
dicts = dict_list(all_params)
[d["reps"] = reps_dict[d["ns"]] for d in dicts]
Running simulations:
for params in dicts
# Unpacking parameters
n, g, attr_type, v, rep = let
@unpack ns, threshold, reps, gs, attr_types, vs = params
ns, gs, attr_types, vs, reps
end
println("Started n=$n and g=$g and attr_type=", attr_type, " and v=$v.")
# Defining the proper attribute type
if attr_type == "UA"
attr = UnorderedAttributes(g, threshold, v)
elseif attr_type == "BA"
attr = BinaryAttributes(g)
elseif attr_type == "OA"
attr = OrderedAttributes(g, threshold, v)
elseif attr_type == "UPA"
attr = UnorderedPositiveAttributes(g, threshold, v)
else
throw(attr_type)
end
# Running the simulation for a set of gammas
r = using_heider_attr(
n,
attr,
gammas,
rep,
3000.0,
"Heider7!";
disp_each = 0,
disp_more_every = 600,
save_each = 600,
files_folder = ["data", "sims"],
filename_prefix = "NumerFig1",
)
end
(If necessary see description of use_heider_attr
in file)
Above code will generate 'mat' or 'jld2' files with results in the folder data/sims
. All the files will be prefixed with 'NumerFig1'.
To analyze the file we need to import packages again (if they are missing, one needs to ] add
them to the Julia registry).
using DrWatson
quickactivate(@__DIR__)
using StatsBase
using Plots
using DataFrames
Then we can collect the data. The interesting data are located in folder data/sims
and are prefixed "NumerFig1".
# get data
res = DrWatson.collect_results(
datadir("sims"),
rinclude = [r"NumerFig1[.]*"],
)
first(res[!, ["N", "G", "attr_name", "gamma", "LP", "GP", "HB", ]], 10)
10 rows × 7 columns
N | G | attr_name | gamma | LP | GP | HB | |
---|---|---|---|---|---|---|---|
UInt32? | UInt32? | String? | Float64? | Float64? | Float64? | Float64? | |
1 | 5 | 1 | BinaryAttributes | 0.5 | 0.78 | 0.94 | 1.0 |
2 | 5 | 1 | BinaryAttributes | 1.5 | 0.744 | 0.93 | 1.0 |
3 | 5 | 1 | BinaryAttributes | 4.0 | 0.744 | 0.92 | 1.0 |
4 | 9 | 1 | BinaryAttributes | 0.5 | 0.774167 | 1.0 | 1.0 |
5 | 9 | 1 | BinaryAttributes | 1.5 | 0.769167 | 1.0 | 1.0 |
6 | 9 | 1 | BinaryAttributes | 4.0 | 0.755833 | 1.0 | 1.0 |
7 | 5 | 3 | BinaryAttributes | 0.5 | 0.729 | 0.91 | 1.0 |
8 | 5 | 3 | BinaryAttributes | 1.5 | 0.744 | 0.8 | 0.82 |
9 | 5 | 3 | BinaryAttributes | 4.0 | 0.579 | 0.29 | 0.26 |
10 | 9 | 3 | BinaryAttributes | 0.5 | 0.748095 | 0.96 | 0.97 |
In above table we see respectively number of Nodes N
, number of attributes G
, attribute name, coupling strength, local polarization LP
, global polarization GP
and probability of reaching structural balance state HB
. All available columns are described in file.
The results were collected. Now they have to be printed. In the case the same parameters were simulated multiple times, for instance to obtain better statistics, one would have to write a function that aggregates over these results.
N = 9
attr_name = "BinaryAttributes" # ["BinaryAttributes", "OrderedAttributes", "UnorderedAttributes", "UnorderedPositiveAttributes"]
gamma = unique(res.gamma)
attr_degeneracy = 2 #It should be 2 for BA, 1000 for CA (OrderedAttributes). Otherwise 4 (in the currently-generated data).
params = @strdict N attr_name gamma attr_degeneracy
dicts = dict_list(params)
p = plot()
for dict in dicts
inds = ones(Bool, size(res)[1])
for param in dict
inds .*= res[!, string(param[1])] .== param[2]
end
plot!(p, res.G[inds], res.LP[inds], lab = "gamma="*string(dict["gamma"]))
end
plot(p, seriestype=:scatter, xlabel = "G", ylabel = "P_{LP}", legend = :bottomright)
attr = attr_name
v = attr_degeneracy
title!(savename(@ntuple(N, attr, v)))
In the current framework attributes used to impact polarization are assumed to have following parameters:
- their count:
g
- threshold currently always set to 0.5 -- threshold changes which mean levels of similarity are considered to have positive/negative impact on relations
- degeneracy (i.e. number of possible categories an attribute can take):
v
Currently following attributes are implemented:
- Binary attributes
- Ordered attributes
- Unordered attributes (named negative unordered attributes in the Preprint)
- Unordered positive attributes
To create another type of attribute (OwnAttributes
), one has to:
- create a
struct
that inherits afterAbstractAttributes
and contains at least fieldg
with number of attributes.
struct OwnAttributes <: AbstractAttributes
g
end
- implement
get_threshold(b::OwnAttributes)
if this is different from generalget_threshold(b::AbstractAttributes)
. - implement
get_degeneracy(b::OwnAttributes)
if this is different from generalget_degeneracy(b::AbstractAttributes)
. - implement a function generating random attributes
get_attributes(b::OwnAttributes, n::Int)
if this is different from generalget_attributes(b::AbstractAttributes, n::Int)
. - implement a function calculating similarity weights
get_attribute_layer_weights(b::OwnAttributes, attr::AbstractArray{<:Number})
if this is different from generalget_attribute_layer_weights(b::AbstractAttributes, attr::AbstractArray{<:Number})
.