Skip to content

pjgorski/PolarizationFramework

Repository files navigation

PolarizationFramework

Table of contents

About the project

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.

Built with

This code base is using the Julia Language (1.6.4) and DrWatson to make a reproducible scientific project.

Getting started

Installation

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.

Example

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.

The influence of growing number of attributes on the preventing polarization from forming

(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'.

Result analysis

(see this file or notebook)

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

NGattr_namegammaLPGPHB
UInt32?UInt32?String?Float64?Float64?Float64?Float64?
151BinaryAttributes0.50.780.941.0
251BinaryAttributes1.50.7440.931.0
351BinaryAttributes4.00.7440.921.0
491BinaryAttributes0.50.7741671.01.0
591BinaryAttributes1.50.7691671.01.0
691BinaryAttributes4.00.7558331.01.0
753BinaryAttributes0.50.7290.911.0
853BinaryAttributes1.50.7440.80.82
953BinaryAttributes4.00.5790.290.26
1093BinaryAttributes0.50.7480950.960.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)))

svg

Attributes

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 after AbstractAttributes and contains at least field g with number of attributes.
struct OwnAttributes <: AbstractAttributes
    g
end
  • implement get_threshold(b::OwnAttributes) if this is different from general get_threshold(b::AbstractAttributes).
  • implement get_degeneracy(b::OwnAttributes) if this is different from general get_degeneracy(b::AbstractAttributes).
  • implement a function generating random attributes get_attributes(b::OwnAttributes, n::Int) if this is different from general get_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 general get_attribute_layer_weights(b::AbstractAttributes, attr::AbstractArray{<:Number}).

About

Framework allowing analysis of preventing and destabilizing polarization

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published