Vi starter med at indlæse relevante pakker her. Pakkerne er installeret på forhånd hos os, hvorfor vi blot indlæser dem.
library(readxl)
library(data.table)
library(zoo)
library(here)
library(tidyverse)
Analysen dækker udfaldsårene 1997 til 2024. Da alle uafhængige variable måles året før, bruger vi data fra 1996 til 2024. Startåret er valgt, så de central- og østeuropæiske lande er ude af de første overgangsår efter kommunismens fald, mens slutåret er sat af datadækningen. Til de længere lags af samfundsmæssig polarisering henter vi V-Dem-data tilbage til 1993.
Vi definerer desuden en udvidet periode fra 1975. Den bruges til kontrolvariablen effektivt antal partier, hvor sidste valgs værdi føres frem, indtil et nyt valg afløser den. På den måde har også årene før landets første valg i perioden en værdi.
år <- 1996:2024
år_udvidet <- 1975:2024
Vi afgrænser vores sample i tre trin. Først et institutionelt kriterium, dernæst datadækning og til sidst et regimekriterium.
Første trin omfatter europæiske lande, der i løbet af perioden er eller har været medlemmer af EU eller EFTA. Det giver et udvalg på 32 lande, der består af de nuværende 27 EU-lande, de fire EFTA-lande og Storbritannien.
kandidat_lande <- c("AUT","BEL","BGR","CHE","CYP","CZE","DEU","DNK","ESP","EST",
"FIN","FRA","GBR","GRC","HRV","HUN","IRL","ISL","ITA","LIE",
"LTU","LUX","LVA","MLT","NLD","NOR","POL","PRT","ROU","SVK",
"SVN","SWE")
cat("Antallet af potentielle lande er", length(kandidat_lande))
Antallet af potentielle lande er 32
Andet og tredje trin bygger på V-Dem. Landene skal være dækket af V-Dem og ved periodens begyndelse være klassificeret som mindst elektorale demokratier i V-Dems Regimes of the World, hvor 0 og 1 er autokratier, mens 2 og 3 er demokratier.
V_Dem_rå <- read_csv("Data/V-Dem/V-Dem data.csv",
col_select = c(country_text_id, year, v2x_regime, v2cacamps)) |>
filter(country_text_id %in% kandidat_lande, year %in% (min(år) - 3):max(år)) |>
rename(lande = country_text_id, år = year, regime = v2x_regime, samf_pol = v2cacamps)
regime_screening <- V_Dem_rå |>
filter(år %in% .env$år) |>
drop_na(regime) |>
group_by(lande) |>
slice_min(år) |>
ungroup() |>
select(lande, første_år = år, regime) |>
arrange(regime, lande)
cat("Lande med V-Dem-dækning:", nrow(regime_screening), "\n")
Lande med V-Dem-dækning: 31
cat("Uden dækning:", paste(setdiff(kandidat_lande, regime_screening$lande),
collapse = ", "), "\n\n")
Uden dækning: LIE
regime_screening |> filter(regime < 2) |> print()
# A tibble: 1 × 3
lande første_år regime
<chr> <dbl> <dbl>
1 HRV 1996 1
Liechtenstein udgår på datadækningen, da landet ikke indgår i V-Dem. Kroatien udgår på regimekriteriet, da landet var klassificeret som elektoralt autokrati i 1996.
lande <- regime_screening |>
filter(regime >= 2) |>
pull(lande) |>
sort()
cat(length(lande), "lande i samplet:", paste(lande, collapse = ", "))
30 lande i samplet: AUT, BEL, BGR, CHE, CYP, CZE, DEU, DNK, ESP, EST, FIN, FRA, GBR, GRC, HUN, IRL, ISL, ITA, LTU, LUX, LVA, MLT, NLD, NOR, POL, PRT, ROU, SVK, SVN, SWE
Vi ender således samlet set på 30 lande i samplet.
Fra V-Dem får vi det samfundsmæssige polariseringsmål. Det er eksperters vurdering af, hvor opdelt et samfund er i fjendtlige politiske lejre.
V_Dem <- V_Dem_rå |>
filter(lande %in% .env$lande, år %in% .env$år)
Vi kontrollerer dimensionerne. 30 lande ganget med 29 år skal give 870 rækker uden dubletter.
dubletter_V_Dem <- V_Dem |> count(lande, år) |> filter(n > 1)
if (nrow(dubletter_V_Dem) == 0) {
cat(nrow(V_Dem), "rækker,", n_distinct(V_Dem$lande),
"unikke lande og ingen dubletter")
} else {
cat(nrow(V_Dem), "rækker,", n_distinct(V_Dem$lande), "unikke lande\n")
print(dubletter_V_Dem)
}
870 rækker, 30 unikke lande og ingen dubletter
Vi undersøger dækningen af det samfundsmæssige polariseringsmål pr. land.
V_Dem |>
group_by(lande) |>
summarise(mangler = sum(is.na(samf_pol)),
første_år = min(år[!is.na(samf_pol)])) |>
arrange(desc(mangler)) |>
print(n = 30)
# A tibble: 30 × 3
lande mangler første_år
<chr> <int> <dbl>
1 ISL 4 2000
2 AUT 0 1996
3 BEL 0 1996
4 BGR 0 1996
5 CHE 0 1996
6 CYP 0 1996
7 CZE 0 1996
8 DEU 0 1996
9 DNK 0 1996
10 ESP 0 1996
11 EST 0 1996
12 FIN 0 1996
13 FRA 0 1996
14 GBR 0 1996
15 GRC 0 1996
16 HUN 0 1996
17 IRL 0 1996
18 ITA 0 1996
19 LTU 0 1996
20 LUX 0 1996
21 LVA 0 1996
22 MLT 0 1996
23 NLD 0 1996
24 NOR 0 1996
25 POL 0 1996
26 PRT 0 1996
27 ROU 0 1996
28 SVK 0 1996
29 SVN 0 1996
30 SWE 0 1996
Island mangler ekspertdækning i 1996-1999 og indgår derfor først fra 2000. Vi bruger også samfundsmæssig polarisering målt et, to og tre år før. Lagsene beregnes ud fra data tilbage til 1993, så også udfaldsåret 1997 har lags tre år tilbage.
samf_pol_lags <- V_Dem_rå |>
filter(lande %in% .env$lande) |>
arrange(lande, år) |>
group_by(lande) |>
mutate(samf_pol_l1 = lag(samf_pol),
samf_pol_l2 = lag(samf_pol, 2),
samf_pol_l3 = lag(samf_pol, 3)) |>
ungroup() |>
filter(år %in% .env$år) |>
select(lande, år, samf_pol_l1, samf_pol_l2, samf_pol_l3)
Fra Manifesto får vi målet for partipolarisering. Partipolarisering
måler, hvor langt partierne står fra hinanden i deres valgprogrammer.
Datasættet har en række pr. parti pr. valg med højre-venstre-position
(rile) og stemmeandel (pervote). Landenavnene
står i klartekst, så vi bygger først en navnetabel.
manifesto_navne <- c("Austria"="AUT","Belgium"="BEL","Bulgaria"="BGR",
"Switzerland"="CHE","Cyprus"="CYP",
"Czech Republic"="CZE","Germany"="DEU","Denmark"="DNK",
"Spain"="ESP","Estonia"="EST","Finland"="FIN",
"France"="FRA","United Kingdom"="GBR","Greece"="GRC",
"Hungary"="HUN","Ireland"="IRL","Iceland"="ISL",
"Italy"="ITA","Lithuania"="LTU","Luxembourg"="LUX",
"Latvia"="LVA","Malta"="MLT","Netherlands"="NLD",
"Norway"="NOR","Poland"="POL","Portugal"="PRT",
"Romania"="ROU","Slovakia"="SVK","Slovenia"="SVN",
"Sweden"="SWE")
cat("Navnetabellen indeholder", length(manifesto_navne), "lande")
Navnetabellen indeholder 30 lande
Vi indlæser fra 1975, så værdier fra valg før 1996 kan føres frem. Vi udleder valgåret af valgdatoen og frasorterer partier uden rile-kodning, uden stemmeandel eller med en stemmeandel på nul.
Manifesto <- read_excel("Data/Manifesto/Manifesto data.xlsx") |>
mutate(lande = manifesto_navne[countryname],
år = year(edate)) |>
filter(!is.na(lande), år %in% år_udvidet) |>
select(lande, år, edate, rile, pervote) |>
drop_na(rile, pervote) |>
filter(pervote > 0)
cat(n_distinct(Manifesto$lande), "unikke lande og",
nrow(distinct(Manifesto, lande, edate)), "valg")
30 unikke lande og 344 valg
Polariseringen beregnes pr. valg som en stemmeandelsvægtet standardafvigelse af partiernes rile-positioner, hvor store partier vægter mere end små. For et valg med n partier beregnes først hvert partis vægt som dets renormaliserede stemmeandel. Renormaliseringen er nødvendig, fordi de kodede partiers stemmeandele ikke nødvendigvis summer til 100 procent. Resten af stemmerne går til småpartier uden rile-kodning, og vægtene skal summe til 1.
w_i = \frac{v_i}{\sum_{j=1}^{n} v_j}
hvor w_i er parti i’s vægt og v_i er dets stemmeandel
(pervote). Dernæst beregnes det vægtede midtpunkt (\mu), altså tyngdepunktet i
partisystemet.
\mu = \sum_{i=1}^{n} w_i \, r_i
hvor r_i er parti i’s rile-position (rile).
Endelig beregnes polariseringen som den vægtede standardafvigelse
omkring midtpunktet.
P = \sqrt{\textstyle\sum_{i=1}^{n} w_i \, (r_i - \mu)^2}
hvor P er polariseringsmålet. I samme trin beregner vi det effektive antal partier som 1 divideret med summen af de kvadrerede stemmeandele. Det bruges som kontrolvariabel.
Manifesto_valg <- Manifesto |>
group_by(lande, edate, år) |>
summarise(eff_partier = 1 / sum((pervote / sum(pervote))^2),
mu = sum((pervote / sum(pervote)) * rile),
prog_pol = sqrt(sum((pervote / sum(pervote)) * (rile - mu)^2)),
.groups = "drop")
cat(nrow(Manifesto_valg), "valg med beregnet polarisering")
344 valg med beregnet polarisering
Tallet svarer til antallet af valg i indlæsningen. Nu kigger vi på, hvilke lande som har haft dobbeltvalg.
dobbeltvalg <- Manifesto_valg |> count(lande, år) |> filter(n > 1)
if (nrow(dobbeltvalg) == 0) {
cat("Ingen land-år har mere end ét valg.")
} else {
print(dobbeltvalg)
}
# A tibble: 5 × 3
lande år n
<chr> <dbl> <int>
1 ESP 2019 2
2 GRC 1989 2
3 GRC 2012 2
4 GRC 2015 2
5 IRL 1982 2
Nogle land-år har to valg samme år. Vi beholder det givne års sidste valg, da det er dét, som gjaldt fremadrettet.
Manifesto_valg <- Manifesto_valg |>
group_by(lande, år) |>
slice_max(edate) |>
ungroup()
cat(nrow(Manifesto_valg), "land-år efter reduktion")
339 land-år efter reduktion
Nu laver vi en manuel test af, hvordan vi beregner polariseringen pr. valg som en stemmeandelsvægtet standardafvigelse af partiernes rile-positioner, hvor store partier vægter mere end små. Vi laver udregningen i hånden, hvorefter vi ser, at vi får det samme med kode. Vi tager GBR (2005) som eksempel, fordi valget kun har tre kodede partier.
GBR (2005) havde følgende tre partier: Labour (rile −3,090; pervote 35,186 pct.), Liberal Democrats (rile 3,212; pervote 22,047 pct.) og Conservatives (rile 14,535; pervote 32,359 pct.).
De tre partiers stemmeandele summer ikke til 100 pct., men til 35,186 + 22,047 + 32,359 = 89,592 pct., fordi resten af stemmerne gik til småpartier uden rile-kodning. Derfor renormaliseres andelene først, så vægtene summer til 1: Labour 35,186/89,592 = 0,3927, Liberal Democrats 22,047/89,592 = 0,2461 og Conservatives 32,359/89,592 = 0,3612. Kontrol: 0,3927 + 0,2461 + 0,3612 = 1,0000.
Dernæst det vægtede midtpunkt (μ): 0,3927·(−3,090) + 0,2461·3,212 + 0,3612·14,535 = 4,83.
Hvert partis afstand til midtpunktet: Labour −3,090 − 4,83 = −7,92; Liberal Democrats 3,212 − 4,83 = −1,62; Conservatives 14,535 − 4,83 = 9,71.
Afstandene kvadreres og vægtes med partiets størrelse: Labour (−7,92)² · 0,3927 = 24,61; Liberal Democrats (−1,62)² · 0,2461 = 0,64; Conservatives (9,71)² · 0,3612 = 34,04.
Summen er 24,61 + 0,64 + 34,04 = 59,30, og kvadratroden fører tallet tilbage til rile-skalaens enheder: √59,30 = 7,70.
kontrol_GBR <- Manifesto_valg |>
filter(lande == "GBR", år == 2005) |>
pull(prog_pol)
cat("prog_pol =", format(kontrol_GBR, digits = 3, nsmall = 2, decimal.mark = ","))
prog_pol = 7,70
Manifesto måler kun ved valg. Danmark har f.eks. et valg i 2015 og igen i 2019, men hvad står der så i årene 2016, 2017 og 2018? Svaret afhænger af, hvad der måles.
Partipolarisering bruger kun valgår. Årene mellem valgene står tomme, så analysen bygger kun på det, der faktisk er målt.
Effektivt antal partier er en kontrolvariabel i alle modeller og skal derfor have en værdi hvert år. Her føres sidste valgs værdi frem, indtil et nyt valg afløser den.
Manifesto_panel <- expand_grid(lande = lande, år = år_udvidet) |>
left_join(Manifesto_valg |> select(lande, år, prog_pol, eff_partier),
by = c("lande", "år")) |>
arrange(lande, år) |>
group_by(lande) |>
mutate(eff_partier = zoo::na.locf(eff_partier, na.rm = FALSE)) |>
ungroup() |>
filter(år %in% .env$år) |>
select(lande, år, prog_pol_valgår = prog_pol, eff_partier)
Vi undersøger dækningen af partipolarisering pr. land.
Manifesto_panel |>
group_by(lande) |>
summarise(valg = sum(!is.na(prog_pol_valgår)),
første = min(år[!is.na(prog_pol_valgår)]),
sidste = max(år[!is.na(prog_pol_valgår)])) |>
arrange(valg, lande) |>
print(n = 30)
# A tibble: 30 × 4
lande valg første sidste
<chr> <int> <dbl> <dbl>
1 CYP 5 1996 2016
2 LUX 5 1999 2018
3 BEL 6 1999 2019
4 CHE 6 1999 2019
5 EST 6 1999 2019
6 FIN 6 1999 2019
7 FRA 6 1997 2022
8 IRL 6 1997 2020
9 ITA 6 1996 2018
10 NOR 6 1997 2017
11 ROU 6 1996 2016
12 SVK 6 1998 2016
13 AUT 7 1999 2019
14 BGR 7 1997 2017
15 DEU 7 1998 2021
16 DNK 7 1998 2019
17 HUN 7 1998 2022
18 LTU 7 1996 2020
19 MLT 7 1996 2022
20 POL 7 1997 2019
21 SVN 7 1996 2018
22 SWE 7 1998 2022
23 CZE 8 1996 2021
24 GBR 8 1997 2024
25 LVA 8 1998 2022
26 NLD 8 1998 2021
27 PRT 8 1999 2022
28 ESP 9 1996 2023
29 GRC 9 1996 2023
30 ISL 9 1999 2024
Fra Eurobarometer får vi målet for vælgerpolarisering. Respondenterne placerer sig selv på en venstre-højre-skala fra 1 (venstre) til 10 (højre), og vælgerpolarisering er den vægtede standardafvigelse i deres svar pr. land og år.
Målet ligger færdigberegnet i filen
Eurobarometer data.csv, som vi har lavet ud fra de enkelte
Eurobarometer-runder. Har et land flere runder i samme år, bruger vi
gennemsnittet. Huller på op til to år er udfyldt med lineær
interpolation. Der er ingen målinger i 2012.
EB <- read_csv("Data/Eurobarometer/Eurobarometer data.csv", show_col_types = FALSE) |>
filter(lande %in% .env$lande, år %in% .env$år)
Vi undersøger dækningen af vælgerpolarisering pr. land.
EB |>
group_by(lande) |>
summarise(målt = sum(kilde == "målt"),
interpoleret = sum(kilde == "interpoleret"),
første = min(år[kilde == "målt"]),
sidste = max(år[kilde == "målt"])) |>
arrange(målt, lande) |>
print(n = 30)
# A tibble: 30 × 5
lande målt interpoleret første sidste
<chr> <int> <int> <dbl> <dbl>
1 CHE 4 0 2020 2023
2 NOR 5 0 1996 2023
3 ISL 6 2 2010 2022
4 BGR 19 1 2004 2023
5 CYP 19 1 2004 2023
6 CZE 19 1 2004 2023
7 EST 19 1 2004 2023
8 HUN 19 1 2004 2023
9 LTU 19 1 2004 2023
10 LVA 19 1 2004 2023
11 MLT 19 1 2004 2023
12 POL 19 1 2004 2023
13 ROU 19 1 2004 2023
14 SVK 19 1 2004 2023
15 SVN 19 1 2004 2023
16 AUT 27 1 1996 2023
17 BEL 27 1 1996 2023
18 DEU 27 1 1996 2023
19 DNK 27 1 1996 2023
20 ESP 27 1 1996 2023
21 FIN 27 1 1996 2023
22 FRA 27 1 1996 2023
23 GBR 27 1 1996 2023
24 GRC 27 1 1996 2023
25 IRL 27 1 1996 2023
26 ITA 27 1 1996 2023
27 LUX 27 1 1996 2023
28 NLD 27 1 1996 2023
29 PRT 27 1 1996 2023
30 SWE 27 1 1996 2023
De 15 lande, der var medlemmer af EU i 1996, er målt i alle år undtagen 2012. De central- og østeuropæiske lande samt Cypern og Malta er med fra 2004. Norge, Island og Schweiz er kun med i enkelte år.
World Inequality Database giver os vores uligheds- og omfordelingsmål.
Vi henter Gini-koefficienten både før og efter skat. Gini efter skat måler uligheden i den disponible indkomst, altså den indkomst, folk faktisk råder over. Gini før skat er målt efter pensioner og arbejdsløshedsunderstøttelse, men før øvrige skatter og overførsler. Forskellen mellem de to er omfordelingen. De to sidste mål bruges til at undersøge, om en sammenhæng med ulighed efter skat kommer fra uligheden før skat eller fra omfordelingen.
Data ligger som separate landefiler. Vi bruger derfor en funktion, der læser én fil ad gangen og med det samme filtrerer ned til de rækker, vi skal bruge, i stedet for at indlæse alt og rydde op bagefter.
wid_navne <- c("AT"="AUT","BE"="BEL","BG"="BGR","CH"="CHE","CY"="CYP",
"CZ"="CZE","DE"="DEU","DK"="DNK","EE"="EST","ES"="ESP",
"FI"="FIN","FR"="FRA","GB"="GBR","GR"="GRC","HU"="HUN",
"IE"="IRL","IS"="ISL","IT"="ITA","LT"="LTU","LU"="LUX",
"LV"="LVA","MT"="MLT","NL"="NLD","NO"="NOR","PL"="POL",
"PT"="PRT","RO"="ROU","SE"="SWE","SI"="SVN","SK"="SVK")
wid_filer <- file.path("Data/World Inequality Database",
paste0("WID_data_", names(wid_navne), ".csv"))
læs_wid <- function(fil) {
fread(fil, sep = ";",
select = c("country", "variable", "percentile", "year", "value")) |>
as_tibble() |>
filter(variable %in% c("gdiincj992", "gptincj992"),
percentile == "p0p100",
year %in% .env$år)
}
WID <- map(wid_filer, læs_wid) |>
list_rbind() |>
mutate(lande = wid_navne[country],
variable = recode(variable,
gdiincj992 = "gini",
gptincj992 = "gini_før")) |>
select(lande, år = year, variable, value) |>
pivot_wider(names_from = variable, values_from = value) |>
mutate(gini = gini * 100,
gini_før = gini_før * 100,
omfordeling = gini_før - gini)
cat(nrow(WID), "rækker og", n_distinct(WID$lande), "lande")
870 rækker og 30 lande
Vi ser på, om vi har manglende observationer.
cat("Manglende observationer: Gini efter skat", sum(is.na(WID$gini)),
"| Gini før skat", sum(is.na(WID$gini_før)))
Manglende observationer: Gini efter skat 0 | Gini før skat 0
Vi har således ingen manglende observationer i WID.
World Bank giver os de resterende økonomiske variable, som vi skal bruge.
wb_filer <- c(
bnp_vækst = "World Bank data BNP-vækst.csv",
bnp_pc = "World Bank data BNP per capita.csv",
inflation = "World Bank data inflation.csv",
arbejdsløshed = "World Bank data arbejdsløshed.csv") |>
(\(x) setNames(file.path("Data/World Bank", x), names(x)))()
læs_wb <- function(fil, varnavn) {
read_csv(fil, skip = 4, show_col_types = FALSE,
name_repair = "unique_quiet") |>
filter(`Country Code` %in% lande) |>
select(lande = `Country Code`, matches("^\\d{4}$")) |>
pivot_longer(cols = -lande,
names_to = "år",
values_to = varnavn,
names_transform = as.integer) |>
filter(år %in% .env$år)
}
WB <- imap(wb_filer, læs_wb) |>
reduce(full_join, by = c("lande", "år"))
cat(nrow(WB), "rækker og", n_distinct(WB$lande), "lande")
870 rækker og 30 lande
Vi ser på, om vi har manglende observationer.
manglende_detaljer <- WB |>
pivot_longer(cols = -c(lande, år),
names_to = "variabel", values_to = "værdi") |>
filter(is.na(værdi)) |>
group_by(variabel, lande) |>
summarise(antal = n(),
år = paste(sort(år), collapse = ", "),
.groups = "drop") |>
arrange(variabel, lande)
if (nrow(manglende_detaljer) == 0) {
cat("Ingen manglende observationer")
} else {
print(manglende_detaljer, n = Inf, width = Inf)
}
Ingen manglende observationer
Vi har således ingen manglende observationer i World Bank.
Vores kilder samles nu til ét analysepanel. Panelet indeholder kun de variable, vi bruger i analysen.
panel <- list(V_Dem |> select(-regime),
samf_pol_lags,
Manifesto_panel,
EB |> select(lande, år, eb_pol, eb_pol_interp),
WID, WB) |>
reduce(left_join, by = c("lande", "år"),
.init = expand_grid(lande = lande, år = .env$år))
dubletter_panel <- panel |> count(lande, år) |> filter(n > 1)
cat(nrow(panel), "rækker,", ncol(panel), "kolonner",
ifelse(nrow(dubletter_panel) == 0, "og ingen dubletter", "MEN DUBLETTER!"))
870 rækker, 17 kolonner og ingen dubletter
Nu fryser vi panelet, så vi kan arbejde ud fra det.
saveRDS(panel, "Data/analysepanel.rds")
kontrol_panel <- readRDS("Data/analysepanel.rds")
if (identical(panel, kontrol_panel)) {
cat(paste0("Panelet er frosset: Data/analysepanel.rds (",
nrow(panel), " rækker og ", ncol(panel), " kolonner)"))
} else {
cat("FEJL: Det gemte panel afviger fra panelet i hukommelsen")
}
Panelet er frosset: Data/analysepanel.rds (870 rækker og 17 kolonner)