knitr::opts_chunk$set(warning = FALSE, message = FALSE, echo = TRUE, include = TRUE)
if(!require("pacman")) install.packages("pacman")
pacman::p_load(tidyverse, devtools, magrittr, knitr, kableExtra, readxl, lubridate, tidytext, Amelia, naniar, RColorBrewer, LexisNexisTools, manifestoR, eurostat, OECD, countrycode, Statamarkdown, zoo, csodata, quanteda, googleLanguageR, tm.plugin.factiva, spacyr, udpipe, syuzhet, broom.mixed, stm, ggraph, igraph, tidygraph, texreg, modelsummary, sjlabelled, lme4)
# avoid select function from wrong package
select <- dplyr::select
# here we define
countries.list <- c("Australia",
"Austria",
"Belgium",
"Canada",
"Czech Republic",
"Czechia",
"Denmark",
"Estonia",
"Finland",
"France",
"Germany",
"Greece",
"Hungary",
"Ireland",
"Israel",
"Italy",
"Japan",
"Latvia",
"Lithuania",
"Netherlands",
"New Zealand",
"Norway",
"Poland",
"Portugal",
"Slovakia",
"Slovenia",
"Spain",
"Sweden",
"Switzerland",
"United Kingdom",
"United States"
)
countries.selected <- c("Australia",
"Austria",
"Belgium",
"Canada",
"Denmark",
"Finland",
"France",
"Germany",
"Greece",
"Ireland",
"Italy",
"Netherlands",
"New Zealand",
"Norway",
"Portugal",
"Spain",
"Sweden",
"Switzerland",
"United Kingdom",
"United States"
)
countries.iso <- countrycode(countries.list, 'country.name', 'iso3c')
# data can be downloaded from the following link: https://www.dropbox.com/sh/9z8buwaa8yhpg5a/AAAGuM8tHNVuWbHU5YZ9n3zOa?dl=0
# set the working directory to the respective folder. This allows one to import the excel/csv/dta files in the raw-data directory.
# In addition, read in the processed data as well. All these objects can be reproduced but here we read them in to directly use them in the paper.
wd <- getwd()
path <- paste(wd, "processed-data/processed-data-full.RData", sep = "/")
#then load data
load(path)
# In order to not have to download all the data again, we skip the data collection section. All code chuncks, however, can be easily executed.
knitr::opts_chunk$set(eval = FALSE)
Since we need to merge/combine the data with GDP data to obtain expenditure data as a percentage of GDP (as opposed to Eurostat, OECD does not directly provide these data), we need to first get GDP data.
#We use output approach data measured in current prices (just like in the cofog data)
gdp_oecd <- get_dataset(dataset = "SNA_TABLE1",
filter = "AUS+AUT+BEL+CAN+CZE+DNK+EST+FIN+FRA+DEU+GRC+HUN+IRL+ISR+ITA+JPN+KOR+LVA+LTU+LUX+NLD+NZL+NOR+POL+PRT+SVK+SVN+ESP+SWE+CHE+GBR+USA.B1_GA.C",
pre_formatted = T,
start_time = 1980,
end_time = 2020)%>%
select(-c(TIME_FORMAT, TRANSACT, POWERCODE, OBS_STATUS))%>%
rename(GDP = obsValue)
# one problem here is that GDP is inflated for Ireland in particular (see also [here](https://www.ft.com/content/6c7a0c9a-1913-30a2-a317-24d2623e1865)), so one could alternatively use the modified gross national income calculated by the irish central bank
irish_mod_gni <- cso_get_data("N2024")%>%
filter(Item == "10. Modified gross national income at current market prices")%>%
select(-Statistic)%>%
pivot_longer(-c(Item), names_to = "obsTime")%>%
mutate(LOCATION = "IRL",
MEASURE = "C",
UNIT = "EUR")%>%
select(-Item)%>%
rename(GDP = "value") #not that we rename the modified GNP here to GDP for ease of merging
# we can now replace the data in the GDP dataset for Ireland after 1995 with those of the modified gnp dataset (before 1995 we don't have modified GNP data, but values were very similar still then)
gdp_oecd_mod <- gdp_oecd%>%
filter(!(LOCATION == "IRL" & obsTime>=1995))%>%
rbind(irish_mod_gni)
In order to minimize missing data, I compiled education spending from three different sources.
Cofog data 1
Unesco data provided by the Worldbank
3 The Comparative Political Dataset (CPDS) which draws on the Worldbank indicators
For cofog, I download the data for all countries in the sample since 1980. One way to go about this is to use just all education spending (090). However, since I want to combine these with Unesco data, it makes sense to include spending on family and children as well as it is part of the Unesco education expenditure data. This make the data more comparable.
As the manual explains:
“Both UOE and COFOG are based on ISCED. However, COFOG relies on ISCED-97 whilst UOE has adopted ISCED-2011. The main difference concerns COFOG level II 9.11 pre-primary education based on the ISCED-97 level 0. This corresponds to only a part of the new ISCED-2011 as it does not include early childhood educational development (ISCED level 01). The”enlarged” ISCED-2011 level 0 includes education expenditure at ISCED level 01 that COFOG classifies according to its main purpose as child care services under social protection, in group 10.4 family and children.”
Finally, to further increase data availability, I download data compiled by the CPDS, which draws on the World Development Indicators and has already interpolated the data. Sometimes, the (interpolated) values from the CPDS are more encompassing, sometimes the ones directly downloaded from the Worldbank/Unesco, but they are otherwise almost identical, at least for the first 3-4 digits.
# cofog
cofog_oecd <- get_dataset(dataset = "SNA_TABLE11",
filter = "AUS+AUT+BEL+CAN+CZE+DNK+EST+FIN+FRA+DEU+GRC+HUN+IRL+ISR+ITA+JPN+KOR+LVA+LTU+LUX+NLD+NZL+NOR+POL+PRT+SVK+SVN+ESP+SWE+CHE+GBR+USA.TLYCG.090+1004.GS13.C",
pre_formatted = T,
start_time = 1960,
end_time = 2020)%>%
select(-c(TIME_FORMAT, TRANSACT, SECTOR, POWERCODE, OBS_STATUS))%>% #remove invariant columns
rename(edu_exp = obsValue)%>%
group_by(LOCATION, obsTime)%>%
summarize(edu_exp = sum(edu_exp))
# combine these data with the gdp data
cofog_oecd <- full_join(cofog_oecd, gdp_oecd_mod, by = c("LOCATION", "obsTime"))%>%
arrange(LOCATION, obsTime)%>%
mutate(edu_exp_gdp = edu_exp/GDP,
obsTime = as.numeric(obsTime))%>%
select(LOCATION, obsTime, edu_exp, GDP, edu_exp_gdp)
# Unesco data on education expenditure
edu_exp_wb <- wbstats::wb(country = c(countries.iso),indicator = "SE.XPD.TOTL.GD.ZS", startdate = 1960, enddate = 2019)%>%
select(iso3c, date, value)%>%
rename("LOCATION" = iso3c,
obsTime = date,
edu_exp2_gdp = value)%>%
mutate(obsTime = as.numeric(obsTime),
edu_exp2_gdp = edu_exp2_gdp/100)
# CPDS data (we select interpolated and non-interpolated)
cpds_edu <- read_excel("raw-data/CPDS_1960-2019_Update_2021.xlsx")%>%
filter(year >1959,
country %in% countries.list | country == "USA")%>%
mutate(country = plyr::revalue(country, c("USA" = "United States")))%>%
dplyr::select(iso, year, educexp_gov, educexp_gov_ipol)%>%
mutate(educexp_gov = educexp_gov/100,
educexp_gov_ipol = educexp_gov_ipol/100)%>%
rename(LOCATION = iso,
obsTime = year)
We can then combine the CPDS and the directly downloaded Worldbank data and replace missing values with the interpolated ones from the CPDS.
Lastly, we can try to minimise missing data even further by combining these expenditure data with cofog data. We need to keep in mind, however, the differences between how the cofog and unesco data are collected (see section 4.4.3. Consistency with COFOG in the manual). If we opt for maximizing data points, we can combine the data as follows, keeping the worldbank data as the main indicator however. The correlation between the two measures is quite high (r = 0.83) but not perfect. We take the approach here to take the mean when we have both values available and take the one we have available if there is only one available. Because there are more data points available, we keep the combined data for robustness.
#first combine
edu_exp_wb%<>%
full_join(cpds_edu)%>%
arrange(LOCATION, obsTime)%>%
mutate(edu_exp2_gdp = ifelse(is.na(edu_exp2_gdp), educexp_gov_ipol, edu_exp2_gdp))%>%
select(-educexp_gov, educexp_gov_ipol)
# full combine (we keep the separate and combined education spending variables)
cofog_oecd <- full_join(cofog_oecd, edu_exp_wb, by = c("LOCATION", "obsTime"))%>%
arrange(LOCATION, obsTime)%>%
rowwise()%>%
mutate(edu_exp3_gdp = mean(c(edu_exp_gdp, edu_exp2_gdp)),
edu_exp3_gdp = ifelse(is.na(edu_exp3_gdp), edu_exp_gdp, edu_exp3_gdp),
edu_exp3_gdp = ifelse(is.na(edu_exp3_gdp), edu_exp2_gdp, edu_exp3_gdp))%>%
expss::apply_labels(
edu_exp_gdp = "Cofog Education Expenditure Data",
edu_exp2_gdp = "Worldbank Education Expenditure Data",
edu_exp3_gdp = "Combined Expenditure Data")
For R&D spending we use GBARD data, and, alternatively, specific categories (those directly relevant to knowledge-based capital). GBARD stands for government budget allocations for R&D (see here for a breakdown of the variables and here for the entire manual)
It is important to note that R&D spending is generally not covered by education spending (cofog manual: 3.10.46. Case 46 – R&D expenditure in universities); there might be some small issues with regard to how education and R&D spending are calculated (cofog manual: 3.10.38. Case 38 - funding of R&D activities as part of tertiary education studies), but those special cases should be negligible.
It also needs to be noted that combining cofog and GBARD data introduces a small inconsistency as GBARD data are based on the final budget of a year and not actual allocations in that year (4.1.3. Coherence of COFOG R&D data with R&D expenditure data). These should, however, be relatively negligible.
In addition to overall spending, I collected data on the following selected spending categories which are even more immediately relevant to knowledge-based capital accumulation than R&D generally - some countries, however, do not provide data on the different categories (for some years) but only overall spending data.
“NABS04” = Transport, telecommunication and other infrastructures “NABS05” = Energy “NABS06” = Industrial production and technology “NABS08” = Agriculture “NABS11” = Political and social systems, structures and processes “NABS12” = General advancement of knowledge: R&D financed from General University Funds (GUF) “NABS13” = General advancement of knowledge: R&D financed from other sources than GUF “NABS14” = Defence
It is also important to note that we ignore missing values here and summarize even if there are some values for subcategories missing (this is the case 43 times). For most of these cases, however, concern the NABS12 subcategory and often (especially in the case of Korea for which otherwise all observations would be missing) were assigned to a different subcategory, generally NABS13 (observation status K) or a slightly different methodology was used with similar effects (obs status D). We can therefore be confident that simply summing up gives in the vast majority of these anyway few cases the correct results and is preferable to discarding all information because information for one subcategory is missing.
# Download GBARD data, total expenditure in national currency, I already combine the different categories here, summing them up
gbard_oecd <- get_dataset(dataset = "GBARD_NABS2007",
filter = "AUS+AUT+BEL+CAN+CZE+DNK+EST+FIN+FRA+DEU+GRC+HUN+IRL+ISR+ITA+JPN+KOR+LVA+LTU+LUX+NLD+NZL+NOR+POL+PRT+SVK+SVN+ESP+SWE+CHE+GBR+USA._T.MIO_NAC",
pre_formatted = T,
start_time = 1960,
end_time = 2020)%>%
select(c(COUNTRY, SEO, obsTime, obsValue))%>%
group_by(COUNTRY, obsTime)%>%
summarise(obsValue = sum(obsValue, na.rm = T))%>%#see comment above
rename(GBARD = obsValue,
LOCATION = COUNTRY)%>%
mutate(obsTime = as.numeric(obsTime))
# alterantive with specific categories
gbard_oecd_sel <- get_dataset(dataset = "GBARD_NABS2007",
filter = "AUS+AUT+BEL+CAN+CZE+DNK+EST+FIN+FRA+DEU+GRC+HUN+IRL+ISR+ITA+JPN+KOR+LVA+LTU+LUX+NLD+NZL+NOR+POL+PRT+SVK+SVN+ESP+SWE+CHE+GBR+USA.NABS04+NABS05+NABS06+NABS08+NABS11+NABS14+NABS12+NABS13.MIO_NAC",
pre_formatted = T,
start_time = 1960,
end_time = 2020)%>%
select(c(COUNTRY, SEO, obsTime, obsValue))%>%
group_by(COUNTRY, obsTime)%>%
summarise(obsValue = sum(obsValue, na.rm = T))%>%#see comment above
rename(GBARD_sel = obsValue,
LOCATION = COUNTRY)%>%
mutate(obsTime = as.numeric(obsTime))
gbard_oecd <- gbard_oecd%>%
left_join(gbard_oecd_sel)
Expenditures on active labor market policies are collected from LMPEXP. They would have also been available from the unemployment and general labor affairs categories (see also cofog manual: 3.10.10. Case 10 – schooling to help people find a job) but only at the cost of mixing up passive and active lmp spending, in addition to data availability issues. Here, I therefore use the LMPEXP data to obtain expenditure data for active labor market policies in categories 20-70 (excluding the administrative category). These categories are:
Training
Employment incentives
Sheltered and supported employment and rehabilitation
Direct job creation
Start-up incentives
I get the data for all countries, for the two relevant categories, and in national currency (EXP) as opposed to percentage of gdp (EXPPCT) (in order to get somewhat more fine-grained data as the percentage values are rounded at two digits)
alp_oecd <- get_dataset(dataset = "LMPEXP",
filter = "AUS+AUT+BEL+CAN+CZE+DNK+EST+FIN+FRA+DEU+GRC+HUN+IRL+ISR+ITA+JPN+KOR+LVA+LTU+LUX+NLD+NZL+NOR+POL+PRT+SVK+SVN+ESP+SWE+CHE+GBR+USA.112.EXP.A",
pre_formatted = T,
start_time = 1960,
end_time = 2020)%>%
select(-c("MEAS","FREQUENCY","TIME_FORMAT"))%>%
rename(LOCATION = LFS_COUNTRY,
alp_type = PROG,
alp_exp = obsValue)%>%
mutate(obsTime = as.numeric(obsTime))
Combining these data gives use the the dependent variable, but we only do this after the multiple imputations. For now, we only do some more data cleaning.
# merge all the dataframes created so far
dig_index <- cofog_oecd%>%
left_join(gbard_oecd, by = c("LOCATION", "obsTime"))%>%
left_join(alp_oecd, by = c("LOCATION", "obsTime")) %>%
rename(Country = LOCATION,
Year = obsTime)%>%
mutate(Year = as.numeric(Year))%>%
mutate(Country = countrycode(Country, 'iso3c', 'country.name'))%>%
mutate(rd_gdp = GBARD/GDP,
rd_gdp_sel = GBARD_sel/GDP,
alp_gdp = alp_exp/GDP) %>%
select(Country, Year, rd_gdp, rd_gdp_sel, edu_exp_gdp, edu_exp2_gdp, edu_exp3_gdp, alp_gdp, GDP)
For getting the party positions, I first follow the excellent script by Dimiter Thoskov which combines manifesto data with ParlGov data.
I calculate the emphasis measure based on several items (for the CMP codebook, see here):
per404 Economic Planning Favourable mentions of long-standing economic planning by the government. May be: • Policy plans, strategies, policy patterns etc.; • Of a consultative or indicative nature.
per410 Economic Growth: Positive The paradigm of economic growth. Includes: • General need to encourage or facilitate greater production; • Need for the government to take measures to aid economic growth.
per411 Technology and Infrastructure: Positive Importance of modernisation of industry and updated methods of transport and communication. May include: • Importance of science and technological developments in industry; • Need for training and research within the economy (This does not imply education in general (see category 506); • Calls for public spending on infrastructure such as roads and bridges; • Support for public spending on technological infrastructure (e.g.: broadband internet, etc.).
per506 Education Expansion Need to expand and/or improve educational provision at all levels. Note: This excludes technical training which is coded under 411.
#first, define functions
#basic functions
#make a number from a character vector and round it
make.number<-function (x, y) {round(as.numeric(as.character(x)), digits=y)}
sum.na<-function (x) sum(x, na.rm=T) #sum that aviods NAs, returns 0 if all NAs
sum.allna <- function(x) if (all(is.na(x))) NA else sum(x,na.rm=T) #sum that avoids NAs but returns NA if all NAs
rowsum.na<-function (x) rowSums(x, na.rm=T) #sum by row that avoids NAs
rowsum.allna <- function(x) rowSums(x, na.rm=TRUE) * ifelse(rowSums(is.na(x)) == ncol(x), NA, 1) #sum by row that avoids NAs but gives NA for a row with all NAs
mean.na<-function (x) mean(x, na.rm=T) #sum that aviods NAs, returns infinity if all NAs
mean.allna <- function(x) if (all(is.na(x))) NA else mean(x,na.rm=T) #sum that avoids NAs but returns NA if all NAs
min.na<-function (x) min(x, na.rm=T) #sum that aviods NAs, returns 0 if all NAs
min.allna <- function(x) if (all(is.na(x))) NA else min(x,na.rm=T) #sum that avoids NAs but returns NA if all NAs
max.na<-function (x) max(x, na.rm=T) #sum that aviods NAs, returns 0 if all NAs
max.allna <- function(x) if (all(is.na(x))) NA else max(x,na.rm=T) #sum that avoids NAs but returns NA if all NAs
#party position functions
# Party position and salience calculation ---------------------------------
pos.add<-function (x=NA,y=NA, data=cabinets) {
pos = if (is.na(y[1]))
rowsum.allna(data[, x, drop=F])
else if (is.na(x[1]))
-rowsum.allna(data[, y, drop=F])
else
rowsum.allna(data[, x, drop=F])-rowsum.allna(data[, y, drop=F])
pos
}
pos.add.sal<-function (x=NA, ..., data=cabinets) {
pos = rowsum.allna(data[, x, drop=F])
pos
}
pos.add.n<-function (x=NA,y=NA, data=cabinets) {
pos = if (is.na(y[1]))
round(rowsum.allna(data[,x, drop=F])*data[,'total']/100)
else if (is.na(x[1]))
-round(rowsum.allna(data[,y, drop=F])*data[,'total']/100)
else
round(rowsum.allna(data[,x, drop=F])*data[,'total']/100) - round(rowsum.allna(data[,y, drop=F])*data[,'total']/100)
pos
}
pos.add.n.sal<-function (x=NA, ..., data=cabinets) {
pos = round(rowsum.allna(data[,x, drop=F])*data[,'total']/100)
pos
}
pos.lbml<-function (x=NA,y=NA, data=cabinets) {
pos = if (is.na(y[1]))
log (round(rowsum.allna(data[, x, drop=F])*data[, 'total']/100) + 0.5) - log (0.5)
else if (is.na(x[1]))
- log (round(rowsum.allna(data[, y, drop=F])*data[, 'total']/100) + 0.5) + log (0.5)
else
log((round(rowsum.allna(data[, x, drop=F])*data[, 'total']/100) + 0.5)) - log((round(rowsum.allna(data[, y, drop=F])*data[, 'total']/100) + 0.5))
pos
}
pos.kf<-function (x=NA,y=NA, data=cabinets) {
pos = (round(rowsum.allna(data[,x, drop=F])*data[,'total']/100) - round(rowsum.allna(data[,y, drop=F])*data[,'total']/100))/
(round(rowsum.allna(data[,x, drop=F])*data[,'total']/100) + round(rowsum.allna(data[,y, drop=F])*data[,'total']/100))
pos
}
pos.lbml.sal<-function (x=NA, ..., data=cabinets) {
pos = log((round(rowsum.allna(data[, x, drop=F])*data[, 'total']/100) + 1)/ data[, 'total'])
pos
}
# Party position and salience wrap-up ---------------------------------
party.pos<-function (x=NA,y=NA, data=cabinets, method = pos.add, name = 'position', output = 'table', start='1945-01-01', end='2018-12-31', countries=countries.list, start_col='election_date', end_col='election_date', country_col='country_name.y', party_col='partyname') {
data<-data.frame(data)
dataset<- data%>%filter(data[,start_col] >= start & data[,end_col] <= end & data[,country_col]%in%countries) #filter for the required time and geo scope
temp = method (x,y, data=dataset) #run the party position calculation function
if (output=='vector'){
assign(name, temp, envir = .GlobalEnv)
return (temp)}
else if (output=='attach'){
data.out<-cbind(dataset, temp)
colnames(data.out)[ncol(data.out)]<-name
return(data.out)}
else if (output=='table'){
data.out<-cbind(dataset, temp)
data.out = data.out[,c(country_col, start_col, party_col, 'temp')]
colnames(data.out)[1:4]<-c('country','election.date', 'party.name', name)
data.out<-data.out[order(data.out$country, data.out$election.date),]
return(data.out)}
}
# government position functions (not from source because this executes new countries.list)
gov.pos<-function (x=NA,y=NA, data=cabinets, method = pos.add, name ='position', start='1945-01-01', end='2018-12-31', countries=countries.list) {
dataset2 = party.pos(x=x, y=y, data=data, method=method, output='attach') #calculate the party score and attach to the dataframe
colnames(dataset2)[ncol(dataset2)]<-'party.score' #rename the last column temporarity
dataset2<- dataset2%>%
filter(election_date > start & election_date < end & country_name.y%in%countries & cabinet_party==1)%>%
select(cabinet_id, seats_share,country_name.y,start_date,end_date,election_date, party.score)
#first, create a variable that calculates the party seats share from all parties in government *that have a valid position*
for (i in unique(dataset2$cabinet_id)){
dataset2[dataset2$cabinet_id==i,'rel_seats_share'] = dataset2[dataset2$cabinet_id==i,'seats_share'] / sum.allna(dataset2[dataset2$cabinet_id==i & !is.na(dataset2$party.score),'seats_share'])
}
#now aggregate per cabinet
m = dataset2%>% group_by(cabinet_id) %>% summarise(country=country_name.y[1], election.date=election_date[1],
start.date = start_date[1], end.date = end_date[1],
simple.mean = round(mean.allna(party.score),2),
weighted.mean = round(weighted.mean(party.score, rel_seats_share, na.rm=T),2),
minimum = round(min.allna(party.score),2),
maximum = round(max.allna(party.score),2),
range = abs (round(max.allna(party.score),2) -round(min.allna(party.score),2)),
parties.number = n(),
share.missing = round(sum.na(seats_share[is.na(party.score)])/sum.na(seats_share)*100,0)
)
m<-m[order(m$country, m$start.date),]
m
}
# Aggregation over time ---------------------------------------------------
gov.pos.time <-function (x=NA,y=NA, data=cabinets, method = pos.add, name ='position', start='1945-01-01', end='2019-12-31', countries=countries.list, time='month') {
dat<-gov.pos (x=x,y=y, data=data, method=method, countries=countries,start='1945-01-01', end='2019-12-31')
dat$startY<-year(dat$start.date)
dat$startYM<-as.yearmon(dat$start.date)
dat$endY<-year(dat$end.date)
dat$endYM<-as.yearmon(dat$end.date)
u.c<-countries
u.m<-as.yearmon(seq.Date(from=as.Date(start), to=as.Date(end), by='month'))
month.table<-expand.grid(u.c, u.m)
colnames(month.table)<-c('country','month.year')
month.table$simple.mean<-NA
month.table$weighted.mean<-NA
month.table$minimum<-NA
month.table$maximum<-NA
month.table$range<-NA
month.table$parties.number<-NA
month.table$share.missing<-NA
for (i in 1:nrow(month.table)){
try(month.table[i, 3:9] <-dat[which(dat$country==month.table$country[i] & dat$startYM <= month.table$month.year[i] & dat$endYM > month.table$month.year[i]), 6:12], silent=TRUE)
}
month.table<-month.table[order(month.table$country, month.table$month.year),]
if (time=='month'){
return (month.table)}
else if (time=='year'){
month.table$year<-year(month.table$month.year)
month.table$index<-paste0(month.table$country, '.', month.table$year)
year.table = month.table%>% group_by(index) %>% summarise(country=country[1], year= year[1],
simple.mean = mean.allna(simple.mean),
weighted.mean = mean.allna(weighted.mean),
minimum = mean.allna(minimum),
maximum = mean.allna(maximum),
range = mean.allna(range),
parties.number = mean.allna(parties.number),
share.missing = mean.allna(share.missing))
return (year.table)
}
}
#then get the manifesto corpus
mp_setapikey(key.file = "manifesto_apikey.txt")
manifestos <- mp_maindataset()
#and the parlgov data
# load ParlGov party-level file
parties<-read_csv("https://www.parlgov.org/data/parlgov-development_csv-utf-8/view_party.csv")
# load ParlGov cabinets-level file
cabs <-read_csv("https://www.parlgov.org/data/parlgov-development_csv-utf-8/view_cabinet.csv")
#subset only relevant columns
#(should include more info also on left-right, etc.)
parties %<>%
select(country_name, party_name_english, party_id, cmp)
cabs %<>%
select(
country_name,
party_name_english,
party_id,
cabinet_id,
previous_cabinet_id,
cabinet_name,
election_date,
start_date,
cabinet_name,
cabinet_party,
seats,
election_seats_total)
#subset the datasets for the EU+ countries only
manifestos <- manifestos %>% filter(countryname %in% countries.list)
parties <- parties %>% filter(country_name %in% countries.list)
cabs <- cabs %>% filter(country_name %in% countries.list,
election_date>'1970-01-01')
#create country_list with iso names for later combination with party facts
countries.iso <- countrycode(countries.list, 'country.name', 'iso3c')
cabs$election_date <- as.character(cabs$election_date)
#election date changes: these changes align the election dates between the Manifesto and ParlGov datasets
cabs[cabs$country_name=='Poland' & cabs$election_date=='2007-10-19', 'election_date']<-"2007-10-21"
cabs[cabs$country_name=='Hungary' & cabs$election_date=='1990-04-08', 'election_date']<-"1990-03-25"
cabs[cabs$country_name=='Hungary' & cabs$election_date=='1994-05-29', 'election_date']<-"1994-05-08"
cabs[cabs$country_name=='Hungary' & cabs$election_date=='1998-05-24', 'election_date']<-"1998-05-10"
cabs[cabs$country_name=='Hungary' & cabs$election_date=='2002-04-21', 'election_date']<-"2002-04-07"
cabs[cabs$country_name=='Hungary' & cabs$election_date=='2010-04-25', 'election_date']<-"2010-04-11"
cabs[cabs$country_name=='Czech Republic' & cabs$election_date=='1996-06-01', 'election_date']<-"1996-05-31"
cabs[cabs$country_name=='Czech Republic' & cabs$election_date=='1998-06-20', 'election_date']<-"1998-06-19"
cabs[cabs$country_name=='Czech Republic' & cabs$election_date=='2002-06-15', 'election_date']<-"2002-06-14"
cabs[cabs$country_name=='Czech Republic' & cabs$election_date=='2013-10-25', 'election_date']<-"2013-10-26"
cabs[cabs$country_name=='Lithuania' & cabs$election_date=='1992-11-15', 'election_date']<-"1992-10-25"
cabs[cabs$country_name=='Lithuania' & cabs$election_date=='2004-10-24', 'election_date']<-"2004-10-10"
cabs[cabs$country_name=='Latvia' & cabs$election_date=='1993-06-06', 'election_date']<-"1993-06-05"
cabs[cabs$country_name=='Latvia' & cabs$election_date=='1995-10-01', 'election_date']<-"1995-09-30"
cabs[cabs$country_name=='Slovakia' & cabs$election_date=='1994-10-01', 'election_date']<-"1994-09-30"
cabs[cabs$country_name=='Slovakia' & cabs$election_date=='2002-09-21', 'election_date']<-"2002-09-20"
cabs[cabs$country_name=='Slovenia' & cabs$election_date=='1990-04-12', 'election_date']<-"1990-04-08"
cabs[cabs$country_name=='Italy' & cabs$election_date=='1992-04-05', 'election_date']<-"1992-04-06"
cabs[cabs$country_name=='Italy' & cabs$election_date=='1994-03-27', 'election_date']<-"1994-03-28"
cabs[cabs$country_name=='Italy' & cabs$election_date=='2006-04-09', 'election_date']<-"2006-04-10"
cabs[cabs$country_name=='Italy' & cabs$election_date=='2013-02-25', 'election_date']<-"2013-02-24"
cabs[cabs$country_name=='Belgium' & cabs$election_date=='1949-06-26', 'election_date']<-"1949-06-29"
cabs[cabs$country_name=='France' & cabs$election_date=='1958-11-30', 'election_date']<-"1958-11-23"
cabs[cabs$country_name=='France' & cabs$election_date=='1962-11-25', 'election_date']<-"1962-11-18"
cabs[cabs$country_name=='France' & cabs$election_date=='1967-03-12', 'election_date']<-"1967-03-05"
cabs[cabs$country_name=='France' & cabs$election_date=='1968-06-30', 'election_date']<-"1968-06-23"
cabs[cabs$country_name=='France' & cabs$election_date=='1973-03-11', 'election_date']<-"1973-03-04"
cabs[cabs$country_name=='France' & cabs$election_date=='1978-03-19', 'election_date']<-"1978-03-12"
cabs[cabs$country_name=='France' & cabs$election_date=='1981-06-21', 'election_date']<-"1981-06-14"
cabs[cabs$country_name=='France' & cabs$election_date=='1988-06-12', 'election_date']<-"1988-06-05"
cabs[cabs$country_name=='France' & cabs$election_date=='1993-03-28', 'election_date']<-"1993-03-21"
cabs[cabs$country_name=='France' & cabs$election_date=='1997-06-01', 'election_date']<-"1997-05-25"
cabs[cabs$country_name=='France' & cabs$election_date=='2002-06-16', 'election_date']<-"2002-06-09"
cabs[cabs$country_name=='France' & cabs$election_date=='2007-06-17', 'election_date']<-"2007-06-10"
cabs[cabs$country_name=='France' & cabs$election_date=='2012-06-17', 'election_date']<-"2012-06-10"
cabs[cabs$country_name=='France' & cabs$election_date=='2017-06-18', 'election_date']<-"2017-06-11"
cabs[cabs$country_name=='Sweden' & cabs$election_date=='1998-09-20', 'election_date']<-"1998-09-21"
cabs[cabs$country_name=='Sweden' & cabs$election_date=='1956-09-16', 'election_date']<-"1956-09-26"
cabs[cabs$country_name=='Finland' & cabs$election_date=='1979-03-19', 'election_date']<-"1979-03-13"
cabs[cabs$country_name=='Ireland' & cabs$election_date=='1954-05-18', 'election_date']<-"1954-04-18"
cabs[cabs$country_name=='Ireland' & cabs$election_date=='1969-06-18', 'election_date']<-"1969-06-16"
#cabs[cabs$country_name=='Netherlands' & cabs$election_date=='1971-04-28', 'election_date']<-"1971-03-28"
cabs[cabs$country_name=='Slovakia' & cabs$election_date=='2016-03-06', 'election_date']<-"2016-03-05"
cabs[cabs$country_name=='Iceland' & cabs$election_date=='1949-10-24', 'election_date']<-"1949-10-23"
cabs[cabs$country_name=='Iceland' & cabs$election_date=='1959-10-26', 'election_date']<-"1959-10-25"
cabs[cabs$country_name=='Iceland' & cabs$election_date=='1979-12-03', 'election_date']<-"1979-12-02"
table(is.na(parties$cmp)) #how many cmp codes are missing?
#get additional CMP codes if the party names match exactly
parties$cmp2<-parties$cmp #first create a copy of the cmp variable
#for each row in parties, if the cmp code is NA and if the corresponding party name in Manifestos is not NA and the country is the same, record it in cmp2
for (i in 1:nrow(parties)){
if (is.na(parties$cmp)==T)
if (is.na(as.data.frame(manifestos[manifestos$countryname==parties$country_name[i] & manifestos$partyname==parties$party_name_english[i], 'party'][1,]))==T)
next
else
parties$cmp2[i]<-as.data.frame(manifestos[manifestos$countryname==parties$country_name[i] & manifestos$partyname==parties$party_name_english[i], 'party'][1,])
else
next
}
parties$cmp2<-as.numeric(parties$cmp2)
table(is.na(parties$cmp2)) #how many cmp codes are still missing? There is an improvement, but still a lot
source('https://raw.githubusercontent.com/demetriodor/govpositions/master/cmp%20code%20corrections.R')
table(is.na(parties$cmp2)) #there is progress but we can still do better
#using the newly relased Party Facts data
#get the data
file_name <- "partyfacts-mapping.csv"
url <- "https://partyfacts.herokuapp.com/download/external-parties-csv/"
download.file(url, file_name)
partyfacts <- read_csv(file_name, guess_max = 30000)
#select EU+ countries of interset
partyfacts<-partyfacts %>% filter(country %in% countries.iso)
#subset and join manifesto and parlgov data
dataset_1 <- partyfacts %>% filter(dataset_key == "manifesto")
dataset_2 <- partyfacts %>% filter(dataset_key == "parlgov")
links <- dataset_1 %>% inner_join(dataset_2, by = c("partyfacts_id" = "partyfacts_id"))
links<-links[,c('dataset_party_id.x','dataset_party_id.y')]
colnames(links)<-c('mani','parlgov')
## for some parties, there are more than one Manifesto code for each Parlgov code. Most of these are not missing a cmp code but two parties are.
## (and seven would have been before our custom corrections above)
## We filter so that there is a one-to-one match. As we are not sure which cmp to keep, we just keep the first encountered one
## the code below can be used to inspect these duplicate cases
#temp<-unique(links$parlgov[which(duplicated(links$parlgov)==T)])
#temp2<-parties[is.na(parties$cmp2),]
#temp3<-parties[is.na(parties$cmp),]
#temp[which(temp%in%temp2$party_id==T)]
#temp[which(temp%in%temp3$party_id==T)]
links<-links[!duplicated(links[,c('parlgov')]),]
#merge with the parties data
parties<-merge(parties, links, by.y='parlgov', by.x='party_id', all.x=T)
#if the cmp code is still missing in parties but is not missing in the party facts dataset, impute it
parties$cmp2[is.na(parties$cmp2) & !is.na(parties$mani)]<-parties$mani[is.na(parties$cmp2) & !is.na(parties$mani)]
parties$cmp2<-make.number(parties$cmp2)
table(is.na(parties$cmp2)) #how are we doing? altogether, better (filled in 161 parties in total) but far from perfect match
# Merge parties and cabinets
parties$party<-parties$cmp2 #copy the column to use for merge
manipart<-merge(manifestos, parties, by="party") #keep only observations that have CMP codes in ParlGov
manipart$new_id<-paste0(manipart$party_id, ".", manipart$edate) #index variable
cabs$new_id<-paste0(cabs$party_id, '.',cabs$election_date) #index variable
cabinets<-merge(manipart, cabs, by="new_id", all.y=T) #merge parties and cabinets
#additional variables which will be useful later
cabinets$seats_share <- (cabinets$seats / cabinets$election_seats_total) * 100 #calculate party seat share
#put the end dates of the cabinets in the file, based on the starting date of the next cabinet
for (i in 1:nrow(cabinets)){
cabinets$end_date[i]<-cabinets$start_date[cabinets$previous_cabinet_id==cabinets$cabinet_id[i] & !is.na(cabinets$previous_cabinet_id)][1]
}
cabinets$end_date<-as_date(cabinets$end_date-1)
#create end date for governments that are still governing
cabinets$end_date<-as_date(ifelse(is.na(cabinets$end_date) == T, 18414, cabinets$end_date )) #(18414 represents "2020-06-01")
# The parl-gov file does not contain data for the US, I don't really know why. So we add these data manually (I could not find them anywhere, though they should exist). The dataframe us_cabs is created here; we first import the data from the comparative political dataset on government composition and clean them quite extensively to have data comparable to those of the parlgov cabinet data
CPDS_cabin <- read_excel("raw-data/Government_Composition_1960-2019_Update_2021.xlsx", sheet = "United States", skip = 3, col_types = c("text",
"date", "text", "text", "text", "text",
"text", "text", "text", "text", "text",
"text", "text", "text", "text", "text",
"text", "text", "text", "date", "text",
"text", "text", "text", "text", "text",
"text", "text", "text", "text", "text",
"text", "text", "text", "text", "text",
"text", "text", "text", "text", "text",
"text", "text", "text", "text", "text",
"text", "text", "text", "text", "text",
"text", "text"))%>%
filter(!is.na(President))
us_cabs <- CPDS_cabin%>%
select(Year, President, `Investiture Date...2`, `Parliament. Election`, `Governing Party 1`)%>%
mutate(`Investiture Date...2` = as.Date(`Investiture Date...2`),
`Parliament. Election` = as.Date(`Parliament. Election`))%>%
mutate(countryname = "United States")%>%
slice_head(n = 132)%>%# that is because after the 80th row, other data start because of weird formatting of the excel sheet
rename(edate = `Parliament. Election`,
start_date = `Investiture Date...2`,
cabinet_name = President)%>%
mutate(edate = ifelse(start_date == "2017-01-20", ymd("2016-11-08"), edate),
edate = as.Date(edate))%>%#add trump election date which is missing
mutate(edate = na.locf(edate, na.rm = F, fromLast = F))%>%
distinct(cabinet_name, .keep_all = T)%>%
group_by(cabinet_name)%>%
mutate(cabinet_id = cur_group_id())%>%
ungroup()%>%
mutate(previous_cabinet_id = lag(cabinet_id)) %>%
mutate(end_date = lead(start_date, n = 1, default = Sys.Date()) - 1) %>%
left_join(manifestos %>% select(edate, countryname, partyname, absseat, totseats)) %>%
group_by(partyname) %>%
mutate(party_id = cur_group_id()) %>%
mutate(cabinet_name = str_sub(cabinet_name, end = -6)) %>%
rename(gov_par = `Governing Party 1`) %>%
mutate(cabinet_party = ifelse(
gov_par == "RP" &
partyname == "Republican Party",
1,
ifelse(gov_par == "DP" & partyname == "Democratic Party",
1,
0)
))%>%
rename(
party_name_english = partyname,
election_date = edate,
country_name = countryname,
seats = absseat,
election_seats_total = totseats
)%>%
mutate(seats_share = (seats/election_seats_total) * 100)%>%
mutate(election_date = as.character(election_date))%>%
ungroup()%>%
select(
country_name,
party_name_english,
party_id,
cabinet_id,
previous_cabinet_id,
cabinet_name,
election_date,
start_date,
end_date,
cabinet_name,
cabinet_party,
seats,
election_seats_total,
seats_share)
#we then use the manifest corpus (downloaded above as it is also used for the other countries) and select data fro the US
manifestos_us <- manifestos%>%
filter(countryname == "United States",
edate > '1970-01-01')%>%
rename(country_name = countryname,
election_date = edate,
party_name_english = partyname)%>%
mutate(election_date = as.character(election_date))
# we then merge the cabinet with the manifest data
cabinets_us <- left_join(us_cabs, manifestos_us , by = c("country_name", "election_date", "party_name_english"))%>%
rename(country_name.y = country_name,
party_id.y = party_id,
party_name_english.y = party_name_english)#rename to make compatible with the relevant columns in the cabinets data (party_name_english.y is the more comprehensive version of party_name_english.x, for example)
# we then join the data together, no we have the cabinet data also for the us
cabinets <- full_join(cabinets_us, cabinets)
#Now we can calculate cabinet (or also party) positions based on the salience placed on the different items described above
government_positions_digital <- data.frame(gov.pos.time(x=c("per404", "per410", "per411", "per506"), y = "per507", method = pos.add.sal, data = cabinets, start='1970-01-01', end='2018-12-31', time = "year", countries = c(countries.list)))%>%
select(country, year, weighted.mean)%>%
rename(investment_weighted = weighted.mean)
# Here I extract government positions on the rile left-right indicator
government_positions_leftright <- data.frame(gov.pos.time(x = 'rile', method = pos.add, start='1970-01-01', end='2018-12-31', data = cabinets, time = "year", countries= c(countries.list)))%>%
select(country, year, weighted.mean)%>%
rename(rile_weighted = weighted.mean)
# I then combine these data into a single dataframe which we then merge with other variables and prepare for merging with the main data
# I also delete data older than 1980 only here, because doing it earlier, i.e. via the elections dates could mean that we lose some of the coded information for the years after
government_positions <- government_positions_digital%>%
left_join(government_positions_leftright)%>%
rename(Country = country,
Year = year)%>%
mutate(Country = as.character(Country))%>%
filter(Year >=1980)%>%
expss::apply_labels(
rile_weighted = "Weighted RILE score",
investment_weighted = "Weighted Emphasis put on Investment Categories")
I now need to merge information on an annual basis with cabinet information, that is, we need to assign cabinets to years. Some years will have multiple cabinets and therefore we need to select those that were in office in that year for the highest amount of days. I first use the start day variable to create and end day variable, which is just the start date of the next cabinet minus 1. For the most recent cabinets I just used the current date as the end date. I then add new variables based on the days in between start and end date, create a new variable years in office to see which cabinet had spent most time in a given year (also newly created based on the date). Finally I just see who spend most days in office in any given year and assign that year to the respective government.
cabinet_years <- cabs %>%
full_join(us_cabs %>%
select(-c(seats_share, end_date))%>%
filter(election_date>"1970-01-01"))%>%
group_by(country_name, cabinet_name) %>%
distinct(cabinet_name, .keep_all = T) %>%
select(country_name, cabinet_name, start_date)%>%
group_by(country_name) %>%
mutate(end_date = lead(start_date, n = 1, default = Sys.Date()) - 1)%>%
transmute(
cabinet_name = cabinet_name,
country_name = country_name,
year = map2(start_date, end_date, ~ seq(.x, .y, by = 'day'))
) %>%
unnest()%>%
mutate(Year = as.numeric(str_sub(year, 1, 4))) %>%
group_by(Year, country_name, cabinet_name) %>%
mutate(days_in_office = length(cabinet_name)) %>%
distinct(country_name, days_in_office)%>%
group_by(Year, country_name) %>%
filter(days_in_office == max(days_in_office))%>%
rename(Country = country_name)%>%
select(-days_in_office)
Next, I add the share of social democratic and other left parties in government. I select the share of left parties in government from the CPDS dataset: “Government composition:relative power position of social democratic and other left parties in government based on their seat share in parliament, measured in percentage of the total parliamentary seat share of all governing parties. Weighted by the number of days in office in a given year.”
share_left <- read_excel("raw-data/CPDS-1960-2017-Update-2019.xlsx")%>%
filter(year >1959,
country %in% countries.list | country == "USA")%>%
select(year, country, gov_left2)%>%
rename(Year = year,
Country = country)%>%
expss::apply_labels(
gov_left2 = "Share Left Parties Government")%>%
mutate(Country = plyr::revalue(Country, c("USA" = "United States")))
To get a bit more fine-grained information that contained in the CPDS, I get party families by merging cabinet data with the parlgov parties data (and add party families for Republicans and Democrats manually). The data not only allow for filtering for other party families than social democrats but also take into account the actual seat share of social democrats as opposed to left parties generally. For example, for the Schröder II government in Germany, the CPDS data give 100% as the cabinet was composed of social democrats and greens whereas my variable 82% reflecting the share of social democrats in government.
# In the first step, I get the cabinet data and calculate the seat share of the different parties so as to get the seat share for social democratic (or other parties) parties later. IMPORTANT. We do not use the seat share of these parties overall (seats/elections_seats_total) but rather the share of those parties of the government. We do this by adding up all the seats of cabinet parties (which we filtered for).
cabinet_families <- cabs %>%
filter(cabinet_party == 1)%>%
full_join(us_cabs %>%
select(-c(seats_share, end_date))%>%
filter(election_date>"1970-01-01"))%>%
group_by(country_name, cabinet_name, party_name_english) %>%
distinct(cabinet_name, .keep_all = T)%>%
select(country_name, cabinet_name, party_name_english, seats, election_seats_total)%>%
group_by(country_name, cabinet_name)%>%
mutate(gov_seats_total = sum(seats))%>%
group_by(country_name, cabinet_name, party_name_english)%>%
mutate(gov_seat_share = (seats/gov_seats_total)*100)%>%
select(country_name, cabinet_name, party_name_english, gov_seat_share)
# now party families and then merge and manually adding data for the US
parties_families <-
read_csv("https://www.parlgov.org/data/parlgov-development_csv-utf-8/view_party.csv") %>% filter(country_name %in% countries.list)%>%
select(country_name, party_name_english, family_name)
cabinet_parties_families <- left_join(cabinet_families, parties_families)%>%
mutate(family_name = ifelse(country_name == "United States" & party_name_english == "Republican Party", "Conservative", ifelse(country_name == "United States" & party_name_english == "Democratic Party", "Liberal", family_name)))
#now we can just filter for social democracy and just to check if there are two social democratic parties in one government also look if a grouped distinct call gets rid of some observations which is not the case.
cabinet_parties_families%<>%
filter(family_name == "Social democracy")%>%
group_by(country_name, cabinet_name, party_name_english)%>%
distinct(party_name_english, .keep_all = T)%>%
mutate(gov_seat_share = sum(gov_seat_share))%>%
ungroup()%>%
rename(Country = country_name)%>%
select(Country, cabinet_name, gov_seat_share)
Finally, I merge the different datasets together.
# Note that government seat_share will be NA for cabinets that don't have social democrats in them (we filtered them out before). As the social-democratic government seat share is by definition 0 here we just assign zero to these NAs
government_positions_full <- government_positions %>%
left_join(cabinet_years)%>%
left_join(share_left)%>%
left_join(cabinet_parties_families)%>%
mutate(Country = plyr::revalue(Country, c("Czech Republic" = "Czechia")))%>%
mutate(gov_seat_share = ifelse(is.na(gov_seat_share), 0, gov_seat_share))
I reconstructed and updated Jahn’s (2016) index of corporatism based on ICTWSS database developed by Visser (2019).
Following Jahn, I used the following variables:
CENT: Summary measure of centralisation of wage bargaining (0-1) = CENTconf + CENTunion weighting the degree of authority or vertical coordination in the union movement and union concentration or horizontal coordination, taking account of multiple levels at which bargaining can take place and assuming a non-zero division of union authority over different levels (see Visser, 1990; Iversen, 1999). Taking the square root serves to magnify the differences at the low end of this scale (CF. Iversen, 1999: 53)
WC_struct: structure of works council representation 4 = single-channel works councils, union-based representation, elected by union members or established by union, based on law or national agreement 3 = dual-channel works councils, union dominated representation, elected by union and non-union members, based on law or national agreement 2 = split-channel works councils, employee elected works councils are mandatory where there is no or insufficient union representation, as a structure supplementary to the union, based on law or national agreement 1 = single-channel works councils, union-based representation, established by local agreement, no legal provisions for representation if no union is present or recognized; 0 = works council or similar (union or non-union) based institutions of employee representation confronting management do not exist or are exceptional.
WC_rights: rights of works councils 3 = economic and social rights, including codetermination on some issues (e.g., mergers, take-overs, restructuring, etc.) 2 = economic and social rights, consultation (advice, with possibility of judicial redress) 1 = information and consultation rights (without judicial redress) 0 = works council or similar (union or non-union) based institutions of employee representation confronting management do not exist or are exceptional.
Govint: government intervention in wage bargaining 5 = the government imposes private sector wage settlements, places a ceiling on bargaining outcomes or suspends bargaining; 4 = the government participates directly in wage bargaining (tripartite bargaining, as in social pacts); 3 = the government influences wage bargaining outcomes indirectly through priceceilings, indexation, tax measures, minimum wages, and/or pattern setting through public sector wages; 2 = the government influences wage bargaining by providing an institutional framework of consultation and information exchange, by conditional agreement to extend private sector agreements, and/or by providing a conflict resolution mechanism which links the settlement of disputes across the economy and/or allows the intervention of state arbitrators or Parliament; 1 = none of the above.
Level: The predominant level at which wage bargaining takes place (in terms of coverage of employees) 5 = bargaining predominantly takes place at central or cross-industry level negotiated at lower levels; 4 = intermediate or alternating between central and industry bargaining; 3 = bargaining predominantly takes place at the sector or industry level; 2 = intermediate or alternating between sector and company bargaining; 1 = bargaining predominantly takes place at the local or company level [A level is ‘predominant’ if it accounts for at least two-thirds of the total bargaining coverage rate in a given year. If it accounts for less, but for more than one-third of the coverage rate, there is a mixed or intermediate situation, between two levels. A mixed situation also occurs when bargaining levels alternate and/or it is impossible to assess which of the two contributes more to the actual coverage of agreements.]
RI: routine involvement of unions and employers in government decisions on social and economic policy. 2 = full concertation, regular and frequent involvement; 1 = partial concertation, irregular and infrequent involvement; 0 = no concertation, involvement is rare or absent
Coord: coordination of wage-setting 5 = Binding norms regarding maximum or minimum wage rates or wage increases issued as a result of a) centralized bargaining by the central union and employers’ associations, with or without government involvement, or b) unilateral government imposition of wage schedule/freeze, with or without prior consultation and negotiations with unions and/or employers’ associations. 4 = Non-binding norms and/or guidelines (recommendations on maximum or minimum wage rates or wage increases) issued by a) the government or government agency, and/or the central union and employers’ associations (together or alone), or b) resulting from an extensive, regularized pattern setting coupled with high degree of union concentration and authority. 3 = Procedural negotiation guidelines (recommendations on, for instance, wage demand formula relating to productivity or inflation) issued by a) the government or government agency, and/or the central union and employers’ associations (together or alone), or b) resulting from an extensive, regularized pattern setting coupled with high degree of union concentration and authority. 2 = Some coordination of wage setting, based on pattern setting by major companies, sectors, government wage policies in the public sector, judicial awards, or minimum wage policies. 1 = fragmented wage bargaining, confined largely to individual firms or plants, no coordination [Refers to the private sector, across branches or sectors; based on Kenworthy (2001a; 2001b). Note that this is an indicator of the “degree, rather than the type, of coordination” (Kenworthy 2001a:78), (…) “based on a set of expectations about which institutional features of wage setting arrangements are likely to generate more or less coordination” (2001a:80).]
Ext: Mandatory extension of collective agreements to non-organised employers 3 = extension is virtually automatic and more or less general (including enlargement) 2 = extension is used in many industries, but there are thresholds and Ministers can (and sometimes do) decide not to extend (clauses in) collective agreements 1 = extension is rather exceptional, used in some industries only, because of absence of sector agreements, very high thresholds (supermajorities of 60_ or more, public policy criteria, etc.), and/or veto powers of employers 0 = there are neither legal provisions for mandatory extension, nor is there a functional equivalent.
I also use social pact and agreement signed variables, which are in the do file but the article said were not used. As I believe them to be relevant, I included them.
# I load the ICTWSS database on Institutional Characteristics of Trade Unions, Wage Setting, State Intervention and Social Pacts (data go until 2018).
ICTWSS <- read_excel("raw-data/20191107_ICTWSS_6_1_Dataset.xlsx",
skip = 0) %>%
filter(
country %in% countries.list |
country == "United States of America" |
country == "Slovak Republic",
year > 1959
) %>%
select(
country,
year,
CENT,
WC_STRUCT,
WC_RIGHTS,
Govint,
Level,
RI,
Coord,
EXT,
PACTSIGN,
AGRSIGN
) %>%
mutate(country = plyr::revalue(country, c("United States of America" = "United States"))) %>%
mutate(country = plyr::revalue(country, c("Czech Republic" = "Czechia"))) %>%
mutate(country = plyr::revalue(country, c("Slovak Republic" = "Slovakia")))
# There are a few missing values for the variables making up the corporatism index. The safer strategy is to conservatively linearly interpolate a few missing values and use the closest values for the end points of the time series (which are often interpolated oddly). We also interpolate over a maximum gap of 3 years. I eliminate country-years with generally missing data (and not just for single variables. I then normalize the variables, add them together, and divide by the number of variables used (i.e. for which there was no missing data) to obtain the index. Thus, rather than assigning an arbitrary value in cases where not data is available for a subcomponent of the index, I just ignore them. The histogram below shows that the vast majority of country-year observations have 0 or 1 missing values on subcomponents.
corporatism_index<- ICTWSS%>%
group_by(country)%>%
mutate(dplyr::across(c(CENT, WC_STRUCT, WC_RIGHTS, Govint, Level, RI, Coord, EXT, PACTSIGN, AGRSIGN), na.approx,na.rm = F, maxgap = 3))%>%
mutate(dplyr::across(c(CENT, WC_STRUCT, WC_RIGHTS, Govint, Level, RI, Coord, EXT, PACTSIGN, AGRSIGN), na.locf, na.rm = F, maxgap = 1))%>%
mutate(dplyr::across(c(CENT, WC_STRUCT, WC_RIGHTS, Govint, Level, RI, Coord, EXT, PACTSIGN, AGRSIGN), na.locf, na.rm = F, fromLast = T, maxgap = 1 ))%>%
ungroup()%>%
filter_at(vars(Level, RI, Coord, EXT, PACTSIGN, AGRSIGN), all_vars(!is.na(.)))%>%# this is just an effective way of eliminating cases where data are just missing, because if these are missing, data are just missing in general
mutate(dplyr::across(c(CENT, WC_STRUCT, WC_RIGHTS, Govint, Level, RI, Coord, EXT, PACTSIGN, AGRSIGN), scale))%>%
mutate(count_na = rowSums(is.na(.)))%>%#just for checking
mutate(corp_index = rowMeans(subset(., select = c(CENT, WC_STRUCT, WC_RIGHTS, Govint, Level, RI, Coord, EXT, PACTSIGN, AGRSIGN)), na.rm = TRUE))
We can now compare our recreation to the original index
# The corporatism index developed by Jahn 2016 (data go until 2010). Data were obtained through Jahn directly.
corporatism_index_original <- haven::read_dta("raw-data/Corporatism_sum.dta")%>%
filter(country %in% countries.list)%>%
group_by(country)%>%
mutate(mean_index_original = mean(Corp_Jahn_add, na.rm = T))%>%
select(country, year, z_Corp_Jahn_sm_add, mean_index_original)
corporatism_index_recreation <- corporatism_index%>%
filter(year<2011)%>%
group_by(country)%>%
mutate(mean_index_recreation = mean(corp_index, na.rm = T))%>%
select(country, year, corp_index, mean_index_recreation)
#create rolling mean to make more comparable
corporatism_index_recreation%<>%
arrange(country, year) %>%
mutate(corp_index_rollmean=rollapply(corp_index,5,mean,align='right',fill=NA))
#combine the two datasets: the original one loaded from visser and the one I created
index_cor <- right_join(corporatism_index_recreation, corporatism_index_original)%>%
pivot_longer(c(z_Corp_Jahn_sm_add, corp_index_rollmean))
# Plotting the data. Generally, data are a bit more compressed, with high values being lower and low values being higher, potentially because of the way the values were z-transformed.
index_cor%>%
filter(year>1979)%>%
ggplot(aes(year, value, color = name))+
geom_line()+
facet_wrap(~country)+
theme(legend.position = "bottom")
# Some further cleaning
corporatism_index%<>%
filter(year >= 1960,
country %in% c(countries.list))%>%
select(country, year, corp_index)%>%
rename(Country = country,
Year = year)
Finally, we also want to get the corporatism index only regarding its functional dimension (we again also include the pact variables)
ICTWSS <- read_excel("raw-data/20191107_ICTWSS_6_1_Dataset.xlsx",
skip = 0) %>%
filter(
country %in% countries.list |
country == "United States of America" |
country == "Slovak Republic",
year > 1959
) %>%
select(
country,
year,
CENT,
WC_STRUCT,
WC_RIGHTS,
Govint,
Level,
RI,
Coord,
EXT,
PACTSIGN,
AGRSIGN
) %>%
mutate(country = plyr::revalue(country, c("United States of America" = "United States"))) %>%
mutate(country = plyr::revalue(country, c("Czech Republic" = "Czechia"))) %>%
mutate(country = plyr::revalue(country, c("Slovak Republic" = "Slovakia")))
corporatism_index_fun<- ICTWSS%>%
group_by(country)%>%
mutate(dplyr::across(c(CENT, WC_STRUCT, WC_RIGHTS, Govint, Level, RI, Coord, EXT, PACTSIGN, AGRSIGN), na.approx,na.rm = F, maxgap = 3))%>%
mutate(dplyr::across(c(CENT, WC_STRUCT, WC_RIGHTS, Govint, Level, RI, Coord, EXT, PACTSIGN, AGRSIGN), na.locf, na.rm = F, maxgap = 1))%>%
mutate(dplyr::across(c(CENT, WC_STRUCT, WC_RIGHTS, Govint, Level, RI, Coord, EXT, PACTSIGN, AGRSIGN), na.locf, na.rm = F, fromLast = T, maxgap = 1 ))%>%
ungroup()%>%
filter_at(vars(Level, RI, Coord, EXT, PACTSIGN, AGRSIGN), all_vars(!is.na(.)))%>%# this is just an effective way of eliminating cases where data are just missing, because if these are missing, data are just missing in general
mutate(dplyr::across(
c(Govint, Level, RI, PACTSIGN, AGRSIGN),
na.locf,
na.rm = F,
fromLast = T,
maxgap = 1
))%>%
mutate(count_na = rowSums(is.na(.)))%>%#just for checking
mutate(corp_index_fun = rowMeans(subset(., select = c(Govint, Level, RI, PACTSIGN, AGRSIGN)), na.rm = TRUE))
# some further cleaning
corporatism_index_fun%<>%
filter(year >= 1960,
country %in% c(countries.list))%>%
#select(country, year, corp_index)%>% this row we would keep if we already created the index
rename(Country = country,
Year = year)%>%
expss::apply_labels(
corp_index_fun = "Index of Corporatism (functional only)")
We measure trade openness, following Busemeyer 2009 as the average of exports and imports as a share of GDP
trade_open <- get_dataset(dataset = "NAAG",
filter = "AUS+AUT+BEL+CAN+CZE+DNK+EST+FIN+FRA+DEU+GRC+HUN+IRL+ISR+ITA+JPN+KOR+LVA+LTU+LUX+NLD+NZL+NOR+POL+PRT+SVK+SVN+ESP+SWE+CHE+GBR+USA.P6S+P7S",
pre_formatted = T,
start_time = 1960,
end_time = 2020)%>%
select(c(LOCATION, INDICATOR, obsValue, obsTime))
# we add up exports and imports as a share of GDP, which we got from the data
trade_open%<>%
group_by(LOCATION, obsTime)%>%
mutate(trade_open = sum(obsValue))%>%
distinct(trade_open)%>%
select(c(LOCATION, obsTime, trade_open))%>%
rename(Country = LOCATION,
Year = obsTime)%>%
mutate(Year = as.numeric(Year),
Country = countrycode(Country, 'iso3c', 'country.name'))%>%
expss::apply_labels(
trade_open = "Exports+Imports/GDP")
Consumer price inflation rates were taken from the OECD.
inflation <- get_dataset(dataset = "PRICES_CPI",
filter = "AUS+AUT+BEL+CAN+CZE+DNK+EST+FIN+FRA+DEU+GRC+HUN+IRL+ISR+ITA+JPN+KOR+LVA+LTU+LUX+NLD+NZL+NOR+POL+PRT+SVK+SVN+ESP+SWE+CHE+GBR+USA.CPALTT01.GY.A",
pre_formatted = T,
start_time = 1960,
end_time = 2020)%>%
select(c(LOCATION, obsTime, obsValue))
inflation%<>%
rename(Country = LOCATION,
Year = obsTime,
Inflation = obsValue)%>%
mutate(Year = as.numeric(Year),
Country = countrycode(Country, 'iso3c', 'country.name'))%>%
expss::apply_labels(
Inflation = "Average Annual Inflation Rate")
Annual GDP growth data taken from OECD.
growth <- get_dataset(dataset = "SNA_TABLE1",
filter = "AUS+AUT+BEL+CAN+CZE+DNK+EST+FIN+FRA+DEU+GRC+HUN+IRL+ISR+ITA+JPN+KOR+LVA+LTU+LUX+NLD+NZL+NOR+POL+PRT+SVK+SVN+ESP+SWE+CHE+GBR+USA.B1_GE.G",
pre_formatted = T,
start_time = 1960,
end_time = 2019)%>%
select(LOCATION, obsTime, obsValue)
growth%<>%
rename(Country = LOCATION,
Year = obsTime,
Growth = obsValue)%>%
mutate(Year = as.numeric(Year),
Country = countrycode(Country, 'iso3c', 'country.name'))%>%
expss::apply_labels(
Growth = "GDP Growth")
I use general government budget deficit data from the OECD. In addition, to better control for economic fluctuations, I use the cyclically adjusted deficit obtained through the CPDS.
deficit <- get_dataset(dataset = "NAAG",
filter = "AUS+AUT+BEL+CAN+CZE+DNK+EST+FIN+FRA+DEU+GRC+HUN+IRL+ISR+ITA+JPN+KOR+LVA+LTU+LUX+NLD+NZL+NOR+POL+PRT+SVK+SVN+ESP+SWE+CHE+GBR+USA.B9S13S",
pre_formatted = T,
start_time = 1960,
end_time = 2019)%>%
select(LOCATION, obsTime, obsValue)
deficit%<>%
rename(Country = LOCATION,
Year = obsTime,
Deficit = obsValue)%>%
mutate(Year = as.numeric(Year),
Country = countrycode(Country, 'iso3c', 'country.name'))%>%
expss::apply_labels(
Deficit = "Budget Deficit")
cpds_deficit <- read_excel("raw-data/CPDS_1960-2019_Update_2021.xlsx")%>%
select(country, year, deficit, capb)%>%
rename(Country = country,
Year = year)%>%
mutate(Country = plyr::revalue(Country, c("Czech Republic" = "Czechia")))
General government debt as percentage of GDP from OECD.
debt <- get_dataset(dataset = "NAAG",
filter = "AUS+AUT+BEL+CAN+CZE+DNK+EST+FIN+FRA+DEU+GRC+HUN+IRL+ISR+ITA+JPN+KOR+LVA+LTU+LUX+NLD+NZL+NOR+POL+PRT+SVK+SVN+ESP+SWE+CHE+GBR+USA.DBTS13GDP",
pre_formatted = T,
start_time = 1960,
end_time = 2019)%>%
select(LOCATION, obsTime, obsValue)%>%
rename(Country = LOCATION,
Year = obsTime,
debt = obsValue)%>%
mutate(Year = as.numeric(Year),
Country = countrycode(Country, 'iso3c', 'country.name'))
Unemployment rate from OECD.
unemployment <- get_dataset(dataset = "LFS_SEXAGE_I_R",
filter = "AUS+AUT+BEL+CAN+CZE+DNK+EST+FIN+FRA+DEU+GRC+HUN+IRL+ISR+ITA+JPN+KOR+LVA+LTU+LUX+NLD+NZL+NOR+POL+PRT+SVK+SVN+ESP+SWE+CHE+GBR+USA.MW.900000.UR.A",
pre_formatted = T,
start_time = 1960,
end_time = 2020)%>%
select(c(COUNTRY, obsTime, obsValue))
unemployment%<>%
rename(Country = COUNTRY,
Year = obsTime,
unemployment = obsValue)%>%
mutate(Year = as.numeric(Year),
Country = countrycode(Country, 'iso3c', 'country.name'))%>%
expss::apply_labels(
unemployment = "Unemployment Rate")
Population data are obtained from the OECD and Eurostat.
# Numbers are in thousands so multiply them by a 1000
pop_size <- get_dataset(dataset = "ALFS_POP_VITAL",
filter = "AUS+AUT+BEL+CAN+CZE+DNK+EST+FIN+FRA+DEU+GRC+HUN+IRL+ISR+ITA+JPN+KOR+LVA+LUX+NLD+NZL+NOR+POL+PRT+SVK+SVN+ESP+SWE+CHE+GBR+USA.YPTTTTL1_ST.A",
pre_formatted = T,
start_time = 1960,
end_time = 2020)%>%
mutate(pop_size = obsValue*1000)%>%
select(c(LOCATION, obsTime, pop_size))
# Data for Lithuania are incomplete so I use Eurostat data. Values are minimally different, probably because they are measured mid-year (OECD) and January 1 (Eurostat); this differences are negligible
lithuania <-
get_eurostat(
"demo_pjan",
time_format = "num",
type = "label",
filters = list(
unit = "NR",
age = "TOTAL",
sex = "T",
geo = c("LT"),
sinceTimePeriod = 1960
)
)%>%
dplyr::rename("LOCATION" = geo,
"obsTime" = time,
"pop_size" = values)%>%
select(c(LOCATION, obsTime, pop_size))%>%
mutate(LOCATION = plyr::revalue(LOCATION, c("Lithuania" = "LTU")))
# small state variable is created in three different ways. There is no clear definition of what counts as a small state. 10 and 6 Million are reasonable cutoffs based on the Katzensteinian analysis. The third operationalization distinghuishes between small, mid-sized and large countries (references category).
pop_size <- rbind(pop_size, lithuania)%>%
arrange(LOCATION)%>%
rename(Country = LOCATION,
Year = obsTime)%>%
mutate(Year = as.numeric(Year),
Country = countrycode(Country, 'iso3c', 'country.name'),
small_state_binary_1 = ifelse(pop_size < 10000000, 1, 0),
small_state_binary_2 = ifelse(pop_size < 6000000, 1, 0),
small_state_three = ifelse(pop_size < 6000000, 2, ifelse(pop_size>6000000 & pop_size < 20000000, 1, 0)))%>%
expss::apply_labels(
pop_size = "Population Size",
small_state_binary_1 = "Under 10 Mil",
small_state_binary_2 = "Under 6 Mil",
small_state_three = "Under 6 Mil, Under 20 Mil")
Following Jensen, deindustrialization is basically measured as the share of service-sector employment in overall employment (Jensen operationlizes this as 100 -share of manufacturing - share of agriculture).
# I rely on Employment by activities from the Employment by activities and status (ALFS) dataset based on the fourth revision of the International Standard Industrial Classification (ISIC). However, for some countries this only goes back to 2003 when the revision was introduced. In that case, I use data based on the third revision, which was used between 1990 and 2003, or, if not available or for data older than 1990, based on the second revision which was used until 1989. There are small differences between the different revisions but they are not substantial and outweighed by having real-data available instead of imputing them. For the US, there are data issues after 2002 so I use data from the ALFS summary table there, which are also very similiar
alfs4 <- get_dataset(
dataset = "ALFS_EMP",
filter = "AUS+AUT+BEL+CAN+CZE+DNK+EST+FIN+FRA+DEU+GRC+HUN+IRL+ISR+ITA+JPN+KOR+LVA+LTU+LUX+NLD+NZL+NOR+POL+PRT+SVK+SVN+ESP+SWE+CHE+GBR+USA.YA994AL1_ST+YA994IL1_ST+YA994SL1_ST.TT.A",
pre_formatted = T,
start_time = 1960,
end_time = 2020
)
alfs4_ <- alfs4%>%
select(LOCATION, SUBJECT, obsTime, obsValue)%>%
mutate(SUBJECT = plyr::revalue(
SUBJECT,
c(
"YA994AL1_ST" = "agricult4",
"YA994IL1_ST" = "manufact4",
"YA994SL1_ST" = "service4"
)
)) %>%
pivot_wider(names_from = SUBJECT, values_from = obsValue)%>%
mutate(total4 = agricult4 + manufact4 + service4,
agricult_share4 = agricult4/total4,
manufact_share4 = manufact4/total4,
service_share4 = service4/total4)%>%
mutate(deindustrialization_4 = service_share4*100)
alfs3 <- get_dataset(
dataset = "ALFS_EMP",
filter = "AUS+AUT+BEL+CAN+CZE+DNK+EST+FIN+FRA+DEU+GRC+HUN+IRL+ISR+ITA+JPN+KOR+LVA+LTU+LUX+NLD+NZL+NOR+POL+PRT+SVK+SVN+ESP+SWE+CHE+GBR+USA.YA993AL1_ST+YA993IL1_ST+YA993SL1_ST.TT.A",
pre_formatted = T,
start_time = 1960,
end_time = 2020
)
alfs3_ <- alfs3%>%
select(LOCATION, SUBJECT, obsTime, obsValue)%>%
mutate(SUBJECT = plyr::revalue(
SUBJECT,
c(
"YA993AL1_ST" = "agricult3",
"YA993IL1_ST" = "manufact3",
"YA993SL1_ST" = "service3"
)
)) %>%
pivot_wider(names_from = SUBJECT, values_from = obsValue)%>%
mutate(total3 = agricult3 + manufact3 + service3,
agricult_share3 = agricult3/total3,
manufact_share3 = manufact3/total3,
service_share3 = service3/total3)%>%
mutate(deindustrialization_3 = service_share3*100)
alfs2 <- get_dataset(
dataset = "ALFS_EMP",
filter = "AUS+AUT+BEL+CAN+CZE+DNK+EST+FIN+FRA+DEU+GRC+HUN+IRL+ISR+ITA+JPN+KOR+LVA+LTU+LUX+NLD+NZL+NOR+POL+PRT+SVK+SVN+ESP+SWE+CHE+GBR+USA.YA992AL1_ST+YA992IL1_ST+YA992SL1_ST.TT.A",
pre_formatted = T,
start_time = 1960,
end_time = 2020
)
alfs2_ <- alfs2%>%
select(LOCATION, SUBJECT, obsTime, obsValue)%>%
mutate(SUBJECT = plyr::revalue(
SUBJECT,
c(
"YA992AL1_ST" = "agricult2",
"YA992IL1_ST" = "manufact2",
"YA992SL1_ST" = "service2"
)
)) %>%
pivot_wider(names_from = SUBJECT, values_from = obsValue)%>%
mutate(total2 = agricult2 + manufact2 + service2,
agricult_share2 = agricult2/total2,
manufact_share2 = manufact2/total2,
service_share2 = service2/total2)%>%
mutate(deindustrialization_2 = service_share2*100)
deindu_us <- get_dataset(dataset = "ALFS_SUMTAB",
filter = "USA.YGTT09PE_ST+YGTT10PE_ST+YGTT11PE_ST.A",
pre_formatted = T,
start_time = 1960,
end_time = 2020)%>%
mutate(SUBJECT = plyr::revalue(SUBJECT, c("YGTT09PE_ST" = "agricult", "YGTT10PE_ST" = "manufact", "YGTT11PE_ST" = "service")))%>%
select(LOCATION, SUBJECT, obsTime, obsValue)%>%
pivot_wider(names_from = SUBJECT, values_from = obsValue)%>%
group_by(LOCATION, obsTime)%>%
mutate(deindustrialization_us = service)
deindu <- alfs2_%>%
full_join( alfs3_)%>%
full_join(alfs4_)%>%
full_join(deindu_us)%>%
select(LOCATION, obsTime, starts_with("deindu"))%>%
mutate(deindustrialization = deindustrialization_4,
deindustrialization = ifelse(
is.na(deindustrialization),
deindustrialization_3,
deindustrialization),
deindustrialization = ifelse(is.na(deindustrialization),
deindustrialization_2,
deindustrialization),
deindustrialization = ifelse(is.na(deindustrialization),
deindustrialization_us,
deindustrialization)) %>%
rename(Country = LOCATION,
Year = obsTime) %>%
mutate(Year = as.numeric(Year),
Country = countrycode(Country, 'iso3c', 'country.name'))%>%
select(Country, Year, deindustrialization)
I use the quality of democracy dataset. There are several options:
the h_f variable: Independent Sub-Federal Unit, Dummy variable coded 1 if there are independent sub-federal units (states, provinces, regions etc.) that impose substantive constraints on national fiscal policy.
h_polcon3 Political Constraints Index III This index measures the feasibility of policy change, i.e. the extent to which a change in the preferences of any one political actor may lead to a change in government policy. The index is composed from the following information: the number of independent branches of government with veto power over policy change, counting the executive and the presence of an elective lower and upper house in the legislature (more branches leading to more constraint); the extent of party alignment across branches of government, measured as the extent to which the same party or coalition of parties control each branch (decreasing the level of constraint); and the extent of preference heterogeneity within each legislative branch, measured as legislative fractionalization in the relevant house (increasing constraint for aligned executives, decreasing it for opposed executives). The index scores are derived from a simple spatial model and theoretically ranges from 0 to 1, with higher scores indicating more political constraint and thus less feasibility of policy change. Note that the coding reflects information as of January 1 in any given year. Henisz (2002) uses this index to demonstrate that political environments that limit the feasibility of policy change are an important determinant of investment in infrastructure.
h_polcon5 Political Constraints Index V
This index follows the same logic as Political Constraints Index III (h_polcon3) but also includes two additional veto points: the judiciary and sub-federal entities. Note that the coding reflects information as of January 1 in any given year. Henisz (2000) uses this index to measure the impact on cross-national growth rates of a government’s ability to provide credible commitment.
qod <- read.csv("raw-data/qog_std_ts_jan20.csv")
qod %<>%
filter(cname %in% countries.list,
year >= 1960) %>%
select(cname, year, h_f, h_polcon3, h_polcon5) %>%
rename(Country = cname,
Year = year) %>%
mutate(Country = plyr::revalue(Country, c("Czech Republic" = "Czechia")))%>%
expss::apply_labels(
h_f = "Independent Sub-Federal Unit",
h_polcon3 = "Political Constraints Index III",
h_polcon5 = "Political Constraints Index V"
)
We use data from the IMF Fiscal Rule dataset. General: “0” indicates that the feature is not in place or does not apply; “1” indicates it is in place or applies.
Three features are selected:
I select country/years that have a debt rule but do not have an exeption for investments
fiscal_rules <- read_excel("raw-data/FAD-Fiscal Rules Dataset.xlsx", skip = 1, sheet = 3)%>%
filter(year >1959,
`Country name` %in% countries.list)%>%
select(c(year, `Country name`, `DR: Debt rule...7`, `DR: Debt rule...11`,`Rule(s) exclude public investment or other priority items from ceiling`))%>%
rename(Year = year,
Country = `Country name`,
debt_rule = `DR: Debt rule...7`,
national_debt_rule = `DR: Debt rule...11`,
investment_exception = `Rule(s) exclude public investment or other priority items from ceiling` )%>%
mutate(Country = plyr::revalue(Country, c("Czech Republic" = "Czechia")))%>%
mutate(hard_debt_rule = ifelse(debt_rule == 1 & investment_exception == 0, 1, 0))%>%
select(Year, Country, hard_debt_rule)
Data are again from the OECD.
# I collect GDP per capita, which I cannot easily just recreate with the GDP and pop-size variables as I collected GDP (as well as the other variables) in current prices and not in a common format with common currency
gdp_cap <- get_dataset(dataset = "SNA_TABLE1",
filter = "AUS+AUT+BEL+CAN+CZE+DNK+EST+FIN+FRA+DEU+GRC+HUN+IRL+ISR+ITA+JPN+KOR+LVA+LTU+LUX+NLD+NZL+NOR+POL+PRT+SVK+SVN+ESP+SWE+CHE+GBR+USA.B1_GE.HCPC",
pre_formatted = T,
start_time = 1960,
end_time = 2020)%>%
select(LOCATION, obsTime, obsValue)%>%
rename(Country = LOCATION,
Year = obsTime,
gdp_capita = obsValue)%>%
mutate(Year = as.numeric(Year),
Country = countrycode(Country, 'iso3c', 'country.name'))
Whether a country is a E(M)U member or not in a given year. Data taken from the CPDS.
cpds_eu <- read_excel("raw-data/CPDS_1960-2019_Update_2021.xlsx")%>%
select(country, year, eu, emu)%>%
rename(Country = country,
Year = year)%>%
mutate(Country = plyr::revalue(Country, c("Czech Republic" = "Czechia")))
Aggregate foreign direct investment inflows based on OECD data.
fdi_inflows <- get_dataset(dataset = "FDI_AGGR_SUMM",
filter = "AUS+AUT+BEL+CAN+CZE+DNK+EST+FIN+FRA+DEU+GRC+HUN+IRL+ISR+ITA+JPN+KOR+LVA+LTU+LUX+NLD+NZL+NOR+POL+PRT+SVK+SVN+ESP+SWE+CHE+GBR+USA.PER_GDP.DI.T_FA_F",
pre_formatted = T,
start_time = 1960,
end_time = 2020)%>%
select(COU, obsTime, obsValue)%>%
rename(Country = COU,
Year = obsTime,
fdi_inflows = obsValue)%>%
mutate(Year = as.numeric(Year),
Country = countrycode(Country, 'iso3c', 'country.name'))
Employment rate based on OECD data.
employment <- get_dataset(dataset = "STLABOUR",
filter = "AUS+AUT+BEL+CAN+CZE+DNK+EST+FIN+FRA+DEU+GRC+HUN+IRL+ISR+ITA+JPN+KOR+LVA+LTU+LUX+NLD+NZL+NOR+POL+PRT+SVK+SVN+ESP+SWE+CHE+GBR+USA.LREM64TT.STSA.A",
pre_formatted = T,
start_time = 1960,
end_time = 2020)%>%
select(LOCATION, obsTime, obsValue)%>%
rename(Country = LOCATION,
Year = obsTime,
employment = obsValue)%>%
mutate(Year = as.numeric(Year),
Country = countrycode(Country, 'iso3c', 'country.name'))
full_data <- dig_index%>%
left_join(government_positions_full, by = c("Country", "Year"))%>%
left_join(corporatism_index, by = c("Country", "Year"))%>%
left_join(corporatism_index_fun, by = c("Country", "Year"))%>%
left_join(gdp_cap, by = c("Country", "Year"))%>%
left_join(trade_open, by = c("Country", "Year"))%>%
left_join(inflation, by = c("Country", "Year"))%>%
left_join(growth, by = c("Country", "Year"))%>%
left_join(cpds_deficit, by = c("Country", "Year"))%>%
left_join(unemployment, by = c("Country", "Year"))%>%
left_join(fiscal_rules, by = c("Country", "Year"))%>%
left_join(deindu, by = c("Country", "Year"))%>%
left_join(elderly, by = c("Country", "Year"))%>%
left_join(qod, by = c("Country", "Year"))%>%
left_join(cpds_eu, by = c("Country", "Year"))%>%
left_join(debt, by = c("Country", "Year"))%>%
left_join(employment, by = c("Country", "Year"))%>%
left_join(fdi_inflows, by = c("Country", "Year"))%>%
left_join(pop_size, by = c("Country", "Year"))
I linearly interpolated some of the subindications for the corporatism index. But I did so very conservatively, so there is still missing values for the aggregate measures as well. The missing values in full_data dataset are multiply imputed using Amelia (for more information, see the online appendix).
# to work better with the dataset it makes sense to delete the otherwise informative labels.
full_data_unlabelled <- remove_all_labels(full_data)
# I include lags and leads of most variables. It makes sense to include as many variables as possible for the imputation; here we only leave out the lags of the government level variables.
lags_leads <- c(
"GDP",
"corp_index",
"corp_index_fun",
"gdp_capita",
"rd_gdp",
"rd_gdp_sel",
"alp_gdp",
"employment",
"fdi_inflows",
"trade_open",
"Inflation",
"Growth",
"deficit",
"unemployment",
"pop_size" ,
"deindustrialization",
"share_elderly",
"capb",
"debt"
)
# Run amelia. We specify a linear time trend here (polytime = 1) as this seems most plausible for most missing values.
set.seed(1234)
amelia.out <-
amelia(
full_data_unlabelled,
m = 10,
ts = "Year",
cs = "Country",
polytime = 1,
intercs = T,
idvars = "cabinet_name",
parallel = "snow",
lags = lags_leads,
leads = lags_leads,
empri = .01 * nrow(full_data_unlabelled)
)
Given that I now have a list of dataframes with imputed values, I need to use broom/purr/tidyverse to meld the imputed data in a tidy manner (this is useful in that regard.). I also combine the three subindicators of investment spending into the dependent variable: the knowledge investment index. I create alternative versions here, one with combined education spending (edu_exp3_gdp) and one with only the Worldbank data (edu_exp2_gdp) as well as one with overall R&D spending and one with only spending on selected categories. For each imputation - m - I create lags, round imputed data for non-continuous variables that were imputed, group-mean center the variables and create the within and between variables, and normalize the data.
all_imputations <- bind_rows(unclass(amelia.out$imputations), .id = "m") %>%
group_by(m)%>%
mutate(dii_score_gdp = (edu_exp3_gdp + rd_gdp + alp_gdp),
dii_score_gdp_sel = (edu_exp3_gdp + rd_gdp_sel + alp_gdp),
dii_score_gdp_without = (edu_exp3_gdp + rd_gdp),
dii_score2_gdp = (edu_exp2_gdp + rd_gdp + alp_gdp),
dii_score2_gdp_without = (edu_exp2_gdp + rd_gdp))%>%
group_by(m, Country)%>%
mutate(dii_score_gdp_lag = lag(dii_score_gdp),
dii_score_gdp_sel_lag = lag(dii_score_gdp_sel),
dii_score_gdp_without_lag = lag(dii_score_gdp_without),
dii_score2_gdp_lag = lag(dii_score2_gdp),
rd_gdp_lag = lag(rd_gdp),
edu_exp3_gdp_lag = lag(edu_exp3_gdp),
alp_gdp_lag = lag(alp_gdp))%>%
filter((Year>1994 | Country %in% countries.selected & Year >1980) & Year <2019)%>%
ungroup()%>%
mutate(small_state_binary_1 = round(small_state_binary_1),
small_state_binary_2 = round(small_state_binary_2),
small_state_three = round(small_state_three))%>%
group_by(m) %>%
mutate(corp_index_between = ave(corp_index, Country),
corp_index_within = corp_index-corp_index_between,
corp_index_fun_between = ave(corp_index_fun, Country),
corp_index_fun_within = corp_index_fun-corp_index_fun_between,
capb_between = ave(capb, Country),
capb_within = capb-capb_between,
deindustrialization_between = ave(deindustrialization, Country),
deindustrialization_within = deindustrialization-deindustrialization_between,
h_polcon5_between = ave(h_polcon5, Country),
h_polcon5_within = h_polcon5-h_polcon5_between,
h_polcon3_between = ave(h_polcon3, Country),
h_polcon3_within = h_polcon3-h_polcon3_between,
deficit_between = ave(deficit, Country),
deficit_within = deficit-deficit_between,
unemployment_between = ave(unemployment, Country),
unemployment_within = unemployment-unemployment_between,
employment_between = ave(employment, Country),
employment_within = employment-employment_between,
gdp_capita_between = ave(gdp_capita, Country),
gdp_capita_within = gdp_capita-gdp_capita_between,
trade_open_between = ave(trade_open, Country),
trade_open_within = trade_open-trade_open_between)%>%
mutate(across(c(starts_with("corp_"), starts_with("dii"), starts_with("alp"), starts_with("edu_exp"), starts_with("rd_gdp"), ends_with("weighthed"), starts_with("gov_"), starts_with("trad"), Inflation:pop_size, starts_with("deindust"), starts_with("defic"), starts_with("h_"), starts_with("unemploy"), starts_with("employ"), investment_weighted, share_elderly, starts_with("gdp"), starts_with("public"), starts_with("capb"), starts_with("GDP"), debt), scale, .names = "{col}_normal"))%>%
nest()
This is to code to run the mixed-effects models on the imputed data. The code is a bit lengthy as standard regression functions do not provide all the coefficients/information (e.g. the random slope variance) in a tidy format which we can later efficiently plot with the texreg package (or any other package), especially when data need to be extracted and averaged across multiple imputations. In the following code blocks, I summarize 4 models into one set of imputations and create texreg objects that can be used for plotting the data in regression tables. First, I do the 4 models from the main paper. Below I do several robustness checks. model_000 and model_001 need different data/imputations.
models_imputations <- all_imputations %>%
mutate(
model_empty = data %>% map( ~ lmer(
dii_score_gdp_normal ~ 1 + (1 | cabinet_name) + (1 | Country),
data = .,
na.action = na.omit,
control = lmerControl(optimizer = "Nelder_Mead"),
REML = TRUE)),
tidied_empty = model_empty %>% map(~ broom.mixed::tidy(., effects = c("fixed"))),
glance_empty = model_empty %>% map(~ broom.mixed::glance(.)),
VarCorr_empty = model_empty %>% map(~ as.tibble(VarCorr(.))),
nobs_empty = model_empty%>% map(~nobs(.)),
model_1 = data %>% map(
~ lmer(
dii_score_gdp_normal ~ gov_seat_share_normal +
corp_index_normal + capb_normal + deindustrialization_normal + trade_open_normal + h_polcon5_normal + hard_debt_rule + eu + small_state_binary_2 + unemployment_normal + splines::bs(Year, degree = 3) + (1 | cabinet_name) + (1 | Country),
data = .,
na.action = na.omit,
control = lmerControl(optimizer = "Nelder_Mead"),
REML = TRUE
)
),
tidied_1 = model_1 %>% map(~ broom.mixed::tidy(., effects = c("fixed"))),
glance_1 = model_1 %>% map(~ broom.mixed::glance(.)),
VarCorr_1 = model_1 %>% map(~ as.tibble(VarCorr(.))),
nobs_1 = model_1%>% map(~nobs(.)),
model_2 = data %>% map(
~ lmer(
dii_score_gdp_normal ~ gov_seat_share_normal +
corp_index_within_normal + corp_index_between_normal + capb_normal + eu + deindustrialization_within_normal + deindustrialization_between_normal + trade_open_normal + h_polcon5_normal + hard_debt_rule + small_state_binary_2 +unemployment_normal + splines::bs(Year, degree = 3) + (1 | cabinet_name) + (1 | Country),
data = .,
na.action = na.omit,
control = lmerControl(optimizer = "Nelder_Mead"),
REML = TRUE
)
),
tidied_2 = model_2 %>% map(~ broom.mixed::tidy(., effects = c("fixed"))),
glance_2 = model_2 %>% map(~ broom.mixed::glance(.)),
VarCorr_2 = model_2 %>% map(~ as.tibble(VarCorr(.))),
nobs_2 = model_2%>% map(~nobs(.)),
model_3 = data %>% map(
~ lmer(dii_score_gdp_normal ~ gov_seat_share_normal + corp_index_within_normal + deindustrialization_within_normal*corp_index_between_normal + capb_normal + eu + deindustrialization_between_normal + trade_open_normal + h_polcon5_normal + hard_debt_rule + small_state_binary_2 + unemployment_normal+ splines::bs(Year, degree = 3) + (1 | cabinet_name) + (deindustrialization_within_normal | Country),
data = .,
na.action = na.omit,
control = lmerControl(optimizer = "Nelder_Mead"),
REML = TRUE
)
),
tidied_3 = model_3 %>% map(~ broom.mixed::tidy(., effects = c("fixed"))),
glance_3 = model_3 %>% map(~ broom.mixed::glance(.)),
VarCorr_3 = model_3 %>% map(~ as.tibble(VarCorr(.))),
nobs_3 = model_3%>% map(~nobs(.))
)
# Create a wide data frame of just the coefficients and standard errors
params_empty <- models_imputations %>%
unnest(tidied_empty)%>%
dplyr::select(m, term, estimate, std.error)%>%
gather(key, value, estimate, std.error)%>%
spread(term, value)
params_1 <- models_imputations %>%
unnest(tidied_1)%>%
dplyr::select(m, term, estimate, std.error)%>%
gather(key, value, estimate, std.error)%>%
spread(term, value)
params_2 <- models_imputations %>%
unnest(tidied_2)%>%
dplyr::select(m, term, estimate, std.error)%>%
gather(key, value, estimate, std.error)%>%
spread(term, value)
params_3 <- models_imputations %>%
unnest(tidied_3)%>%
dplyr::select(m, term, estimate, std.error)%>%
gather(key, value, estimate, std.error)%>%
spread(term, value)
# Extract just the coefficients
just_coefs_empty <- params_empty %>%
filter(key == "estimate")%>%
ungroup()%>%
dplyr::select(-m, -key)
just_coefs_1 <- params_1 %>%
filter(key == "estimate")%>%
ungroup()%>%
dplyr::select(-m, -key)
just_coefs_2 <- params_2 %>%
filter(key == "estimate")%>%
ungroup()%>%
dplyr::select(-m, -key)
just_coefs_3 <- params_3 %>%
filter(key == "estimate")%>%
ungroup()%>%
dplyr::select(-m, -key)
# Extract just the standard errors
just_ses_empty <- params_empty %>%
filter(key == "std.error")%>%
ungroup()%>%
dplyr::select(-m, -key)
just_ses_1 <- params_1 %>%
filter(key == "std.error")%>%
ungroup()%>%
dplyr::select(-m, -key)
just_ses_2 <- params_2 %>%
filter(key == "std.error")%>%
ungroup()%>%
dplyr::select(-m, -key)
just_ses_3 <- params_3 %>%
filter(key == "std.error")%>%
ungroup()%>%
dplyr::select(-m, -key)
#then we use amelias mi.meld function to combine estimates and se according to rubin's formula
coefs_melded_empty <- mi.meld(just_coefs_empty, just_ses_empty)
coefs_melded_1 <- mi.meld(just_coefs_1, just_ses_1)
coefs_melded_2 <- mi.meld(just_coefs_2, just_ses_2)
coefs_melded_3 <- mi.meld(just_coefs_3, just_ses_3)
# now we can also get pvalues as well as the R² and other estimates
model_degree_freedom_empty <- models_imputations %>%
unnest(glance_empty) %>%
filter(m == "imp1")%>%
pull(df.residual)
model_degree_freedom_1 <- models_imputations %>%
unnest(glance_1) %>%
filter(m == "imp1")%>%
pull(df.residual)
model_degree_freedom_2 <- models_imputations %>%
unnest(glance_2) %>%
filter(m == "imp1")%>%
pull(df.residual)
model_degree_freedom_3 <- models_imputations %>%
unnest(glance_3) %>%
filter(m == "imp1")%>%
pull(df.residual)
# variance/ICC
VarCorr_empty <- models_imputations %>%
unnest(VarCorr_empty)%>%
ungroup()%>%
group_by(grp)%>%
summarize( vcov = mean(vcov), sdcor = mean(sdcor))%>%
rename(term = grp, estimate = vcov)%>%
mutate(term = recode(term, "Country" = "Variance Country Level", "cabinet_name" = "Variance Government Level"))%>%
dplyr::select(-sdcor)
VarCorr_1 <- models_imputations %>%
unnest(VarCorr_1)%>%
ungroup()%>%
group_by(grp)%>%
summarize( vcov = mean(vcov), sdcor = mean(sdcor))%>%
rename(term = grp, estimate = vcov)%>%
mutate(term = recode(term, "Country" = "Variance Country Level", "cabinet_name" = "Variance Government Level"))%>%
dplyr::select(-sdcor)
VarCorr_2 <- models_imputations %>%
unnest(VarCorr_2)%>%
ungroup()%>%
group_by(grp)%>%
summarize( vcov = mean(vcov), sdcor = mean(sdcor))%>%
rename(term = grp, estimate = vcov)%>%
mutate(term = recode(term, "Country" = "Variance Country Level", "cabinet_name" = "Variance Government Level"))%>%
dplyr::select(-sdcor)
# here we have a random slope so we need to merge var 1 and var 2 to get the covariance between intercept and slope and we cannot group by country as we have both random intercepts and slopes for countries
VarCorr_3 <- models_imputations %>%
unnest(VarCorr_3)%>%
ungroup()%>%
replace_na(list(var1 = "", var2 = "")) %>%
unite(term, grp, var1,var2, remove = FALSE, sep = "")%>%
group_by(term)%>%
summarize( vcov = mean(vcov), sdcor = mean(sdcor))%>%
rename(estimate = vcov)%>%
mutate(term = recode(term, "Country(Intercept)" = "Variance Country Level", "cabinet_name(Intercept)" = "Variance Government Level", "Country(Intercept)deindustrialization_within_normal" = "Covariance Random Slope/Intercept", "Countrydeindustrialization_within_normal" = "Variance Random Slope"))%>%
dplyr::select(-sdcor)
# here we can just extract the number of grouped observations from the first model as they are the same for all imputations of this particular model
num_groups_empty <- as.data.frame(sapply(ranef(models_imputations$model_empty[[1]]), nrow))
colnames(num_groups_empty) <- "estimate"
num_groups_empty <- rownames_to_column(num_groups_empty, var = "term")
num_groups_1 <- as.data.frame(sapply(ranef(models_imputations$model_1[[1]]), nrow))
colnames(num_groups_1) <- "estimate"
num_groups_1 <- rownames_to_column(num_groups_1, var = "term")
num_groups_2 <- as.data.frame(sapply(ranef(models_imputations$model_2[[1]]), nrow))
colnames(num_groups_2) <- "estimate"
num_groups_2 <- rownames_to_column(num_groups_2, var = "term")
num_groups_3 <- as.data.frame(sapply(ranef(models_imputations$model_3[[1]]), nrow))
colnames(num_groups_3) <- "estimate"
num_groups_3 <- rownames_to_column(num_groups_3, var = "term")
# general goodness of fit stats (rename all nobs to avoid having differently names nobs in the texreg plotting)
glance_empty <- models_imputations %>%
unnest(glance_empty)%>%
ungroup()%>%
dplyr::select(AIC, nobs_empty)%>%
mutate(nobs_empty = as.numeric(nobs_empty))%>%
summarise(across(everything(), mean))%>%
pivot_longer(everything(), names_to = "term", values_to = "estimate")%>%
rbind(VarCorr_empty)%>%
rbind(num_groups_empty)%>%
dplyr::mutate(gof.decimal = ifelse(term %in% c("nobs_empty", "cabinet_name", "Country"), TRUE, FALSE))%>%
mutate(term = recode(term, "nobs_empty" = "nobs"))
glance_1 <- models_imputations %>%
unnest(glance_1)%>%
ungroup()%>%
dplyr::select(AIC, nobs_1)%>%
mutate(nobs_1 = as.numeric(nobs_1))%>%
summarise(across(everything(), mean))%>%
pivot_longer(everything(), names_to = "term", values_to = "estimate")%>%
rbind(VarCorr_1)%>%
rbind(num_groups_1)%>%
dplyr::mutate(gof.decimal = ifelse(term %in% c("nobs_1", "cabinet_name", "Country"), TRUE, FALSE))%>%
mutate(term = recode(term, "nobs_1" = "nobs"))
glance_2 <- models_imputations %>%
unnest(glance_2)%>%
ungroup()%>%
dplyr::select(AIC, nobs_2)%>%
mutate(nobs_2 = as.numeric(nobs_2))%>%
summarise(across(everything(), mean))%>%
pivot_longer(everything(), names_to = "term", values_to = "estimate")%>%
rbind(VarCorr_2)%>%
rbind(num_groups_2)%>%
dplyr::mutate(gof.decimal = ifelse(term %in% c("nobs_2", "cabinet_name", "Country"), TRUE, FALSE))%>%
mutate(term = recode(term, "nobs_2" = "nobs"))
glance_3 <- models_imputations %>%
unnest(glance_3)%>%
ungroup()%>%
dplyr::select(AIC, nobs_3)%>%
mutate(nobs_3 = as.numeric(nobs_3))%>%
summarise(across(everything(), mean))%>%
pivot_longer(everything(), names_to = "term", values_to = "estimate")%>%
rbind(VarCorr_3)%>%
rbind(num_groups_3)%>%
dplyr::mutate(gof.decimal = ifelse(term %in% c("nobs_3", "cabinet_name", "Country"), TRUE, FALSE))%>%
mutate(term = recode(term, "nobs_3" = "nobs"))
# overall summary of coefficient estimates
melded_summary_empty <- as.data.frame(cbind(t(coefs_melded_empty$q.mi),
t(coefs_melded_empty$se.mi))) %>%
magrittr::set_colnames(c("estimate", "std.error"))%>%
mutate(term = rownames(.)) %>%
dplyr::select(term, everything()) %>%
mutate(statistic = estimate / std.error,
conf.low = estimate + std.error * qt(0.025, model_degree_freedom_empty),
conf.high = estimate + std.error * qt(0.975, model_degree_freedom_empty),
p.value = 2 * pt(abs(statistic), model_degree_freedom_empty, lower.tail = FALSE)
)
melded_summary_1 <- as.data.frame(cbind(t(coefs_melded_1$q.mi),
t(coefs_melded_1$se.mi))) %>%
magrittr::set_colnames(c("estimate", "std.error"))%>%
mutate(term = rownames(.)) %>%
dplyr::select(term, everything()) %>%
mutate(statistic = estimate / std.error,
conf.low = estimate + std.error * qt(0.025, model_degree_freedom_1),
conf.high = estimate + std.error * qt(0.975, model_degree_freedom_1),
p.value = 2 * pt(abs(statistic), model_degree_freedom_1, lower.tail = FALSE)
)
melded_summary_2 <- as.data.frame(cbind(t(coefs_melded_2$q.mi),
t(coefs_melded_2$se.mi))) %>%
magrittr::set_colnames(c("estimate", "std.error"))%>%
mutate(term = rownames(.)) %>%
dplyr::select(term, everything()) %>%
mutate(statistic = estimate / std.error,
conf.low = estimate + std.error * qt(0.025, model_degree_freedom_2),
conf.high = estimate + std.error * qt(0.975, model_degree_freedom_2),
p.value = 2 * pt(abs(statistic), model_degree_freedom_2, lower.tail = FALSE)
)
melded_summary_3 <- as.data.frame(cbind(t(coefs_melded_3$q.mi),
t(coefs_melded_3$se.mi))) %>%
magrittr::set_colnames(c("estimate", "std.error"))%>%
mutate(term = rownames(.)) %>%
dplyr::select(term, everything()) %>%
mutate(statistic = estimate / std.error,
conf.low = estimate + std.error * qt(0.025, model_degree_freedom_3),
conf.high = estimate + std.error * qt(0.975, model_degree_freedom_3),
p.value = 2 * pt(abs(statistic), model_degree_freedom_3, lower.tail = FALSE)
)
# creating texreg object
texreg_melded_empty <- createTexreg(
coef.names = melded_summary_empty$term,
coef = melded_summary_empty$estimate,
se = melded_summary_empty$std.error,
pvalues = melded_summary_empty$p.value,
gof.names = glance_empty$term,
gof = glance_empty$estimate,
gof.decimal = glance_empty$estimate %% 1 > 0
)
texreg_melded_1 <- createTexreg(
coef.names = melded_summary_1$term,
coef = melded_summary_1$estimate,
se = melded_summary_1$std.error,
pvalues = melded_summary_1$p.value,
gof.names = glance_1$term,
gof = glance_1$estimate,
gof.decimal = glance_1$estimate %% 1 > 0
)
texreg_melded_2 <- createTexreg(
coef.names = melded_summary_2$term,
coef = melded_summary_2$estimate,
se = melded_summary_2$std.error,
pvalues = melded_summary_2$p.value,
gof.names = glance_2$term,
gof = glance_2$estimate,
gof.decimal = glance_2$estimate %% 1 > 0
)
texreg_melded_3 <- createTexreg(
coef.names = melded_summary_3$term,
coef = melded_summary_3$estimate,
se = melded_summary_3$std.error,
pvalues = melded_summary_3$p.value,
gof.names = glance_3$term,
gof = glance_3$estimate,
gof.decimal = glance_3$estimate %% 1 > 0
)
models_imputations_robust <- all_imputations %>%
mutate(
model_00 = data %>% map( ~ lmer(
dii_score_gdp_normal ~ investment_weighted_normal +
corp_index_within_normal + capb_normal + eu + deindustrialization_within_normal*corp_index_between_normal + deindustrialization_between_normal + trade_open_normal + h_polcon5_normal + unemployment_normal+ hard_debt_rule + small_state_binary_2 + splines::bs(Year, degree = 3) + (1 | cabinet_name) + (deindustrialization_within_normal | Country),
data = .,
na.action = na.omit,
control = lmerControl(optimizer = "Nelder_Mead"),
REML = TRUE)),
tidied_00 = model_00 %>% map(~ broom.mixed::tidy(., effects = c("fixed"))),
# we can also add the random coefficients here by just adding "ran_coefs" to the vectors
glance_00 = model_00 %>% map(~ broom.mixed::glance(.)),
VarCorr_00 = model_00 %>% map(~ as.tibble(VarCorr(.))),
nobs_00 = model_00%>% map(~nobs(.)),
model_01 = data %>% map(
~ lmer(
dii_score_gdp_normal ~ gov_seat_share_normal +
corp_index_within_normal + capb_normal + eu + deindustrialization_within_normal*corp_index_between_normal + deindustrialization_between_normal + trade_open_normal + h_polcon5_normal + unemployment_normal + hard_debt_rule+ small_state_binary_2 + splines::bs(Year, degree = 3) + gdp_capita_normal + (1 | cabinet_name) + (deindustrialization_within_normal | Country),
data = .,
na.action = na.omit,
control = lmerControl(optimizer = "Nelder_Mead"),
REML = TRUE
)
),
tidied_01 = model_01 %>% map(~ broom.mixed::tidy(., effects = c("fixed"))),
glance_01 = model_01 %>% map(~ broom.mixed::glance(.)),
VarCorr_01 = model_01 %>% map(~ as.tibble(VarCorr(.))),
nobs_01 = model_01%>% map(~nobs(.)),
model_02 = data %>% map(
~ lmer(
dii_score_gdp_normal ~ dii_score_gdp_lag_normal + gov_seat_share_normal +
corp_index_within_normal + capb_normal + eu + deindustrialization_within_normal*corp_index_between_normal + deindustrialization_between_normal + trade_open_normal + h_polcon5_normal + unemployment_normal + hard_debt_rule+ small_state_binary_2 + splines::bs(Year, degree = 3) + (1 | cabinet_name) + (deindustrialization_within_normal | Country),
data = .,
na.action = na.omit,
control = lmerControl(optimizer = "Nelder_Mead"),
REML = TRUE
)
),
tidied_02 = model_02 %>% map(~ broom.mixed::tidy(., effects = c("fixed"))),
glance_02 = model_02 %>% map(~ broom.mixed::glance(.)),
VarCorr_02 = model_02 %>% map(~ as.tibble(VarCorr(.))),
nobs_02 = model_02%>% map(~nobs(.)),
model_03 = data %>% map(
~ lmer(dii_score2_gdp_normal ~ gov_seat_share_normal +
corp_index_within_normal + capb_normal + eu + deindustrialization_within_normal*corp_index_between_normal + deindustrialization_between_normal + trade_open_normal + h_polcon5_normal + unemployment_normal+ hard_debt_rule + small_state_binary_2 + splines::bs(Year, degree = 3) + (1 | cabinet_name) + (deindustrialization_within_normal | Country),
data = .,
na.action = na.omit,
control = lmerControl(optimizer = "Nelder_Mead"),
REML = TRUE
)
),
tidied_03 = model_03 %>% map(~ broom.mixed::tidy(., effects = c("fixed"))),
glance_03 = model_03 %>% map(~ broom.mixed::glance(.)),
VarCorr_03 = model_03 %>% map(~ as.tibble(VarCorr(.))),
nobs_03 = model_03%>% map(~nobs(.))
)
# Create a wide data frame of just the coefficients and standard errors
params_00 <- models_imputations_robust %>%
unnest(tidied_00)%>%
dplyr::select(m, term, estimate, std.error)%>%
gather(key, value, estimate, std.error)%>%
spread(term, value)
params_01 <- models_imputations_robust %>%
unnest(tidied_01)%>%
dplyr::select(m, term, estimate, std.error)%>%
gather(key, value, estimate, std.error)%>%
spread(term, value)
params_02 <- models_imputations_robust %>%
unnest(tidied_02)%>%
dplyr::select(m, term, estimate, std.error)%>%
gather(key, value, estimate, std.error)%>%
spread(term, value)
params_03 <- models_imputations_robust %>%
unnest(tidied_03)%>%
dplyr::select(m, term, estimate, std.error)%>%
gather(key, value, estimate, std.error)%>%
spread(term, value)
# Extract just the coefficients
just_coefs_00 <- params_00 %>%
filter(key == "estimate")%>%
ungroup()%>%
dplyr::select(-m, -key)
just_coefs_01 <- params_01 %>%
filter(key == "estimate")%>%
ungroup()%>%
dplyr::select(-m, -key)
just_coefs_02 <- params_02 %>%
filter(key == "estimate")%>%
ungroup()%>%
dplyr::select(-m, -key)
just_coefs_03 <- params_03 %>%
filter(key == "estimate")%>%
ungroup()%>%
dplyr::select(-m, -key)
# Extract just the standard errors
just_ses_00 <- params_00 %>%
filter(key == "std.error")%>%
ungroup()%>%
dplyr::select(-m, -key)
just_ses_01 <- params_01 %>%
filter(key == "std.error")%>%
ungroup()%>%
dplyr::select(-m, -key)
just_ses_02 <- params_02 %>%
filter(key == "std.error")%>%
ungroup()%>%
dplyr::select(-m, -key)
just_ses_03 <- params_03 %>%
filter(key == "std.error")%>%
ungroup()%>%
dplyr::select(-m, -key)
#then we use amelias mi.meld function to combine estimates and se according to rubin's formula
coefs_melded_00 <- mi.meld(just_coefs_00, just_ses_00)
coefs_melded_01 <- mi.meld(just_coefs_01, just_ses_01)
coefs_melded_02 <- mi.meld(just_coefs_02, just_ses_02)
coefs_melded_03 <- mi.meld(just_coefs_03, just_ses_03)
# dfs
model_degree_freedom_00 <- models_imputations_robust %>%
unnest(glance_00) %>%
filter(m == "imp1")%>%
pull(df.residual)
model_degree_freedom_01 <- models_imputations_robust %>%
unnest(glance_01) %>%
filter(m == "imp1")%>%
pull(df.residual)
model_degree_freedom_02 <- models_imputations_robust %>%
unnest(glance_02) %>%
filter(m == "imp1")%>%
pull(df.residual)
model_degree_freedom_03 <- models_imputations_robust %>%
unnest(glance_03) %>%
filter(m == "imp1")%>%
pull(df.residual)
# variance/ICC
VarCorr_00 <- models_imputations_robust %>%
unnest(VarCorr_00)%>%
ungroup()%>%
replace_na(list(var1 = "", var2 = "")) %>%
unite(term, grp, var1,var2, remove = FALSE, sep = "")%>%
group_by(term)%>%
summarize( vcov = mean(vcov), sdcor = mean(sdcor))%>%
rename(estimate = vcov)%>%
mutate(term = recode(term, "Country(Intercept)" = "Variance Country Level", "cabinet_name(Intercept)" = "Variance Government Level", "Country(Intercept)deindustrialization_within_normal" = "Covariance Random Slope/Intercept", "Countrydeindustrialization_within_normal" = "Variance Random Slope"))%>%
dplyr::select(-sdcor)
VarCorr_01 <- models_imputations_robust %>%
unnest(VarCorr_01)%>%
ungroup()%>%
replace_na(list(var1 = "", var2 = "")) %>%
unite(term, grp, var1,var2, remove = FALSE, sep = "")%>%
group_by(term)%>%
summarize( vcov = mean(vcov), sdcor = mean(sdcor))%>%
rename(estimate = vcov)%>%
mutate(term = recode(term, "Country(Intercept)" = "Variance Country Level", "cabinet_name(Intercept)" = "Variance Government Level", "Country(Intercept)deindustrialization_within_normal" = "Covariance Random Slope/Intercept", "Countrydeindustrialization_within_normal" = "Variance Random Slope"))%>%
dplyr::select(-sdcor)
VarCorr_02 <- models_imputations_robust %>%
unnest(VarCorr_02)%>%
ungroup()%>%
replace_na(list(var1 = "", var2 = "")) %>%
unite(term, grp, var1,var2, remove = FALSE, sep = "")%>%
group_by(term)%>%
summarize( vcov = mean(vcov), sdcor = mean(sdcor))%>%
rename(estimate = vcov)%>%
mutate(term = recode(term, "Country(Intercept)" = "Variance Country Level", "cabinet_name(Intercept)" = "Variance Government Level", "Country(Intercept)deindustrialization_within_normal" = "Covariance Random Slope/Intercept", "Countrydeindustrialization_within_normal" = "Variance Random Slope"))%>%
dplyr::select(-sdcor)
VarCorr_03 <- models_imputations_robust %>%
unnest(VarCorr_03)%>%
ungroup()%>%
replace_na(list(var1 = "", var2 = "")) %>%
unite(term, grp, var1,var2, remove = FALSE, sep = "")%>%
group_by(term)%>%
summarize( vcov = mean(vcov), sdcor = mean(sdcor))%>%
rename(estimate = vcov)%>%
mutate(term = recode(term, "Country(Intercept)" = "Variance Country Level", "cabinet_name(Intercept)" = "Variance Government Level", "Country(Intercept)deindustrialization_within_normal" = "Covariance Random Slope/Intercept", "Countrydeindustrialization_within_normal" = "Variance Random Slope"))%>%
dplyr::select(-sdcor)
# here we can just extract the number of grouped observations from the first model as they are the same for all imputations of this particular model
num_groups_00 <- as.data.frame(sapply(ranef(models_imputations_robust$model_00[[1]]), nrow))
colnames(num_groups_00) <- "estimate"
num_groups_00 <- rownames_to_column(num_groups_00, var = "term")
num_groups_01 <- as.data.frame(sapply(ranef(models_imputations_robust$model_01[[1]]), nrow))
colnames(num_groups_01) <- "estimate"
num_groups_01 <- rownames_to_column(num_groups_01, var = "term")
num_groups_02 <- as.data.frame(sapply(ranef(models_imputations_robust$model_02[[1]]), nrow))
colnames(num_groups_02) <- "estimate"
num_groups_02 <- rownames_to_column(num_groups_02, var = "term")
num_groups_03 <- as.data.frame(sapply(ranef(models_imputations_robust$model_03[[1]]), nrow))
colnames(num_groups_03) <- "estimate"
num_groups_03 <- rownames_to_column(num_groups_03, var = "term")
# general goodness of fit stats (rename all nobs to avoid having differently names nobs in the texreg plotting)
glance_00 <- models_imputations_robust %>%
unnest(glance_00)%>%
ungroup()%>%
dplyr::select(AIC, nobs_00)%>%
mutate(nobs_00 = as.numeric(nobs_00))%>%
summarise(across(everything(), mean))%>%
pivot_longer(everything(), names_to = "term", values_to = "estimate")%>%
rbind(VarCorr_00)%>%
rbind(num_groups_00)%>%
dplyr::mutate(gof.decimal = ifelse(term %in% c("nobs_00", "cabinet_name", "Country"), TRUE, FALSE))%>%
mutate(term = recode(term, "nobs_00" = "nobs"))
glance_01 <- models_imputations_robust %>%
unnest(glance_01)%>%
ungroup()%>%
dplyr::select(AIC, nobs_01)%>%
mutate(nobs_01 = as.numeric(nobs_01))%>%
summarise(across(everything(), mean))%>%
pivot_longer(everything(), names_to = "term", values_to = "estimate")%>%
rbind(VarCorr_01)%>%
rbind(num_groups_01)%>%
dplyr::mutate(gof.decimal = ifelse(term %in% c("nobs_01", "cabinet_name", "Country"), TRUE, FALSE))%>%
mutate(term = recode(term, "nobs_01" = "nobs"))
glance_02 <- models_imputations_robust %>%
unnest(glance_02)%>%
ungroup()%>%
dplyr::select(AIC, nobs_02)%>%
mutate(nobs_02 = as.numeric(nobs_02))%>%
summarise(across(everything(), mean))%>%
pivot_longer(everything(), names_to = "term", values_to = "estimate")%>%
rbind(VarCorr_02)%>%
rbind(num_groups_02)%>%
dplyr::mutate(gof.decimal = ifelse(term %in% c("nobs_02", "cabinet_name", "Country"), TRUE, FALSE))%>%
mutate(term = recode(term, "nobs_02" = "nobs"))
glance_03 <- models_imputations_robust %>%
unnest(glance_03)%>%
ungroup()%>%
dplyr::select(AIC, nobs_03)%>%
mutate(nobs_03 = as.numeric(nobs_03))%>%
summarise(across(everything(), mean))%>%
pivot_longer(everything(), names_to = "term", values_to = "estimate")%>%
rbind(VarCorr_03)%>%
rbind(num_groups_03)%>%
dplyr::mutate(gof.decimal = ifelse(term %in% c("nobs_03", "cabinet_name", "Country"), TRUE, FALSE))%>%
mutate(term = recode(term, "nobs_03" = "nobs"))
# overall summary of coefficient estimates
melded_summary_00 <- as.data.frame(cbind(t(coefs_melded_00$q.mi),
t(coefs_melded_00$se.mi))) %>%
magrittr::set_colnames(c("estimate", "std.error"))%>%
mutate(term = rownames(.)) %>%
dplyr::select(term, everything()) %>%
mutate(statistic = estimate / std.error,
conf.low = estimate + std.error * qt(0.025, model_degree_freedom_00),
conf.high = estimate + std.error * qt(0.975, model_degree_freedom_00),
p.value = 2 * pt(abs(statistic), model_degree_freedom_00, lower.tail = FALSE)
)
melded_summary_01 <- as.data.frame(cbind(t(coefs_melded_01$q.mi),
t(coefs_melded_01$se.mi))) %>%
magrittr::set_colnames(c("estimate", "std.error"))%>%
mutate(term = rownames(.)) %>%
dplyr::select(term, everything()) %>%
mutate(statistic = estimate / std.error,
conf.low = estimate + std.error * qt(0.025, model_degree_freedom_01),
conf.high = estimate + std.error * qt(0.975, model_degree_freedom_01),
p.value = 2 * pt(abs(statistic), model_degree_freedom_01, lower.tail = FALSE)
)
melded_summary_02 <- as.data.frame(cbind(t(coefs_melded_02$q.mi),
t(coefs_melded_02$se.mi))) %>%
magrittr::set_colnames(c("estimate", "std.error"))%>%
mutate(term = rownames(.)) %>%
dplyr::select(term, everything()) %>%
mutate(statistic = estimate / std.error,
conf.low = estimate + std.error * qt(0.025, model_degree_freedom_02),
conf.high = estimate + std.error * qt(0.975, model_degree_freedom_02),
p.value = 2 * pt(abs(statistic), model_degree_freedom_02, lower.tail = FALSE)
)
melded_summary_03 <- as.data.frame(cbind(t(coefs_melded_03$q.mi),
t(coefs_melded_03$se.mi))) %>%
magrittr::set_colnames(c("estimate", "std.error"))%>%
mutate(term = rownames(.)) %>%
dplyr::select(term, everything()) %>%
mutate(statistic = estimate / std.error,
conf.low = estimate + std.error * qt(0.025, model_degree_freedom_03),
conf.high = estimate + std.error * qt(0.975, model_degree_freedom_03),
p.value = 2 * pt(abs(statistic), model_degree_freedom_03, lower.tail = FALSE)
)
# creating texreg object
texreg_melded_00 <- createTexreg(
coef.names = melded_summary_00$term,
coef = melded_summary_00$estimate,
se = melded_summary_00$std.error,
pvalues = melded_summary_00$p.value,
gof.names = glance_00$term,
gof = glance_00$estimate,
gof.decimal = glance_00$estimate %% 1 > 0
)
texreg_melded_01 <- createTexreg(
coef.names = melded_summary_01$term,
coef = melded_summary_01$estimate,
se = melded_summary_01$std.error,
pvalues = melded_summary_01$p.value,
gof.names = glance_01$term,
gof = glance_01$estimate,
gof.decimal = glance_01$estimate %% 1 > 0
)
texreg_melded_02 <- createTexreg(
coef.names = melded_summary_02$term,
coef = melded_summary_02$estimate,
se = melded_summary_02$std.error,
pvalues = melded_summary_02$p.value,
gof.names = glance_02$term,
gof = glance_02$estimate,
gof.decimal = glance_02$estimate %% 1 > 0
)
texreg_melded_03 <- createTexreg(
coef.names = melded_summary_03$term,
coef = melded_summary_03$estimate,
se = melded_summary_03$std.error,
pvalues = melded_summary_03$p.value,
gof.names = glance_03$term,
gof = glance_03$estimate,
gof.decimal = glance_03$estimate %% 1 > 0
)
models_imputations_robust_3 <- all_imputations %>%
mutate(
model_04 = data %>% map( ~ lmer(
dii_score_gdp_normal ~ gov_seat_share_normal +
corp_index_within_normal + capb_normal + eu + deindustrialization_within_normal*corp_index_between_normal + deindustrialization_between_normal + trade_open_normal + h_polcon5_normal + unemployment_normal+ hard_debt_rule + fdi_inflows_normal + small_state_binary_2 + splines::bs(Year, degree = 3) + (1 | cabinet_name) + (deindustrialization_within_normal | Country),
data = .,
na.action = na.omit,
control = lmerControl(optimizer = "Nelder_Mead"),
REML = TRUE)),
tidied_04 = model_04 %>% map(~ broom.mixed::tidy(., effects = c("fixed"))),
# we can also add the random coefficients here by just adding "ran_coefs" to the vectors
glance_04 = model_04 %>% map(~ broom.mixed::glance(.)),
VarCorr_04 = model_04 %>% map(~ as.tibble(VarCorr(.))),
nobs_04 = model_04%>% map(~nobs(.)),
model_05 = data %>% map(
~ lmer(
dii_score_gdp_normal ~ gov_seat_share_normal +
corp_index_fun_within_normal + capb_normal + eu + deindustrialization_within_normal*corp_index_fun_between_normal + deindustrialization_between_normal + trade_open_normal + h_polcon5_normal + unemployment_normal + hard_debt_rule+ small_state_binary_2 + splines::bs(Year, degree = 3) + (1 | cabinet_name) + (deindustrialization_within_normal | Country),
data = .,
na.action = na.omit,
control = lmerControl(optimizer = "Nelder_Mead"),
REML = TRUE
)
),
tidied_05 = model_05 %>% map(~ broom.mixed::tidy(., effects = c("fixed"))),
glance_05 = model_05 %>% map(~ broom.mixed::glance(.)),
VarCorr_05 = model_05 %>% map(~ as.tibble(VarCorr(.))),
nobs_05 = model_05%>% map(~nobs(.)),
model_06 = data %>% map(
~ lmer(
dii_score_gdp_normal ~ gov_seat_share_normal +
corp_index_within_normal + capb_normal + eu + deindustrialization_within_normal*corp_index_between_normal + deindustrialization_between_normal + trade_open_normal + h_polcon5_normal + employment_normal + hard_debt_rule+ small_state_binary_2 + splines::bs(Year, degree = 3) + (1 | cabinet_name) + (deindustrialization_within_normal | Country),
data = .,
na.action = na.omit,
control = lmerControl(optimizer = "Nelder_Mead"),
REML = TRUE
)
),
tidied_06 = model_06 %>% map(~ broom.mixed::tidy(., effects = c("fixed"))),
glance_06 = model_06 %>% map(~ broom.mixed::glance(.)),
VarCorr_06 = model_06 %>% map(~ as.tibble(VarCorr(.))),
nobs_06 = model_06%>% map(~nobs(.)),
model_07 = data %>% map(
~ lmer(dii_score_gdp_sel_normal ~ gov_seat_share_normal +
corp_index_within_normal + capb_normal + eu + deindustrialization_within_normal*corp_index_between_normal + deindustrialization_between_normal + trade_open_normal + h_polcon5_normal + unemployment_normal+ hard_debt_rule + small_state_binary_2 + splines::bs(Year, degree = 3) + (1 | cabinet_name) + (deindustrialization_within_normal | Country),
data = .,
na.action = na.omit,
control = lmerControl(optimizer = "Nelder_Mead"),
REML = TRUE
)
),
tidied_07 = model_07 %>% map(~ broom.mixed::tidy(., effects = c("fixed"))),
glance_07 = model_07 %>% map(~ broom.mixed::glance(.)),
VarCorr_07 = model_07 %>% map(~ as.tibble(VarCorr(.))),
nobs_07 = model_07%>% map(~nobs(.)),
model_08 = data %>% map(
~ lmer(dii_score_gdp_normal ~ gov_seat_share_normal +
corp_index_within_normal + capb_normal + eu + deindustrialization_within_normal*corp_index_between_normal + deindustrialization_between_normal + trade_open_normal + h_polcon3_normal + unemployment_normal+ hard_debt_rule + small_state_binary_2 + splines::bs(Year, degree = 3) + (1 | cabinet_name) + (deindustrialization_within_normal | Country),
data = .,
na.action = na.omit,
control = lmerControl(optimizer = "Nelder_Mead"),
REML = TRUE
)
),
tidied_08 = model_08 %>% map(~ broom.mixed::tidy(., effects = c("fixed"))),
glance_08 = model_08 %>% map(~ broom.mixed::glance(.)),
VarCorr_08 = model_08 %>% map(~ as.tibble(VarCorr(.))),
nobs_08 = model_08%>% map(~nobs(.)),
model_09 = data %>% map(
~ lmer(dii_score_gdp_normal ~ gov_seat_share_normal +
corp_index_within_normal + capb_normal + eu + deindustrialization_within_normal*corp_index_between_normal + deindustrialization_between_normal + trade_open_normal + h_polcon5_between_normal + h_polcon5_within_normal + unemployment_normal+ hard_debt_rule + small_state_binary_2 + splines::bs(Year, degree = 3) + (1 | cabinet_name) + (deindustrialization_within_normal | Country),
data = .,
na.action = na.omit,
control = lmerControl(optimizer = "Nelder_Mead"),
REML = TRUE
)
),
tidied_09 = model_09 %>% map(~ broom.mixed::tidy(., effects = c("fixed"))),
glance_09 = model_09 %>% map(~ broom.mixed::glance(.)),
VarCorr_09 = model_09 %>% map(~ as.tibble(VarCorr(.))),
nobs_09 = model_09%>% map(~nobs(.)),
model_10 = data %>% map( ~ lmer(
dii_score_gdp_normal ~ gov_seat_share_normal +
corp_index_within_normal + debt_normal + eu + deindustrialization_within_normal*corp_index_between_normal + deindustrialization_between_normal + trade_open_normal + h_polcon5_normal + unemployment_normal+ hard_debt_rule + small_state_binary_2 + splines::bs(Year, degree = 3) + (1 | cabinet_name) + (deindustrialization_within_normal | Country),
data = .,
na.action = na.omit,
control = lmerControl(optimizer = "Nelder_Mead"),
REML = TRUE)),
tidied_10 = model_10 %>% map(~ broom.mixed::tidy(., effects = c("fixed"))),
# we can also add the random coefficients here by just adding "ran_coefs" to the vectors
glance_10 = model_10 %>% map(~ broom.mixed::glance(.)),
VarCorr_10 = model_10 %>% map(~ as.tibble(VarCorr(.))),
nobs_10 = model_10%>% map(~nobs(.)),
model_11 = data %>% map( ~ lmer(
dii_score_gdp_normal ~ gov_seat_share_normal +
corp_index_within_normal + capb_normal + eu + deindustrialization_within_normal*corp_index_between_normal + deindustrialization_between_normal + trade_open_normal + h_polcon5_normal + unemployment_normal + share_elderly_normal + hard_debt_rule + small_state_binary_2 + splines::bs(Year, degree = 3) + (1 | cabinet_name) + (deindustrialization_within_normal | Country),
data = .,
na.action = na.omit,
control = lmerControl(optimizer = "Nelder_Mead"),
REML = TRUE)),
tidied_11 = model_11 %>% map(~ broom.mixed::tidy(., effects = c("fixed"))),
# we can also add the random coefficients here by just adding "ran_coefs" to the vectors
glance_11 = model_11 %>% map(~ broom.mixed::glance(.)),
VarCorr_11 = model_11 %>% map(~ as.tibble(VarCorr(.))),
nobs_11 = model_11%>% map(~nobs(.))
)
# Create a wide data frame of just the coefficients and standard errors
params_04 <- models_imputations_robust_3 %>%
unnest(tidied_04)%>%
dplyr::select(m, term, estimate, std.error)%>%
gather(key, value, estimate, std.error)%>%
spread(term, value)
params_05 <- models_imputations_robust_3 %>%
unnest(tidied_05)%>%
dplyr::select(m, term, estimate, std.error)%>%
gather(key, value, estimate, std.error)%>%
spread(term, value)
params_06 <- models_imputations_robust_3 %>%
unnest(tidied_06)%>%
dplyr::select(m, term, estimate, std.error)%>%
gather(key, value, estimate, std.error)%>%
spread(term, value)
params_07 <- models_imputations_robust_3 %>%
unnest(tidied_07)%>%
dplyr::select(m, term, estimate, std.error)%>%
gather(key, value, estimate, std.error)%>%
spread(term, value)
params_07 <- models_imputations_robust_3 %>%
unnest(tidied_07)%>%
dplyr::select(m, term, estimate, std.error)%>%
gather(key, value, estimate, std.error)%>%
spread(term, value)
params_08 <- models_imputations_robust_3 %>%
unnest(tidied_08)%>%
dplyr::select(m, term, estimate, std.error)%>%
gather(key, value, estimate, std.error)%>%
spread(term, value)
params_09 <- models_imputations_robust_3 %>%
unnest(tidied_09)%>%
dplyr::select(m, term, estimate, std.error)%>%
gather(key, value, estimate, std.error)%>%
spread(term, value)
params_10 <- models_imputations_robust_3 %>%
unnest(tidied_10)%>%
dplyr::select(m, term, estimate, std.error)%>%
gather(key, value, estimate, std.error)%>%
spread(term, value)
params_11 <- models_imputations_robust_3 %>%
unnest(tidied_11)%>%
dplyr::select(m, term, estimate, std.error)%>%
gather(key, value, estimate, std.error)%>%
spread(term, value)
# Extract just the coefficients
just_coefs_04 <- params_04 %>%
filter(key == "estimate")%>%
ungroup()%>%
dplyr::select(-m, -key)
just_coefs_05 <- params_05 %>%
filter(key == "estimate")%>%
ungroup()%>%
dplyr::select(-m, -key)
just_coefs_06 <- params_06 %>%
filter(key == "estimate")%>%
ungroup()%>%
dplyr::select(-m, -key)
just_coefs_07 <- params_07 %>%
filter(key == "estimate")%>%
ungroup()%>%
dplyr::select(-m, -key)
just_coefs_08 <- params_08 %>%
filter(key == "estimate")%>%
ungroup()%>%
dplyr::select(-m, -key)
just_coefs_09 <- params_09 %>%
filter(key == "estimate")%>%
ungroup()%>%
dplyr::select(-m, -key)
just_coefs_10 <- params_10 %>%
filter(key == "estimate")%>%
ungroup()%>%
dplyr::select(-m, -key)
just_coefs_11 <- params_11 %>%
filter(key == "estimate")%>%
ungroup()%>%
dplyr::select(-m, -key)
# Extract just the standard errors
just_ses_04 <- params_04 %>%
filter(key == "std.error")%>%
ungroup()%>%
dplyr::select(-m, -key)
just_ses_05 <- params_05 %>%
filter(key == "std.error")%>%
ungroup()%>%
dplyr::select(-m, -key)
just_ses_06 <- params_06 %>%
filter(key == "std.error")%>%
ungroup()%>%
dplyr::select(-m, -key)
just_ses_07 <- params_07 %>%
filter(key == "std.error")%>%
ungroup()%>%
dplyr::select(-m, -key)
just_ses_08 <- params_08 %>%
filter(key == "std.error")%>%
ungroup()%>%
dplyr::select(-m, -key)
just_ses_09 <- params_09 %>%
filter(key == "std.error")%>%
ungroup()%>%
dplyr::select(-m, -key)
just_ses_10 <- params_10 %>%
filter(key == "std.error")%>%
ungroup()%>%
dplyr::select(-m, -key)
just_ses_11 <- params_11 %>%
filter(key == "std.error")%>%
ungroup()%>%
dplyr::select(-m, -key)
#then we use amelias mi.meld function to combine estimates and se according to rubin's formula
coefs_melded_04 <- mi.meld(just_coefs_04, just_ses_04)
coefs_melded_05 <- mi.meld(just_coefs_05, just_ses_05)
coefs_melded_06 <- mi.meld(just_coefs_06, just_ses_06)
coefs_melded_07 <- mi.meld(just_coefs_07, just_ses_07)
coefs_melded_08 <- mi.meld(just_coefs_08, just_ses_08)
coefs_melded_09 <- mi.meld(just_coefs_09, just_ses_09)
coefs_melded_10 <- mi.meld(just_coefs_10, just_ses_10)
coefs_melded_11 <- mi.meld(just_coefs_11, just_ses_11)
# dfs
model_degree_freedom_04 <- models_imputations_robust_3 %>%
unnest(glance_04) %>%
filter(m == "imp1")%>%
pull(df.residual)
model_degree_freedom_05 <- models_imputations_robust_3 %>%
unnest(glance_05) %>%
filter(m == "imp1")%>%
pull(df.residual)
model_degree_freedom_06 <- models_imputations_robust_3 %>%
unnest(glance_06) %>%
filter(m == "imp1")%>%
pull(df.residual)
model_degree_freedom_07 <- models_imputations_robust_3 %>%
unnest(glance_07) %>%
filter(m == "imp1")%>%
pull(df.residual)
model_degree_freedom_08 <- models_imputations_robust_3 %>%
unnest(glance_08) %>%
filter(m == "imp1")%>%
pull(df.residual)
model_degree_freedom_09 <- models_imputations_robust_3 %>%
unnest(glance_09) %>%
filter(m == "imp1")%>%
pull(df.residual)
model_degree_freedom_10 <- models_imputations_robust_3 %>%
unnest(glance_10) %>%
filter(m == "imp1")%>%
pull(df.residual)
model_degree_freedom_11 <- models_imputations_robust_3 %>%
unnest(glance_11) %>%
filter(m == "imp1")%>%
pull(df.residual)
# variance/ICC
VarCorr_04 <- models_imputations_robust_3 %>%
unnest(VarCorr_04)%>%
ungroup()%>%
replace_na(list(var1 = "", var2 = "")) %>%
unite(term, grp, var1,var2, remove = FALSE, sep = "")%>%
group_by(term)%>%
summarize( vcov = mean(vcov), sdcor = mean(sdcor))%>%
rename(estimate = vcov)%>%
mutate(term = recode(term, "Country(Intercept)" = "Variance Country Level", "cabinet_name(Intercept)" = "Variance Government Level", "Country(Intercept)deindustrialization_within_normal" = "Covariance Random Slope/Intercept", "Countrydeindustrialization_within_normal" = "Variance Random Slope"))%>%
dplyr::select(-sdcor)
VarCorr_05 <- models_imputations_robust_3 %>%
unnest(VarCorr_05)%>%
ungroup()%>%
replace_na(list(var1 = "", var2 = "")) %>%
unite(term, grp, var1,var2, remove = FALSE, sep = "")%>%
group_by(term)%>%
summarize( vcov = mean(vcov), sdcor = mean(sdcor))%>%
rename(estimate = vcov)%>%
mutate(term = recode(term, "Country(Intercept)" = "Variance Country Level", "cabinet_name(Intercept)" = "Variance Government Level", "Country(Intercept)deindustrialization_within_normal" = "Covariance Random Slope/Intercept", "Countrydeindustrialization_within_normal" = "Variance Random Slope"))%>%
dplyr::select(-sdcor)
VarCorr_06 <- models_imputations_robust_3 %>%
unnest(VarCorr_06)%>%
ungroup()%>%
replace_na(list(var1 = "", var2 = "")) %>%
unite(term, grp, var1,var2, remove = FALSE, sep = "")%>%
group_by(term)%>%
summarize( vcov = mean(vcov), sdcor = mean(sdcor))%>%
rename(estimate = vcov)%>%
mutate(term = recode(term, "Country(Intercept)" = "Variance Country Level", "cabinet_name(Intercept)" = "Variance Government Level", "Country(Intercept)deindustrialization_within_normal" = "Covariance Random Slope/Intercept", "Countrydeindustrialization_within_normal" = "Variance Random Slope"))%>%
dplyr::select(-sdcor)
VarCorr_07 <- models_imputations_robust_3 %>%
unnest(VarCorr_07)%>%
ungroup()%>%
replace_na(list(var1 = "", var2 = "")) %>%
unite(term, grp, var1,var2, remove = FALSE, sep = "")%>%
group_by(term)%>%
summarize( vcov = mean(vcov), sdcor = mean(sdcor))%>%
rename(estimate = vcov)%>%
mutate(term = recode(term, "Country(Intercept)" = "Variance Country Level", "cabinet_name(Intercept)" = "Variance Government Level", "Country(Intercept)deindustrialization_within_normal" = "Covariance Random Slope/Intercept", "Countrydeindustrialization_within_normal" = "Variance Random Slope"))%>%
dplyr::select(-sdcor)
VarCorr_08 <- models_imputations_robust_3 %>%
unnest(VarCorr_08)%>%
ungroup()%>%
replace_na(list(var1 = "", var2 = "")) %>%
unite(term, grp, var1,var2, remove = FALSE, sep = "")%>%
group_by(term)%>%
summarize( vcov = mean(vcov), sdcor = mean(sdcor))%>%
rename(estimate = vcov)%>%
mutate(term = recode(term, "Country(Intercept)" = "Variance Country Level", "cabinet_name(Intercept)" = "Variance Government Level", "Country(Intercept)deindustrialization_within_normal" = "Covariance Random Slope/Intercept", "Countrydeindustrialization_within_normal" = "Variance Random Slope"))%>%
dplyr::select(-sdcor)
VarCorr_09 <- models_imputations_robust_3 %>%
unnest(VarCorr_09)%>%
ungroup()%>%
replace_na(list(var1 = "", var2 = "")) %>%
unite(term, grp, var1,var2, remove = FALSE, sep = "")%>%
group_by(term)%>%
summarize( vcov = mean(vcov), sdcor = mean(sdcor))%>%
rename(estimate = vcov)%>%
mutate(term = recode(term, "Country(Intercept)" = "Variance Country Level", "cabinet_name(Intercept)" = "Variance Government Level", "Country(Intercept)deindustrialization_within_normal" = "Covariance Random Slope/Intercept", "Countrydeindustrialization_within_normal" = "Variance Random Slope"))%>%
dplyr::select(-sdcor)
VarCorr_10 <- models_imputations_robust_3 %>%
unnest(VarCorr_10)%>%
ungroup()%>%
replace_na(list(var1 = "", var2 = "")) %>%
unite(term, grp, var1,var2, remove = FALSE, sep = "")%>%
group_by(term)%>%
summarize( vcov = mean(vcov), sdcor = mean(sdcor))%>%
rename(estimate = vcov)%>%
mutate(term = recode(term, "Country(Intercept)" = "Variance Country Level", "cabinet_name(Intercept)" = "Variance Government Level", "Country(Intercept)deindustrialization_within_normal" = "Covariance Random Slope/Intercept", "Countrydeindustrialization_within_normal" = "Variance Random Slope"))%>%
dplyr::select(-sdcor)
VarCorr_11 <- models_imputations_robust_3 %>%
unnest(VarCorr_11)%>%
ungroup()%>%
replace_na(list(var1 = "", var2 = "")) %>%
unite(term, grp, var1,var2, remove = FALSE, sep = "")%>%
group_by(term)%>%
summarize( vcov = mean(vcov), sdcor = mean(sdcor))%>%
rename(estimate = vcov)%>%
mutate(term = recode(term, "Country(Intercept)" = "Variance Country Level", "cabinet_name(Intercept)" = "Variance Government Level", "Country(Intercept)deindustrialization_within_normal" = "Covariance Random Slope/Intercept", "Countrydeindustrialization_within_normal" = "Variance Random Slope"))%>%
dplyr::select(-sdcor)
# here we can just extract the number of grouped observations from the first model as they are the same for all imputations of this particular model
num_groups_04 <- as.data.frame(sapply(ranef(models_imputations_robust_3$model_04[[1]]), nrow))
colnames(num_groups_04) <- "estimate"
num_groups_04 <- rownames_to_column(num_groups_04, var = "term")
num_groups_05 <- as.data.frame(sapply(ranef(models_imputations_robust_3$model_05[[1]]), nrow))
colnames(num_groups_05) <- "estimate"
num_groups_05 <- rownames_to_column(num_groups_05, var = "term")
num_groups_06 <- as.data.frame(sapply(ranef(models_imputations_robust_3$model_06[[1]]), nrow))
colnames(num_groups_06) <- "estimate"
num_groups_06 <- rownames_to_column(num_groups_06, var = "term")
num_groups_07 <- as.data.frame(sapply(ranef(models_imputations_robust_3$model_07[[1]]), nrow))
colnames(num_groups_07) <- "estimate"
num_groups_07 <- rownames_to_column(num_groups_07, var = "term")
num_groups_08 <- as.data.frame(sapply(ranef(models_imputations_robust_3$model_08[[1]]), nrow))
colnames(num_groups_08) <- "estimate"
num_groups_08 <- rownames_to_column(num_groups_08, var = "term")
num_groups_09 <- as.data.frame(sapply(ranef(models_imputations_robust_3$model_09[[1]]), nrow))
colnames(num_groups_09) <- "estimate"
num_groups_09 <- rownames_to_column(num_groups_09, var = "term")
num_groups_10 <- as.data.frame(sapply(ranef(models_imputations_robust_3$model_10[[1]]), nrow))
colnames(num_groups_10) <- "estimate"
num_groups_10 <- rownames_to_column(num_groups_10, var = "term")
num_groups_11 <- as.data.frame(sapply(ranef(models_imputations_robust_3$model_11[[1]]), nrow))
colnames(num_groups_11) <- "estimate"
num_groups_11 <- rownames_to_column(num_groups_11, var = "term")
# general goodness of fit stats (rename all nobs to avoid having differently names nobs in the texreg plotting)
glance_04 <- models_imputations_robust_3 %>%
unnest(glance_04)%>%
ungroup()%>%
dplyr::select(AIC, nobs_04)%>%
mutate(nobs_04 = as.numeric(nobs_04))%>%
summarise(across(everything(), mean))%>%
pivot_longer(everything(), names_to = "term", values_to = "estimate")%>%
rbind(VarCorr_04)%>%
rbind(num_groups_04)%>%
dplyr::mutate(gof.decimal = ifelse(term %in% c("nobs_04", "cabinet_name", "Country"), TRUE, FALSE))%>%
mutate(term = recode(term, "nobs_04" = "nobs"))
glance_05 <- models_imputations_robust_3 %>%
unnest(glance_05)%>%
ungroup()%>%
dplyr::select(AIC, nobs_05)%>%
mutate(nobs_05 = as.numeric(nobs_05))%>%
summarise(across(everything(), mean))%>%
pivot_longer(everything(), names_to = "term", values_to = "estimate")%>%
rbind(VarCorr_01)%>%
rbind(num_groups_05)%>%
dplyr::mutate(gof.decimal = ifelse(term %in% c("nobs_05", "cabinet_name", "Country"), TRUE, FALSE))%>%
mutate(term = recode(term, "nobs_05" = "nobs"))
glance_06 <- models_imputations_robust_3 %>%
unnest(glance_06)%>%
ungroup()%>%
dplyr::select(AIC, nobs_06)%>%
mutate(nobs_06 = as.numeric(nobs_06))%>%
summarise(across(everything(), mean))%>%
pivot_longer(everything(), names_to = "term", values_to = "estimate")%>%
rbind(VarCorr_06)%>%
rbind(num_groups_06)%>%
dplyr::mutate(gof.decimal = ifelse(term %in% c("nobs_06", "cabinet_name", "Country"), TRUE, FALSE))%>%
mutate(term = recode(term, "nobs_06" = "nobs"))
glance_07 <- models_imputations_robust_3 %>%
unnest(glance_07)%>%
ungroup()%>%
dplyr::select(AIC, nobs_07)%>%
mutate(nobs_07 = as.numeric(nobs_07))%>%
summarise(across(everything(), mean))%>%
pivot_longer(everything(), names_to = "term", values_to = "estimate")%>%
rbind(VarCorr_07)%>%
rbind(num_groups_07)%>%
dplyr::mutate(gof.decimal = ifelse(term %in% c("nobs_07", "cabinet_name", "Country"), TRUE, FALSE))%>%
mutate(term = recode(term, "nobs_07" = "nobs"))
glance_08 <- models_imputations_robust_3 %>%
unnest(glance_08)%>%
ungroup()%>%
dplyr::select(AIC, nobs_08)%>%
mutate(nobs_08 = as.numeric(nobs_08))%>%
summarise(across(everything(), mean))%>%
pivot_longer(everything(), names_to = "term", values_to = "estimate")%>%
rbind(VarCorr_08)%>%
rbind(num_groups_08)%>%
dplyr::mutate(gof.decimal = ifelse(term %in% c("nobs_08", "cabinet_name", "Country"), TRUE, FALSE))%>%
mutate(term = recode(term, "nobs_08" = "nobs"))
glance_09 <- models_imputations_robust_3 %>%
unnest(glance_09)%>%
ungroup()%>%
dplyr::select(AIC, nobs_09)%>%
mutate(nobs_09 = as.numeric(nobs_09))%>%
summarise(across(everything(), mean))%>%
pivot_longer(everything(), names_to = "term", values_to = "estimate")%>%
rbind(VarCorr_09)%>%
rbind(num_groups_09)%>%
dplyr::mutate(gof.decimal = ifelse(term %in% c("nobs_09", "cabinet_name", "Country"), TRUE, FALSE))%>%
mutate(term = recode(term, "nobs_09" = "nobs"))
glance_10 <- models_imputations_robust_3 %>%
unnest(glance_10)%>%
ungroup()%>%
dplyr::select(AIC, nobs_10)%>%
mutate(nobs_10 = as.numeric(nobs_10))%>%
summarise(across(everything(), mean))%>%
pivot_longer(everything(), names_to = "term", values_to = "estimate")%>%
rbind(VarCorr_10)%>%
rbind(num_groups_10)%>%
dplyr::mutate(gof.decimal = ifelse(term %in% c("nobs_10", "cabinet_name", "Country"), TRUE, FALSE))%>%
mutate(term = recode(term, "nobs_10" = "nobs"))
glance_11 <- models_imputations_robust_3 %>%
unnest(glance_11)%>%
ungroup()%>%
dplyr::select(AIC, nobs_11)%>%
mutate(nobs_11 = as.numeric(nobs_11))%>%
summarise(across(everything(), mean))%>%
pivot_longer(everything(), names_to = "term", values_to = "estimate")%>%
rbind(VarCorr_11)%>%
rbind(num_groups_11)%>%
dplyr::mutate(gof.decimal = ifelse(term %in% c("nobs_11", "cabinet_name", "Country"), TRUE, FALSE))%>%
mutate(term = recode(term, "nobs_11" = "nobs"))
# overall summary of coefficient estimates
melded_summary_04 <- as.data.frame(cbind(t(coefs_melded_04$q.mi),
t(coefs_melded_04$se.mi))) %>%
magrittr::set_colnames(c("estimate", "std.error"))%>%
mutate(term = rownames(.)) %>%
dplyr::select(term, everything()) %>%
mutate(statistic = estimate / std.error,
conf.low = estimate + std.error * qt(0.025, model_degree_freedom_04),
conf.high = estimate + std.error * qt(0.975, model_degree_freedom_04),
p.value = 2 * pt(abs(statistic), model_degree_freedom_04, lower.tail = FALSE)
)
melded_summary_05 <- as.data.frame(cbind(t(coefs_melded_05$q.mi),
t(coefs_melded_05$se.mi))) %>%
magrittr::set_colnames(c("estimate", "std.error"))%>%
mutate(term = rownames(.)) %>%
dplyr::select(term, everything()) %>%
mutate(statistic = estimate / std.error,
conf.low = estimate + std.error * qt(0.025, model_degree_freedom_05),
conf.high = estimate + std.error * qt(0.975, model_degree_freedom_05),
p.value = 2 * pt(abs(statistic), model_degree_freedom_05, lower.tail = FALSE)
)
melded_summary_06 <- as.data.frame(cbind(t(coefs_melded_06$q.mi),
t(coefs_melded_06$se.mi))) %>%
magrittr::set_colnames(c("estimate", "std.error"))%>%
mutate(term = rownames(.)) %>%
dplyr::select(term, everything()) %>%
mutate(statistic = estimate / std.error,
conf.low = estimate + std.error * qt(0.025, model_degree_freedom_06),
conf.high = estimate + std.error * qt(0.975, model_degree_freedom_06),
p.value = 2 * pt(abs(statistic), model_degree_freedom_06, lower.tail = FALSE)
)
melded_summary_07 <- as.data.frame(cbind(t(coefs_melded_07$q.mi),
t(coefs_melded_07$se.mi))) %>%
magrittr::set_colnames(c("estimate", "std.error"))%>%
mutate(term = rownames(.)) %>%
dplyr::select(term, everything()) %>%
mutate(statistic = estimate / std.error,
conf.low = estimate + std.error * qt(0.025, model_degree_freedom_07),
conf.high = estimate + std.error * qt(0.975, model_degree_freedom_07),
p.value = 2 * pt(abs(statistic), model_degree_freedom_07, lower.tail = FALSE)
)
melded_summary_08 <- as.data.frame(cbind(t(coefs_melded_08$q.mi),
t(coefs_melded_08$se.mi))) %>%
magrittr::set_colnames(c("estimate", "std.error"))%>%
mutate(term = rownames(.)) %>%
dplyr::select(term, everything()) %>%
mutate(statistic = estimate / std.error,
conf.low = estimate + std.error * qt(0.025, model_degree_freedom_08),
conf.high = estimate + std.error * qt(0.975, model_degree_freedom_08),
p.value = 2 * pt(abs(statistic), model_degree_freedom_08, lower.tail = FALSE)
)
melded_summary_09 <- as.data.frame(cbind(t(coefs_melded_09$q.mi),
t(coefs_melded_09$se.mi))) %>%
magrittr::set_colnames(c("estimate", "std.error"))%>%
mutate(term = rownames(.)) %>%
dplyr::select(term, everything()) %>%
mutate(statistic = estimate / std.error,
conf.low = estimate + std.error * qt(0.025, model_degree_freedom_09),
conf.high = estimate + std.error * qt(0.975, model_degree_freedom_09),
p.value = 2 * pt(abs(statistic), model_degree_freedom_09, lower.tail = FALSE)
)
melded_summary_10 <- as.data.frame(cbind(t(coefs_melded_10$q.mi),
t(coefs_melded_10$se.mi))) %>%
magrittr::set_colnames(c("estimate", "std.error"))%>%
mutate(term = rownames(.)) %>%
dplyr::select(term, everything()) %>%
mutate(statistic = estimate / std.error,
conf.low = estimate + std.error * qt(0.025, model_degree_freedom_10),
conf.high = estimate + std.error * qt(0.975, model_degree_freedom_10),
p.value = 2 * pt(abs(statistic), model_degree_freedom_10, lower.tail = FALSE)
)
melded_summary_11 <- as.data.frame(cbind(t(coefs_melded_11$q.mi),
t(coefs_melded_11$se.mi))) %>%
magrittr::set_colnames(c("estimate", "std.error"))%>%
mutate(term = rownames(.)) %>%
dplyr::select(term, everything()) %>%
mutate(statistic = estimate / std.error,
conf.low = estimate + std.error * qt(0.025, model_degree_freedom_11),
conf.high = estimate + std.error * qt(0.975, model_degree_freedom_11),
p.value = 2 * pt(abs(statistic), model_degree_freedom_11, lower.tail = FALSE)
)
# creating texreg object
texreg_melded_04 <- createTexreg(
coef.names = melded_summary_04$term,
coef = melded_summary_04$estimate,
se = melded_summary_04$std.error,
pvalues = melded_summary_04$p.value,
gof.names = glance_04$term,
gof = glance_04$estimate,
gof.decimal = glance_04$estimate %% 1 > 0
)
texreg_melded_05 <- createTexreg(
coef.names = melded_summary_05$term,
coef = melded_summary_05$estimate,
se = melded_summary_05$std.error,
pvalues = melded_summary_05$p.value,
gof.names = glance_05$term,
gof = glance_05$estimate,
gof.decimal = glance_05$estimate %% 1 > 0
)
texreg_melded_06 <- createTexreg(
coef.names = melded_summary_06$term,
coef = melded_summary_06$estimate,
se = melded_summary_06$std.error,
pvalues = melded_summary_06$p.value,
gof.names = glance_06$term,
gof = glance_06$estimate,
gof.decimal = glance_06$estimate %% 1 > 0
)
texreg_melded_07 <- createTexreg(
coef.names = melded_summary_07$term,
coef = melded_summary_07$estimate,
se = melded_summary_07$std.error,
pvalues = melded_summary_07$p.value,
gof.names = glance_07$term,
gof = glance_07$estimate,
gof.decimal = glance_07$estimate %% 1 > 0
)
texreg_melded_08 <- createTexreg(
coef.names = melded_summary_08$term,
coef = melded_summary_08$estimate,
se = melded_summary_08$std.error,
pvalues = melded_summary_08$p.value,
gof.names = glance_08$term,
gof = glance_08$estimate,
gof.decimal = glance_08$estimate %% 1 > 0
)
texreg_melded_09 <- createTexreg(
coef.names = melded_summary_09$term,
coef = melded_summary_09$estimate,
se = melded_summary_09$std.error,
pvalues = melded_summary_09$p.value,
gof.names = glance_09$term,
gof = glance_09$estimate,
gof.decimal = glance_09$estimate %% 1 > 0
)
texreg_melded_10 <- createTexreg(
coef.names = melded_summary_10$term,
coef = melded_summary_10$estimate,
se = melded_summary_10$std.error,
pvalues = melded_summary_10$p.value,
gof.names = glance_10$term,
gof = glance_10$estimate,
gof.decimal = glance_10$estimate %% 1 > 0
)
texreg_melded_11 <- createTexreg(
coef.names = melded_summary_11$term,
coef = melded_summary_11$estimate,
se = melded_summary_11$std.error,
pvalues = melded_summary_11$p.value,
gof.names = glance_11$term,
gof = glance_11$estimate,
gof.decimal = glance_11$estimate %% 1 > 0
)
models_imputations_robust_4 <- all_imputations %>%
mutate(
model_0000 = data %>% map( ~ lmer(dii_score_gdp_normal ~ gov_seat_share_normal +
corp_index_within_normal + capb_normal + eu + deindustrialization_within_normal*corp_index_between_normal + deindustrialization_between_normal + trade_open_normal + h_polcon5_normal + unemployment_normal + hard_debt_rule + small_state_binary_1 + splines::bs(Year, degree = 3) + (1 | cabinet_name) + (deindustrialization_within_normal | Country),
data = .,
na.action = na.omit,
control = lmerControl(optimizer = "Nelder_Mead"),
REML = TRUE)),
tidied_0000 = model_0000 %>% map(~ broom.mixed::tidy(., effects = c("fixed"))),
glance_0000 = model_0000 %>% map(~ broom.mixed::glance(.)),
VarCorr_0000 = model_0000 %>% map(~ as.tibble(VarCorr(.))),
nobs_0000 = model_0000%>% map(~nobs(.)),
model_0001 = data %>% map(
~ lmer(dii_score_gdp_normal ~ gov_seat_share_normal +
corp_index_within_normal + capb_normal + eu + deindustrialization_within_normal*corp_index_between_normal + deindustrialization_between_normal + trade_open_normal + h_polcon5_normal + unemployment_normal + hard_debt_rule + factor(small_state_three) + splines::bs(Year, degree = 3) + (1 | cabinet_name) + (deindustrialization_within_normal | Country),
data = .,
na.action = na.omit,
control = lmerControl(optimizer = "Nelder_Mead"),
REML = TRUE
)
),
tidied_0001 = model_0001 %>% map(~ broom.mixed::tidy(., effects = c("fixed"))),
glance_0001 = model_0001 %>% map(~ broom.mixed::glance(.)),
VarCorr_0001 = model_0001 %>% map(~ as.tibble(VarCorr(.))),
nobs_0001 = model_0001%>% map(~nobs(.)),
model_0002 = data %>% map(
~ lmer(
rd_gdp_normal ~ gov_seat_share_normal +
corp_index_within_normal + capb_normal + eu + deindustrialization_within_normal*corp_index_between_normal + deindustrialization_between_normal + trade_open_normal + h_polcon5_normal + unemployment_normal + hard_debt_rule+ small_state_binary_2 + splines::bs(Year, degree = 3) + (1 | cabinet_name) + (deindustrialization_within_normal | Country),
data = .,
na.action = na.omit,
control = lmerControl(optimizer = "Nelder_Mead"),
REML = TRUE
)
),
tidied_0002 = model_0002 %>% map(~ broom.mixed::tidy(., effects = c("fixed"))),
glance_0002 = model_0002 %>% map(~ broom.mixed::glance(.)),
VarCorr_0002 = model_0002 %>% map(~ as.tibble(VarCorr(.))),
nobs_0002 = model_0002%>% map(~nobs(.)),
model_0003 = data %>% map(
~ lmer(edu_exp3_gdp_normal ~ gov_seat_share_normal +
corp_index_within_normal + capb_normal + eu + deindustrialization_within_normal*corp_index_between_normal + deindustrialization_between_normal + trade_open_normal + h_polcon5_normal + unemployment_normal+ hard_debt_rule + small_state_binary_2 + splines::bs(Year, degree = 3) + (1 | cabinet_name) + (deindustrialization_within_normal | Country),
data = .,
na.action = na.omit,
control = lmerControl(optimizer = "Nelder_Mead"),
REML = TRUE
)
),
tidied_0003 = model_0003 %>% map(~ broom.mixed::tidy(., effects = c("fixed"))),
glance_0003 = model_0003 %>% map(~ broom.mixed::glance(.)),
VarCorr_0003 = model_0003 %>% map(~ as.tibble(VarCorr(.))),
nobs_0003 = model_0003%>% map(~nobs(.)),
model_0004 = data %>% map(
~ lmer(alp_gdp_normal ~ gov_seat_share_normal +
corp_index_within_normal + capb_normal + eu + deindustrialization_within_normal*corp_index_between_normal + deindustrialization_between_normal + trade_open_normal + h_polcon5_normal + unemployment_normal+ hard_debt_rule + small_state_binary_2 + splines::bs(Year, degree = 3) + (1 | cabinet_name) + (deindustrialization_within_normal | Country),
data = .,
na.action = na.omit,
control = lmerControl(optimizer = "Nelder_Mead"),
REML = TRUE
)
),
tidied_0004 = model_0004 %>% map(~ broom.mixed::tidy(., effects = c("fixed"))),
glance_0004 = model_0004 %>% map(~ broom.mixed::glance(.)),
VarCorr_0004 = model_0004 %>% map(~ as.tibble(VarCorr(.))),
nobs_0004 = model_0004%>% map(~nobs(.))
)
# Create a wide data frame of just the coefficients and standard errors
params_0000 <- models_imputations_robust_4 %>%
unnest(tidied_0000)%>%
dplyr::select(m, term, estimate, std.error)%>%
gather(key, value, estimate, std.error)%>%
spread(term, value)
params_0001 <- models_imputations_robust_4 %>%
unnest(tidied_0001)%>%
dplyr::select(m, term, estimate, std.error)%>%
gather(key, value, estimate, std.error)%>%
spread(term, value)
params_0002 <- models_imputations_robust_4 %>%
unnest(tidied_0002)%>%
dplyr::select(m, term, estimate, std.error)%>%
gather(key, value, estimate, std.error)%>%
spread(term, value)
params_0003 <- models_imputations_robust_4 %>%
unnest(tidied_0003)%>%
dplyr::select(m, term, estimate, std.error)%>%
gather(key, value, estimate, std.error)%>%
spread(term, value)
params_0004 <- models_imputations_robust_4 %>%
unnest(tidied_0004)%>%
dplyr::select(m, term, estimate, std.error)%>%
gather(key, value, estimate, std.error)%>%
spread(term, value)
# Extract just the coefficients
just_coefs_0000 <- params_0000 %>%
filter(key == "estimate")%>%
ungroup()%>%
dplyr::select(-m, -key)
just_coefs_0001 <- params_0001 %>%
filter(key == "estimate")%>%
ungroup()%>%
dplyr::select(-m, -key)
just_coefs_0002 <- params_0002 %>%
filter(key == "estimate")%>%
ungroup()%>%
dplyr::select(-m, -key)
just_coefs_0003 <- params_0003 %>%
filter(key == "estimate")%>%
ungroup()%>%
dplyr::select(-m, -key)
just_coefs_0004 <- params_0004 %>%
filter(key == "estimate")%>%
ungroup()%>%
dplyr::select(-m, -key)
# Extract just the standard errors
just_ses_0000 <- params_0000 %>%
filter(key == "std.error")%>%
ungroup()%>%
dplyr::select(-m, -key)
just_ses_0001 <- params_0001 %>%
filter(key == "std.error")%>%
ungroup()%>%
dplyr::select(-m, -key)
just_ses_0002 <- params_0002 %>%
filter(key == "std.error")%>%
ungroup()%>%
dplyr::select(-m, -key)
just_ses_0003 <- params_0003 %>%
filter(key == "std.error")%>%
ungroup()%>%
dplyr::select(-m, -key)
just_ses_0004 <- params_0004 %>%
filter(key == "std.error")%>%
ungroup()%>%
dplyr::select(-m, -key)
#then we use amelias mi.meld function to combine estimates and se according to rubin's formula
coefs_melded_0000 <- mi.meld(just_coefs_0000, just_ses_0000)
coefs_melded_0001 <- mi.meld(just_coefs_0001, just_ses_0001)
coefs_melded_0002 <- mi.meld(just_coefs_0002, just_ses_0002)
coefs_melded_0003 <- mi.meld(just_coefs_0003, just_ses_0003)
coefs_melded_0004 <- mi.meld(just_coefs_0004, just_ses_0004)
# dfs
model_degree_freedom_0000 <- models_imputations_robust_4 %>%
unnest(glance_0000) %>%
filter(m == "imp1")%>%
pull(df.residual)
model_degree_freedom_0001 <- models_imputations_robust_4 %>%
unnest(glance_0001) %>%
filter(m == "imp1")%>%
pull(df.residual)
model_degree_freedom_0002 <- models_imputations_robust_4 %>%
unnest(glance_0002) %>%
filter(m == "imp1")%>%
pull(df.residual)
model_degree_freedom_0003 <- models_imputations_robust_4 %>%
unnest(glance_0003) %>%
filter(m == "imp1")%>%
pull(df.residual)
model_degree_freedom_0004 <- models_imputations_robust_4 %>%
unnest(glance_0004) %>%
filter(m == "imp1")%>%
pull(df.residual)
# variance/ICC
VarCorr_0000 <- models_imputations_robust_4 %>%
unnest(VarCorr_0000)%>%
ungroup()%>%
replace_na(list(var1 = "", var2 = "")) %>%
unite(term, grp, var1,var2, remove = FALSE, sep = "")%>%
group_by(term)%>%
summarize( vcov = mean(vcov), sdcor = mean(sdcor))%>%
rename(estimate = vcov)%>%
mutate(term = recode(term, "Country(Intercept)" = "Variance Country Level", "cabinet_name(Intercept)" = "Variance Government Level", "Country(Intercept)deindustrialization_within_normal" = "Covariance Random Slope/Intercept", "Countrydeindustrialization_within_normal" = "Variance Random Slope"))%>%
dplyr::select(-sdcor)
VarCorr_0001 <- models_imputations_robust_4 %>%
unnest(VarCorr_0001)%>%
ungroup()%>%
replace_na(list(var1 = "", var2 = "")) %>%
unite(term, grp, var1,var2, remove = FALSE, sep = "")%>%
group_by(term)%>%
summarize( vcov = mean(vcov), sdcor = mean(sdcor))%>%
rename(estimate = vcov)%>%
mutate(term = recode(term, "Country(Intercept)" = "Variance Country Level", "cabinet_name(Intercept)" = "Variance Government Level", "Country(Intercept)deindustrialization_within_normal" = "Covariance Random Slope/Intercept", "Countrydeindustrialization_within_normal" = "Variance Random Slope"))%>%
dplyr::select(-sdcor)
VarCorr_0002 <- models_imputations_robust_4 %>%
unnest(VarCorr_0002)%>%
ungroup()%>%
replace_na(list(var1 = "", var2 = "")) %>%
unite(term, grp, var1,var2, remove = FALSE, sep = "")%>%
group_by(term)%>%
summarize( vcov = mean(vcov), sdcor = mean(sdcor))%>%
rename(estimate = vcov)%>%
mutate(term = recode(term, "Country(Intercept)" = "Variance Country Level", "cabinet_name(Intercept)" = "Variance Government Level", "Country(Intercept)deindustrialization_within_normal" = "Covariance Random Slope/Intercept", "Countrydeindustrialization_within_normal" = "Variance Random Slope"))%>%
dplyr::select(-sdcor)
VarCorr_0003 <- models_imputations_robust_4 %>%
unnest(VarCorr_0003)%>%
ungroup()%>%
replace_na(list(var1 = "", var2 = "")) %>%
unite(term, grp, var1,var2, remove = FALSE, sep = "")%>%
group_by(term)%>%
summarize( vcov = mean(vcov), sdcor = mean(sdcor))%>%
rename(estimate = vcov)%>%
mutate(term = recode(term, "Country(Intercept)" = "Variance Country Level", "cabinet_name(Intercept)" = "Variance Government Level", "Country(Intercept)deindustrialization_within_normal" = "Covariance Random Slope/Intercept", "Countrydeindustrialization_within_normal" = "Variance Random Slope"))%>%
dplyr::select(-sdcor)
VarCorr_0004 <- models_imputations_robust_4 %>%
unnest(VarCorr_0004)%>%
ungroup()%>%
replace_na(list(var1 = "", var2 = "")) %>%
unite(term, grp, var1,var2, remove = FALSE, sep = "")%>%
group_by(term)%>%
summarize( vcov = mean(vcov), sdcor = mean(sdcor))%>%
rename(estimate = vcov)%>%
mutate(term = recode(term, "Country(Intercept)" = "Variance Country Level", "cabinet_name(Intercept)" = "Variance Government Level", "Country(Intercept)deindustrialization_within_normal" = "Covariance Random Slope/Intercept", "Countrydeindustrialization_within_normal" = "Variance Random Slope"))%>%
dplyr::select(-sdcor)
# here we can just extract the number of grouped observations from the first model as they are the same for all imputations of this particular model
num_groups_0000 <- as.data.frame(sapply(ranef(models_imputations_robust_4$model_0000[[1]]), nrow))
colnames(num_groups_0000) <- "estimate"
num_groups_0000 <- rownames_to_column(num_groups_0000, var = "term")
num_groups_0001 <- as.data.frame(sapply(ranef(models_imputations_robust_4$model_0001[[1]]), nrow))
colnames(num_groups_0001) <- "estimate"
num_groups_0001 <- rownames_to_column(num_groups_0001, var = "term")
num_groups_0002 <- as.data.frame(sapply(ranef(models_imputations_robust_4$model_0002[[1]]), nrow))
colnames(num_groups_0002) <- "estimate"
num_groups_0002 <- rownames_to_column(num_groups_0002, var = "term")
num_groups_0003 <- as.data.frame(sapply(ranef(models_imputations_robust_4$model_0003[[1]]), nrow))
colnames(num_groups_0003) <- "estimate"
num_groups_0003 <- rownames_to_column(num_groups_0003, var = "term")
num_groups_0004 <- as.data.frame(sapply(ranef(models_imputations_robust_4$model_0004[[1]]), nrow))
colnames(num_groups_0004) <- "estimate"
num_groups_0004 <- rownames_to_column(num_groups_0004, var = "term")
# general goodness of fit stats (rename all nobs to avoid having differently names nobs in the texreg plotting)
glance_0000 <- models_imputations_robust_4 %>%
unnest(glance_0000)%>%
ungroup()%>%
dplyr::select(AIC, nobs_0000)%>%
mutate(nobs_0000 = as.numeric(nobs_0000))%>%
summarise(across(everything(), mean))%>%
pivot_longer(everything(), names_to = "term", values_to = "estimate")%>%
rbind(VarCorr_0000)%>%
rbind(num_groups_0000)%>%
dplyr::mutate(gof.decimal = ifelse(term %in% c("nobs_0000", "cabinet_name", "Country"), TRUE, FALSE))%>%
mutate(term = recode(term, "nobs_0000" = "nobs"))
glance_0001 <- models_imputations_robust_4 %>%
unnest(glance_0001)%>%
ungroup()%>%
dplyr::select(AIC, nobs_0001)%>%
mutate(nobs_0001 = as.numeric(nobs_0001))%>%
summarise(across(everything(), mean))%>%
pivot_longer(everything(), names_to = "term", values_to = "estimate")%>%
rbind(VarCorr_0001)%>%
rbind(num_groups_0001)%>%
dplyr::mutate(gof.decimal = ifelse(term %in% c("nobs_0001", "cabinet_name", "Country"), TRUE, FALSE))%>%
mutate(term = recode(term, "nobs_0001" = "nobs"))
glance_0002 <- models_imputations_robust_4 %>%
unnest(glance_0002)%>%
ungroup()%>%
dplyr::select(AIC, nobs_0002)%>%
mutate(nobs_0002 = as.numeric(nobs_0002))%>%
summarise(across(everything(), mean))%>%
pivot_longer(everything(), names_to = "term", values_to = "estimate")%>%
rbind(VarCorr_0002)%>%
rbind(num_groups_0002)%>%
dplyr::mutate(gof.decimal = ifelse(term %in% c("nobs_0002", "cabinet_name", "Country"), TRUE, FALSE))%>%
mutate(term = recode(term, "nobs_0002" = "nobs"))
glance_0003 <- models_imputations_robust_4 %>%
unnest(glance_0003)%>%
ungroup()%>%
dplyr::select(AIC, nobs_0003)%>%
mutate(nobs_0003 = as.numeric(nobs_0003))%>%
summarise(across(everything(), mean))%>%
pivot_longer(everything(), names_to = "term", values_to = "estimate")%>%
rbind(VarCorr_0003)%>%
rbind(num_groups_0003)%>%
dplyr::mutate(gof.decimal = ifelse(term %in% c("nobs_0003", "cabinet_name", "Country"), TRUE, FALSE))%>%
mutate(term = recode(term, "nobs_0003" = "nobs"))
glance_0004 <- models_imputations_robust_4 %>%
unnest(glance_0004)%>%
ungroup()%>%
dplyr::select(AIC, nobs_0004)%>%
mutate(nobs_0004 = as.numeric(nobs_0004))%>%
summarise(across(everything(), mean))%>%
pivot_longer(everything(), names_to = "term", values_to = "estimate")%>%
rbind(VarCorr_0004)%>%
rbind(num_groups_0004)%>%
dplyr::mutate(gof.decimal = ifelse(term %in% c("nobs_0004", "cabinet_name", "Country"), TRUE, FALSE))%>%
mutate(term = recode(term, "nobs_0004" = "nobs"))
# overall summary of coefficient estimates
melded_summary_0000 <- as.data.frame(cbind(t(coefs_melded_0000$q.mi),
t(coefs_melded_0000$se.mi))) %>%
magrittr::set_colnames(c("estimate", "std.error"))%>%
mutate(term = rownames(.)) %>%
dplyr::select(term, everything()) %>%
mutate(statistic = estimate / std.error,
conf.low = estimate + std.error * qt(0.025, model_degree_freedom_0000),
conf.high = estimate + std.error * qt(0.975, model_degree_freedom_0000),
p.value = 2 * pt(abs(statistic), model_degree_freedom_0000, lower.tail = FALSE)
)
melded_summary_0001 <- as.data.frame(cbind(t(coefs_melded_0001$q.mi),
t(coefs_melded_0001$se.mi))) %>%
magrittr::set_colnames(c("estimate", "std.error"))%>%
mutate(term = rownames(.)) %>%
dplyr::select(term, everything()) %>%
mutate(statistic = estimate / std.error,
conf.low = estimate + std.error * qt(0.025, model_degree_freedom_0001),
conf.high = estimate + std.error * qt(0.975, model_degree_freedom_0001),
p.value = 2 * pt(abs(statistic), model_degree_freedom_0001, lower.tail = FALSE)
)
melded_summary_0002 <- as.data.frame(cbind(t(coefs_melded_0002$q.mi),
t(coefs_melded_0002$se.mi))) %>%
magrittr::set_colnames(c("estimate", "std.error"))%>%
mutate(term = rownames(.)) %>%
dplyr::select(term, everything()) %>%
mutate(statistic = estimate / std.error,
conf.low = estimate + std.error * qt(0.025, model_degree_freedom_0002),
conf.high = estimate + std.error * qt(0.975, model_degree_freedom_0002),
p.value = 2 * pt(abs(statistic), model_degree_freedom_0002, lower.tail = FALSE)
)
melded_summary_0003 <- as.data.frame(cbind(t(coefs_melded_0003$q.mi),
t(coefs_melded_0003$se.mi))) %>%
magrittr::set_colnames(c("estimate", "std.error"))%>%
mutate(term = rownames(.)) %>%
dplyr::select(term, everything()) %>%
mutate(statistic = estimate / std.error,
conf.low = estimate + std.error * qt(0.025, model_degree_freedom_0003),
conf.high = estimate + std.error * qt(0.975, model_degree_freedom_0003),
p.value = 2 * pt(abs(statistic), model_degree_freedom_0003, lower.tail = FALSE)
)
melded_summary_0004 <- as.data.frame(cbind(t(coefs_melded_0004$q.mi),
t(coefs_melded_0004$se.mi))) %>%
magrittr::set_colnames(c("estimate", "std.error"))%>%
mutate(term = rownames(.)) %>%
dplyr::select(term, everything()) %>%
mutate(statistic = estimate / std.error,
conf.low = estimate + std.error * qt(0.025, model_degree_freedom_0004),
conf.high = estimate + std.error * qt(0.975, model_degree_freedom_0004),
p.value = 2 * pt(abs(statistic), model_degree_freedom_0004, lower.tail = FALSE)
)
# creating texreg object
texreg_melded_0000 <- createTexreg(
coef.names = melded_summary_0000$term,
coef = melded_summary_0000$estimate,
se = melded_summary_0000$std.error,
pvalues = melded_summary_0000$p.value,
gof.names = glance_0000$term,
gof = glance_0000$estimate,
gof.decimal = glance_0000$estimate %% 1 > 0
)
texreg_melded_0001 <- createTexreg(
coef.names = melded_summary_0001$term,
coef = melded_summary_0001$estimate,
se = melded_summary_0001$std.error,
pvalues = melded_summary_0001$p.value,
gof.names = glance_0001$term,
gof = glance_0001$estimate,
gof.decimal = glance_0001$estimate %% 1 > 0
)
texreg_melded_0002 <- createTexreg(
coef.names = melded_summary_0002$term,
coef = melded_summary_0002$estimate,
se = melded_summary_0002$std.error,
pvalues = melded_summary_0002$p.value,
gof.names = glance_0002$term,
gof = glance_0002$estimate,
gof.decimal = glance_0002$estimate %% 1 > 0
)
texreg_melded_0003 <- createTexreg(
coef.names = melded_summary_0003$term,
coef = melded_summary_0003$estimate,
se = melded_summary_0003$std.error,
pvalues = melded_summary_0003$p.value,
gof.names = glance_0003$term,
gof = glance_0003$estimate,
gof.decimal = glance_0003$estimate %% 1 > 0
)
texreg_melded_0004 <- createTexreg(
coef.names = melded_summary_0004$term,
coef = melded_summary_0004$estimate,
se = melded_summary_0004$std.error,
pvalues = melded_summary_0004$p.value,
gof.names = glance_0004$term,
gof = glance_0004$estimate,
gof.decimal = glance_0004$estimate %% 1 > 0
)
all_imputations_robust_1 <- bind_rows(unclass(amelia.out$imputations), .id = "m") %>%
group_by(m)%>%
mutate(dii_score_gdp = (edu_exp3_gdp + rd_gdp + alp_gdp),
dii_score_gdp_sel = (edu_exp3_gdp + rd_gdp_sel + alp_gdp),
dii_score_gdp_without = (edu_exp3_gdp + rd_gdp),
dii_score2_gdp = (edu_exp2_gdp + rd_gdp + alp_gdp),
dii_score2_gdp_without = (edu_exp2_gdp + rd_gdp))%>%
group_by(m, Country)%>%
mutate(dii_score_gdp_lag = lag(dii_score_gdp),
dii_score_gdp_sel_lag = lag(dii_score_gdp_sel),
dii_score_gdp_without_lag = lag(dii_score_gdp_without),
dii_score2_gdp_lag = lag(dii_score2_gdp),
rd_gdp_lag = lag(rd_gdp),
edu_exp3_gdp_lag = lag(edu_exp3_gdp),
alp_gdp_lag = lag(alp_gdp))%>%
filter( (Country %in% countries.selected & Year >1980)& Year <2019)%>%
ungroup()%>%
mutate(small_state_binary_1 = round(small_state_binary_1),
small_state_binary_2 = round(small_state_binary_2),
small_state_three = round(small_state_three))%>%
group_by(m) %>%
mutate(corp_index_between = ave(corp_index, Country),
corp_index_within = corp_index-corp_index_between,
corp_index_fun_between = ave(corp_index_fun, Country),
corp_index_fun_within = corp_index_fun-corp_index_fun_between,
capb_between = ave(capb, Country),
capb_within = capb-capb_between,
deindustrialization_between = ave(deindustrialization, Country),
deindustrialization_within = deindustrialization-deindustrialization_between,
h_polcon5_between = ave(h_polcon5, Country),
h_polcon5_within = h_polcon5-h_polcon5_between,
h_polcon3_between = ave(h_polcon3, Country),
h_polcon3_within = h_polcon3-h_polcon3_between,
deficit_between = ave(deficit, Country),
deficit_within = deficit-deficit_between,
unemployment_between = ave(unemployment, Country),
unemployment_within = unemployment-unemployment_between,
employment_between = ave(employment, Country),
employment_within = employment-employment_between,
gdp_capita_between = ave(gdp_capita, Country),
gdp_capita_within = gdp_capita-gdp_capita_between,
trade_open_between = ave(trade_open, Country),
trade_open_within = trade_open-trade_open_between)%>%
mutate(across(c(starts_with("corp_"), starts_with("dii"), starts_with("alp"), starts_with("edu_exp"), starts_with("rd_gdp"), ends_with("weighthed"), starts_with("gov_"), starts_with("trad"), Inflation:pop_size, starts_with("deindust"), starts_with("defic"), starts_with("h_"), starts_with("unemploy"), starts_with("employ"), investment_weighted, share_elderly, starts_with("gdp"), starts_with("public"), starts_with("capb"), starts_with("GDP"), debt), scale, .names = "{col}_normal"))%>%
nest()
models_imputations_robust_1 <- all_imputations_robust_1 %>%
mutate(
model_000 = data %>% map( ~ lmer(
dii_score_gdp_normal ~ gov_seat_share_normal +
corp_index_within_normal + capb_normal + eu + deindustrialization_within_normal*corp_index_between_normal + deindustrialization_between_normal + trade_open_normal + h_polcon5_normal + unemployment_normal+ hard_debt_rule + small_state_binary_2 + splines::bs(Year, degree = 3) + (1 | cabinet_name) + (deindustrialization_within_normal | Country),
data = .,
na.action = na.omit,
control = lmerControl(optimizer = "Nelder_Mead"),
REML = TRUE)),
tidied_000 = model_000 %>% map(~ broom.mixed::tidy(., effects = c("fixed"))),
# we can also add the random coefficients here by just adding "ran_coefs" to the vectors
glance_000 = model_000 %>% map(~ broom.mixed::glance(.)),
VarCorr_000 = model_000 %>% map(~ as.tibble(VarCorr(.))),
nobs_000 = model_000%>% map(~nobs(.))
)
# Create a wide data frame of just the coefficients and standard errors
params_000 <- models_imputations_robust_1 %>%
unnest(tidied_000)%>%
dplyr::select(m, term, estimate, std.error)%>%
gather(key, value, estimate, std.error)%>%
spread(term, value)
# Extract just the coefficients
just_coefs_000 <- params_000 %>%
filter(key == "estimate")%>%
ungroup()%>%
dplyr::select(-m, -key)
# Extract just the standard errors
just_ses_000 <- params_000 %>%
filter(key == "std.error")%>%
ungroup()%>%
dplyr::select(-m, -key)
#then we use amelias mi.meld function to combine estimates and se according to rubin's formula
coefs_melded_000 <- mi.meld(just_coefs_000, just_ses_000)
# dfs
model_degree_freedom_000 <- models_imputations_robust_1 %>%
unnest(glance_000) %>%
filter(m == "imp1")%>%
pull(df.residual)
# variance/ICC
VarCorr_000 <- models_imputations_robust_1 %>%
unnest(VarCorr_000)%>%
ungroup()%>%
replace_na(list(var1 = "", var2 = "")) %>%
unite(term, grp, var1,var2, remove = FALSE, sep = "")%>%
group_by(term)%>%
summarize( vcov = mean(vcov), sdcor = mean(sdcor))%>%
rename(estimate = vcov)%>%
mutate(term = recode(term, "Country(Intercept)" = "Variance Country Level", "cabinet_name(Intercept)" = "Variance Government Level", "Country(Intercept)deindustrialization_within_normal" = "Covariance Random Slope/Intercept", "Countrydeindustrialization_within_normal" = "Variance Random Slope"))%>%
dplyr::select(-sdcor)
# here we can just extract the number of grouped observations from the first model as they are the same for all imputations of this particular model
num_groups_000 <- as.data.frame(sapply(ranef(models_imputations_robust_1$model_000[[1]]), nrow))
colnames(num_groups_000) <- "estimate"
num_groups_000 <- rownames_to_column(num_groups_000, var = "term")
# general goodness of fit stats (rename all nobs to avoid having differently names nobs in the texreg plotting)
glance_000 <- models_imputations_robust_1 %>%
unnest(glance_000)%>%
ungroup()%>%
dplyr::select(AIC, nobs_000)%>%
mutate(nobs_000 = as.numeric(nobs_000))%>%
summarise(across(everything(), mean))%>%
pivot_longer(everything(), names_to = "term", values_to = "estimate")%>%
rbind(VarCorr_000)%>%
rbind(num_groups_000)%>%
dplyr::mutate(gof.decimal = ifelse(term %in% c("nobs_000", "cabinet_name", "Country"), TRUE, FALSE))%>%
mutate(term = recode(term, "nobs_000" = "nobs"))
# overall summary of coefficient estimates
melded_summary_000 <- as.data.frame(cbind(t(coefs_melded_000$q.mi),
t(coefs_melded_000$se.mi))) %>%
magrittr::set_colnames(c("estimate", "std.error"))%>%
mutate(term = rownames(.)) %>%
dplyr::select(term, everything()) %>%
mutate(statistic = estimate / std.error,
conf.low = estimate + std.error * qt(0.025, model_degree_freedom_000),
conf.high = estimate + std.error * qt(0.975, model_degree_freedom_000),
p.value = 2 * pt(abs(statistic), model_degree_freedom_000, lower.tail = FALSE)
)
# creating texreg object
texreg_melded_000 <- createTexreg(
coef.names = melded_summary_000$term,
coef = melded_summary_000$estimate,
se = melded_summary_000$std.error,
pvalues = melded_summary_000$p.value,
gof.names = glance_000$term,
gof = glance_000$estimate,
gof.decimal = glance_000$estimate %% 1 > 0
)
all_imputations_robust_2 <- bind_rows(unclass(amelia.out$imputations), .id = "m") %>%
group_by(m)%>%
mutate(dii_score_gdp = (edu_exp3_gdp + rd_gdp + alp_gdp),
dii_score_gdp_sel = (edu_exp3_gdp + rd_gdp_sel + alp_gdp),
dii_score_gdp_without = (edu_exp3_gdp + rd_gdp),
dii_score2_gdp = (edu_exp2_gdp + rd_gdp + alp_gdp),
dii_score2_gdp_without = (edu_exp2_gdp + rd_gdp))%>%
group_by(m, Country)%>%
mutate(dii_score_gdp_lag = lag(dii_score_gdp),
dii_score_gdp_sel_lag = lag(dii_score_gdp_sel),
dii_score_gdp_without_lag = lag(dii_score_gdp_without),
dii_score2_gdp_lag = lag(dii_score2_gdp),
rd_gdp_lag = lag(rd_gdp),
edu_exp3_gdp_lag = lag(edu_exp3_gdp),
alp_gdp_lag = lag(alp_gdp))%>%
filter(Year >1994 & Year <2019)%>%
ungroup()%>%
mutate(small_state_binary_1 = round(small_state_binary_1),
small_state_binary_2 = round(small_state_binary_2),
small_state_three = round(small_state_three))%>%
group_by(m) %>%
mutate(corp_index_between = ave(corp_index, Country),
corp_index_within = corp_index-corp_index_between,
corp_index_fun_between = ave(corp_index_fun, Country),
corp_index_fun_within = corp_index_fun-corp_index_fun_between,
capb_between = ave(capb, Country),
capb_within = capb-capb_between,
deindustrialization_between = ave(deindustrialization, Country),
deindustrialization_within = deindustrialization-deindustrialization_between,
h_polcon5_between = ave(h_polcon5, Country),
h_polcon5_within = h_polcon5-h_polcon5_between,
h_polcon3_between = ave(h_polcon3, Country),
h_polcon3_within = h_polcon3-h_polcon3_between,
deficit_between = ave(deficit, Country),
deficit_within = deficit-deficit_between,
unemployment_between = ave(unemployment, Country),
unemployment_within = unemployment-unemployment_between,
employment_between = ave(employment, Country),
employment_within = employment-employment_between,
gdp_capita_between = ave(gdp_capita, Country),
gdp_capita_within = gdp_capita-gdp_capita_between,
trade_open_between = ave(trade_open, Country),
trade_open_within = trade_open-trade_open_between)%>%
mutate(across(c(starts_with("corp_"), starts_with("dii"), starts_with("alp"), starts_with("edu_exp"), starts_with("rd_gdp"), ends_with("weighthed"), starts_with("gov_"), starts_with("trad"), Inflation:pop_size, starts_with("deindust"), starts_with("defic"), starts_with("h_"), starts_with("unemploy"), starts_with("employ"), investment_weighted, share_elderly, starts_with("gdp"), starts_with("public"), starts_with("capb"), starts_with("GDP"), debt), scale, .names = "{col}_normal"))%>%
nest()
models_imputations_robust_2 <- all_imputations_robust_2 %>%
mutate(
model_001 = data %>% map( ~ lmer(
dii_score_gdp_normal ~ gov_seat_share_normal +
corp_index_within_normal + capb_normal + eu + deindustrialization_within_normal*corp_index_between_normal + deindustrialization_between_normal + trade_open_normal + h_polcon5_normal + unemployment_normal+ hard_debt_rule + small_state_binary_2 + splines::bs(Year, degree = 3) + (1 | cabinet_name) + (deindustrialization_within_normal | Country),
data = .,
na.action = na.omit,
control = lmerControl(optimizer = "Nelder_Mead"),
REML = TRUE)),
tidied_001 = model_001 %>% map(~ broom.mixed::tidy(., effects = c("fixed"))),
# we can also add the random coefficients here by just adding "ran_coefs" to the vectors
glance_001 = model_001 %>% map(~ broom.mixed::glance(.)),
VarCorr_001 = model_001 %>% map(~ as.tibble(VarCorr(.))),
nobs_001 = model_001%>% map(~nobs(.))
)
# Create a wide data frame of just the coefficients and standard errors
params_001 <- models_imputations_robust_2 %>%
unnest(tidied_001)%>%
dplyr::select(m, term, estimate, std.error)%>%
gather(key, value, estimate, std.error)%>%
spread(term, value)
# Extract just the coefficients
just_coefs_001 <- params_001 %>%
filter(key == "estimate")%>%
ungroup()%>%
dplyr::select(-m, -key)
# Extract just the standard errors
just_ses_001 <- params_001 %>%
filter(key == "std.error")%>%
ungroup()%>%
dplyr::select(-m, -key)
#then we use amelias mi.meld function to combine estimates and se according to rubin's formula
coefs_melded_001 <- mi.meld(just_coefs_001, just_ses_001)
# dfs
model_degree_freedom_001 <- models_imputations_robust_2 %>%
unnest(glance_001) %>%
filter(m == "imp1")%>%
pull(df.residual)
# variance/ICC
VarCorr_001 <- models_imputations_robust_2 %>%
unnest(VarCorr_001)%>%
ungroup()%>%
replace_na(list(var1 = "", var2 = "")) %>%
unite(term, grp, var1,var2, remove = FALSE, sep = "")%>%
group_by(term)%>%
summarize( vcov = mean(vcov), sdcor = mean(sdcor))%>%
rename(estimate = vcov)%>%
mutate(term = recode(term, "Country(Intercept)" = "Variance Country Level", "cabinet_name(Intercept)" = "Variance Government Level", "Country(Intercept)deindustrialization_within_normal" = "Covariance Random Slope/Intercept", "Countrydeindustrialization_within_normal" = "Variance Random Slope"))%>%
dplyr::select(-sdcor)
# here we can just extract the number of grouped observations from the first model as they are the same for all imputations of this particular model
num_groups_001 <- as.data.frame(sapply(ranef(models_imputations_robust_2$model_001[[1]]), nrow))
colnames(num_groups_001) <- "estimate"
num_groups_001 <- rownames_to_column(num_groups_001, var = "term")
# general goodness of fit stats (rename all nobs to avoid having differently names nobs in the <- plotting)
glance_001 <- models_imputations_robust_2 %>%
unnest(glance_001)%>%
ungroup()%>%
dplyr::select(AIC, nobs_001)%>%
mutate(nobs_001 = as.numeric(nobs_001))%>%
summarise(across(everything(), mean))%>%
pivot_longer(everything(), names_to = "term", values_to = "estimate")%>%
rbind(VarCorr_001)%>%
rbind(num_groups_001)%>%
dplyr::mutate(gof.decimal = ifelse(term %in% c("nobs_001", "cabinet_name", "Country"), TRUE, FALSE))%>%
mutate(term = recode(term, "nobs_001" = "nobs"))
# overall summary of coefficient estimates
melded_summary_001 <- as.data.frame(cbind(t(coefs_melded_001$q.mi),
t(coefs_melded_001$se.mi))) %>%
magrittr::set_colnames(c("estimate", "std.error"))%>%
mutate(term = rownames(.)) %>%
dplyr::select(term, everything()) %>%
mutate(statistic = estimate / std.error,
conf.low = estimate + std.error * qt(0.025, model_degree_freedom_001),
conf.high = estimate + std.error * qt(0.975, model_degree_freedom_001),
p.value = 2 * pt(abs(statistic), model_degree_freedom_001, lower.tail = FALSE)
)
# creating texreg object
texreg_melded_001 <- createTexreg(
coef.names = melded_summary_001$term,
coef = melded_summary_001$estimate,
se = melded_summary_001$std.error,
pvalues = melded_summary_001$p.value,
gof.names = glance_001$term,
gof = glance_001$estimate,
gof.decimal = glance_001$estimate %% 1 > 0
)
Here we combine the different texreg objects from the models
texreg_melded <-
list(
texreg_melded_empty,
texreg_melded_1,
texreg_melded_2,
texreg_melded_3,
texreg_melded_00,
texreg_melded_01,
texreg_melded_02,
texreg_melded_03,
texreg_melded_04,
texreg_melded_05,
texreg_melded_06,
texreg_melded_07,
texreg_melded_08,
texreg_melded_09,
texreg_melded_10,
texreg_melded_000,
texreg_melded_001,
texreg_melded_0000,
texreg_melded_0001,
texreg_melded_0002,
texreg_melded_0003,
texreg_melded_0004,
texreg_melded_11
)
# Here, I turn eval on again to reproduce the paper in the html file
knitr::opts_chunk$set(eval = TRUE)
Investments in education and retraining, or research and development have become essential in today’s knowledge-intensive economies. While private actors often underprovide such knowledge-based capital due to various market failures, there is also considerable variation in the extent to which governments invest in knowledge-based capital due to cross-sectional and intertemporal trade-offs. I argue that in trying to account for this variation, corporatist institutions are a neglected but crucial factor. By necessitating and facilitating cooperation and compensation, corporatism creates a more collaborative style of policymaking and a sense of common ownership of policy problems that helps overcome the trade-offs associated with investments in knowledge-based capital. Using within-between mixed-effects models on a novel time-series-cross-sectional dataset, I find strong support for this argument. Corporatist countries invest a lot more in knowledge-based capital, and corporatism also affects how countries react to deindustrialization. This is an important finding given the key role of long-term policymaking in areas like climate change politics, pandemic preparedness, or responding to the digital transformation.
In today’s knowledge economies, the success of individuals, firms, and societies increasingly depends on how much ‘knowledge-based capital’ [@OECD.2013] they possess or command [@Haskel.2017]. We can distinguish between two types of knowledge-based capital: human capital – the knowledge (e.g. skills, expertise) that individuals acquire over the life-course; and innovational capital – the knowledge that groups of individuals hold collectively (e.g. patents, organizational know-how) [@Kraft.2017, pp. 19–20]. Both allow individuals to (inter-)act more efficiently and creatively and are therefore widely seen as essential for surviving and thriving in today’s economy.
Against this background, investments in knowledge-based capital should be a no-brainer. However, the inability of private actors to fully appropriate potential payoffs leads to systematic underinvestments in knowledge-based capital [@EuropeanCommission.2017a]. Governments are therefore assigned a crucial role in providing such investments by spending public resources on education, training, and scientific research and development [@Fournier.2016; @Iversen.2019; @Mazzucato.2019].
However, it is not just markets that often fail to make the socially optimal amount of investments. Governments often fail too. Investments increase individuals’ or groups’ capacity for future consumption [@Beramendi.2015, p. 8; @Kraft.2017, p. 15] and therefore realize a “collective gain” [@Hicks.1998, p. 1632]. However, they also require the conflictual (re-)allocation of resources from present to future consumption and/or from some status groups or sectors to others [@Finnegan.2022; @Jacobs.2016]. It is because of these intertemporal and cross-sectional trade-offs that investment policies are politically costly and governments generally underprovide them.
Governments, however, fail to different degrees. As Figure 3.1 shows, there are considerable differences in the extent to which governments are capable or willing to invest in knowledge-based capital. This paper sets out to explain this variation. For while political scientists have made important inroads into explaining the politics of investment policies [@Bremer.2021; @Boix.1997; @Busemeyer.2009; @Jensen.2011; @Beramendi.2015; @Finnegan.2022; @Garritzmann.2016; @Jacques.2020], the literature falls short in three ways.
First, it suffers from a “persistent ‘education bias’” [@Kraft.2017, p. 14], i.e. it largely looks at (‘social’) investment in human capital formation instead of investment in innovational (or physical) capital. I thus created an index capturing investments in individually as well as collectively held knowledge-based capital, combining three types of investments: 1) public education spending to measure investments in individually-held skills; 2) public spending on research and development to measure investment in collectively-held knowledge; and 3) public investment in active labor market policies that may enhance both actors human capital and societies collective innovational capital.
Second, the literature has focused largely on structural and partisan factors in explaining temporal and geographic differences in investment policies. Structural accounts argue that spending patterns are the result of large-scale economic or demographic transformations that are largely outside of political control. Partisan accounts, on the contrary, stress the importance of partisan politics and explain differences in investment spending with different priorities of governing parties. While both explanatory traditions have acknowledged the role of institutions in moderating (or superseding) the effects of structural or partisan variables [@Jensen.2011; @Garritzmann.2016], they have not sufficiently theorized institutional factors in their own right and have also not sufficiently theorized the importance of intertemporal compared to cross-sectional trade-offs [for exceptions, see @Finnegan.2022; @Jacques.2021].
Building on the literature on power-sharing [@Lindvall.2017; @Jacques.2021] and cooperation-inducing institutions [@Katzenstein.1985; @Ornston.2013; @Hicks.1998], I argue that corporatist institutions can be expected to alleviate not just cross-sectional but also intertemporal trade-offs and thus increase long-term investments [@Finnegan.2022]. Specifically, I argue that corporatist institutions foster a more collaborative style of policymaking as well as a sense of “‘shared ownership’ of policy problems [and a] general capacity to adapt” [@Hemerijck.2001, p. 227] that allows corporatist countries to overcome the cross-sectional and intertemporal trade-offs associated with making policies for the long run.
Third, the literature has largely relied on time-series-cross-sectional models using country-year observations. Governments, however, do not change on a yearly basis, which results in inflated observations and incorrect estimates [@Garritzmann.2016]. Following recent methodological suggestions [@Garritzmann.2020b], I therefore use mixed models to analyze time-series-cross-sectional data where annual observations are nested in governments which are in turn nested in countries. Moreover, the literature often uses country-fixed effects models which - for methodological reasons - control out the between-country effects of variables despite their substantive importance. I thus use within-between mixed-effects models which disentangle the within and between effects of variables [@Bartels.2015; @Bell.2015; @Bell.2019].^[In previous iterations of this paper, I made an additional ideational argument about how state identities and politico-economic cultures could influence investment spending. Specifically, I collected, automatically translated, and analyzed newspaper articles from different countries over time to identify differing conceptions of public debt and deficits, of the role of the state in the economy, and of technological change. For transparency reasons, I discuss this approach in detail in appendix C4.3, where I also explain why I ultimately did not trust the data and therefore did not include them in this paper.
I find strong support for my argument that corporatist institutions, by fostering a collaborative style of policymaking, are a central yet so far largely overlooked factor in explaining cross-country variation in investment policies [again, for exceptions, see @Finnegan.2022; @Jacques.2021]. Moreover, corporatist institutions seem to moderate the relationship between deindustrialization and knowledge investments in that the impact of deindustrialization on investments varies across levels of corporatism as well as over countries more generally. I also find that austerity has a negative effect on investment spending. However, I do not find evidence that partisan factors (still) play an explanatory role, which is in line with most of the recent literature [@Garritzmann.2016; @Jacques.2021; @Ronchi.2018]. These findings matter as they highlight the importance of institutionalized compensation and collaboration between different actors in overcoming obstacles to successful long-term policymaking - obstacles that appear in similar form in climate policymaking or pandemic preparedness, for example [cf. @Finnegan.2022].
The paper proceeds as follows: I first demonstrate why investments in knowledge-based capital matter but why neither markets nor governments fully invest enough. I then show that countries nonetheless differ substantively in how much they invest in knowledge-based capital. After discussing different explanations for why this is the case, I sketch out and substantiate my own argument, which focuses on corporatist institutions. Next, I discuss my empirical strategy and the dataset I compiled. I then present and discuss my findings. I conclude by briefly summarizing key take-aways, discussing some limitations, and pointing to avenues for future research.
The last decades have witnessed a dramatic growth in the economic (and social) importance of knowledge and learning [@OECD.2013; @Stiglitz.2014; @Thelen.2019]. Knowledge-based or intangible capital like skills, patents, know-how, software, or databases have become essential for surviving and thriving in today’s economies [@Haskel.2017]. This process is closely linked to the introduction of digital technologies, which tend to be complements to knowledge-based capital: they put a premium on the ability of actors, organizations and countries to access, acquire, and apply knowledge while rendering other assets and activities less valuable or redundant. This has already been true during the third industrial revolution starting in the 1970s. But it is even more true for today’s fourth industrial revolution, which puts additional pressure on low-knowledge and an additional premium on high-knowledge assets and activities [@Frey.2019; @OECD.2013; @OECD.2017].
In other words, digital technologies - be it those of the fourth industrial revolution which currently gathers steam, or those of the third industrial revolution which slowly runs out of it - have a tendency to make “highly skilled labor the main complement of capital in the production process” [@Boix.2019, p. 23] while rendering technological change increasingly labor-replacing [@Frey.2019]. In such an economy, the value of knowledge – both the knowledge held by individuals and the knowledge held between them – increases dramatically [@OECD.2013; @Haskel.2017]. This has implications on the individual, firm, and country level.
Individuals may find their skills obsolete, businesses their market position upended, and countries their competitive advantage deteriorating. At the same time, digital technologies also promise to massively increase societal welfare by making economies and societies vastly more efficient. Therefore, the royal road to unlocking the ‘collective gains’ [@Hicks.1998] inherent in technological change is not to halt it by increasing the relative price of capital vis a vis labor (the ‘Luddite option’). Nor is to passively compensate its losers and thereby shore up the legitimacy of technological change (the ‘welfarist option’). Rather, the most appealing way to respond to technological change is to invest in complementary assets that allow individuals and companies to fully harness the power of digital technologies.
These investments, however, will be underprovided by markets, be it because private actors cannot exclude others from the fruits of their investment (public goods), because public benefits exceed private benefits (externalities), or because actors have myopic preferences or insufficient knowledge about the payoff of investments (uncertainty, non-rational choices, information asymmetries). Governments – as the only actors with the necessary resources and interests – are thus called upon to invest in the public goods of advanced capitalism [@Fournier.2016; @Iversen.2019, p. 157].
This is particularly true for investments in knowledge-based capital - from education and retraining to basic research and innovating funding - for which the overall benefits for society are considerably higher than the private benefits [@EuropeanCommission.2017a, p. 29]. R&D investments, for example, have been shown to increase long-term growth and labor productivity [@Fournier.2016; @EuropeanCommission.2017a] and to “crowd-in and galvanize other forms of investment” [@Mazzucato.2019, p. 3]. Likewise, investments in (co-)clustered skills are seen as central to the economic success of countries or regions [@Iversen.2019].
Such ‘soft’ investments in knowledge-based capital – as opposed to ‘hard’ investments in physical infrastructures – have already been essential in “creating conditions required for the prosperity and sustainability of a ‘post-industrial’ or ‘knowledge society’” [@Streeck.2011a, p. 2; cf. @Fournier.2016, p. 13]. Today, artificial intelligence further speeds up the ‘race between technology and education’ while making R&D capabilities both more useful and necessary. As a result, investments in knowledge-based capital have become even more essential in the emerging digital or ‘new’ knowledge economy.
But it is not only markets that fail to invest enough. Governments often fail too. Not only is there a persistent investment gap across all advanced capitalist democracies (compared to what would be socially optimal), the size of this gap also varies across countries [@Borunsky.2020]. Figure 3.1 plots the dependent variable of this study: a index that captures investments in knowledge-based capital for various countries over time over time (for more details, see below). We see that despite a shared emphasis by all countries on the ”urgency for governments to be proactive” in shaping the digital transformation [@OECD.2017, p. 22], some countries are much more proactive. We also see that some countries continued to increase their investments in knowledge-based capital over time while others failed to do so. Finally, we see that while richer countries tend to invest more, this relationship is by no means straightforward, with many countries investing much more or much less than their similarly rich peers. This raises the puzzle of how to explain the diachronic and synchronic variation in how much countries invest in knowledge-based capital.2
full_data_imp <- bind_rows(unclass(amelia.out$imputations), .id = "m")%>%
filter((Year>1994 | Country %in% countries.selected & Year >1980) & Year <2019)%>%
group_by(m)%>%
mutate(dii_score_gdp = scale((edu_exp3_gdp + rd_gdp + alp_gdp)))%>%
group_by(Country, Year)%>%
summarise(across(c(dii_score_gdp), mean))
full_data_imp %>%
filter(!is.na(dii_score_gdp)) %>%
mutate(Period = ifelse(
Year %in% (1980:1989),
"1980s",
ifelse(
Year %in% (1990:1999),
"1990s",
ifelse(Year %in% (2000:2009), "2000s", "2010s")
)
)) %>%
group_by(Period, Country) %>%
dplyr::summarise(dii_score_gdp = mean(dii_score_gdp)) %>%
ungroup() %>%
ggplot() +
geom_col(
aes(reorder(Country, -dii_score_gdp), dii_score_gdp),
data = . %>% filter(Period == "2010s"),
show.legend = F,
alpha = 0.4,
fill = "#377eb8"
) +
geom_point(
aes(
x = reorder(Country, -dii_score_gdp),
y = dii_score_gdp,
shape = Period,
color = Period
),
data = . %>% filter(Period %in% c("1980s", "1990s", "2000s", "2010s"))
) +
ggthemes::theme_tufte() +
scale_color_brewer(palette = "Set2")+
theme(
axis.text.x = element_text(angle = 45, hjust = 0.9),
text = element_text(size = 12),
legend.position = "top"
) +
labs(
x = "",
y = "Normalized Index for Knowledge Investments",
color = "",
shape = ""
)
Figure 3.1: Normalized Investment Index (1980s-2010s). Values are averaged across multiple imputations.
The existing literature on the politics of investment policymaking has focused on partisan and structural factors, and more recently also on institutional ones. Partisan accounts emphasize the role of political parties in shaping public investment. Structural accounts focus on forces that are outside the immediate control of governments like deindustrialization or independent of partisan preferences like the exigencies of the political business cycle. Institutional approaches have argued that the relationship between political agency and structural constraints is moderated by the institutional features of a polity. My own argument builds on such institutional approaches but more explicitly theorizes the role of intertemporal in addition to cross-sectional trade-offs.
Starting with @Boix.1997, the modern literature on the politics of investment policies has focused on the role of the partisan composition of government in explaining countries’ supply-side policies. Boix argued that because of their growth-enhancing effects, governments are relatively unconstrained in their ability to make supply-side investments, even in a globalized economy. But because such investments disproportionately benefit their voters, social democratic parties should favor higher levels of public investment, even at the price of higher taxes. Thus, Boix advances the two main claims of partisan accounts: that parties have an independent effect on investment policies; and that parties on the left and the right will have different effects [@Busemeyer.2009, pp. 108–09].
The more recent literature has advanced this partisan argument in several ways. For example, distinguishing between party families has been proposed as a more fine-grained distinction than the left-right dichotomy as there are important differences between conservative, christian-democrat and liberal parties as well as between social democratic and other leftist parties [@Garritzmann.2016, p. 514]. However, even that might not be sufficient as parties within the same party family often have different position while parties in different families have similar positions. Therefore, instead of relying on indirect assumptions about party positions, it is suggested to directly measure them using party manifestos [@Garritzmann.2016, pp. 516–17].
Structural approaches argue that it is not so much the investment preferences of political parties and their constituencies but rather broader structural trends that influence investment spending. @Jensen.2011 finds that it is not the partisan composition of government that explains public investments in education, but the level of deindustrialization. @Streeck.2011a argue that under austerity, the choice for investments becomes much harder as the overall amount of discretionary spending shrinks. Unless the amount of discretionary spending is increased through higher taxes, which is unlikely given broader ideological and economic constraints, ‘soft’ investments in education, R&D, active labor market policies, and families will decline [@Streeck.2011a, p. 23].
@Breunig.2012 find support for this argument, finding that public investments, which are discretionary spending, are hit harder by fiscal austerity than entitlement spending. This is because politicians have lower electoral incentives and face higher political obstacles in maintaining investments. Similarly, @Ronchi.2018 finds that in the aftermath of the euro crisis, the expansion of social investment policies slowed down considerably and almost stagnated, while the conflict between social investment and social consumption policies became starker. Likewise, @Jacques.2020 shows that governments choose the path of least resistance when implementing austerity measures. Because the benefits of investments are diffuse and become visible mostly in the future, they are least protected from fiscal consolidation.
The argument of these structural accounts is not that parties do not matter, but that their differences do not really make a difference. In other words, parties in government make policies, but these policies result not from political differences but from parties operating under tight structural constraints they have little immediate control over. These constraints can be economic or ideological but they can also be electoral.
Moving to institutional approaches, @Breunig.2012 also find that the effect of austerity on cutbacks in discretionary spending is conditional on the electoral system. In majoritarian systems, where constituencies are more concentrated, politicians have more incentives to shield discretionary spending from cutbacks, whereas in proportional systems, politicians are more likely to protect entitlement spending to avoid alienating the broad beneficiaries of these programs. Institutional factors may also supersede partisan factors over time. @Garritzmann.2016 find no partisan effect on education spending since 1995. But this does not mean that parties never mattered; it just means that they stop doing so as investment policy areas mature and institutional path-dependencies started to carry more and more of the explanatory weight [cf. @Beramendi.2015].
Importantly, these approaches tend to focus more on cross-sectional and less on intertemporal trade-offs. But even if we agree with @Boix.1997 that supply-side investments allow policymakers to sidestep cross-sectional trade-offs, they still face these intertemporal ones. Put differently, governments are often disincentivized from implementing investment policies not only because they cost or benefit some groups more than others in the present; but also because they imply “welfare trade-offs at the expense of the present and in favor of the future” [@Jacobs.2016, p. 434]. First, governments never know if future governments will commit to the same investment policies or divert resources to their own (short-term) political ends. This is what Jacobs calls the “fragility of political commitments” problem [@Jacobs.2016, p. 440]. It implies that governments will only invest in the long run at short-run expense if they can be confident that their investments will not be reverted or salvaged by future governing parties. Second, governments can never be certain that voters will adequately factor in the future benefits of investments. This is what calls the “information about long-term consequences” problem [@Jacobs.2016, pp. 439–40]. It implies that politicians will bias their policies towards the short-run to the extent that the salience of information about the short run is high and the quality of information about the long run is low.
However, the problems associated with uncertain ‘political property rights’ (Terry Moe) and incomplete markets for future-oriented policies are not insurmountable. On the one hand, institutions that disperse and fragment power have been argued to increase investment by incentivizing politicians to maintain commitments [@Jacobs.2016, p. 445; @Lindvall.2017] and by diffusing the blame for short-run costs [@Jacobs.2016, p. 444]. Building on these arguments, @Jacques.2021 [p.2] finds that power-sharing institutions such as proportional electoral systems or corporatist interest group mediation can help “break political uncertainty about future investment by ‘locking in’ commitments” and thereby strengthen the capacity of governments to overcome intertemporal trade-offs [@Jacques.2021, p. 2]. On the other hand, “cooperative institutions” that “promote cooperation among economic actors” allow for credibly compensating actors for the short-term costs of investments while credibly involving them in their long benefits [@Hicks.1998, p. 1634]. And @Finnegan.2022 indeed finds that proportional representation and interest group concertation increase the stringency of climate policies by lowering political costs through ensuring credible compensation.
In making the case for partisan explanations, Boix had explicitly argued against the view that corporatist institutions matter for the ability of governments to invest in the supply-side of the economy. Governments can do so “without the consent of organized labor” [@Boix.1997, p. 819]. But in today’s societies, there are many actors, including labor, that can raise the political costs of investments [@Finnegan.2022]. The promise of power-sharing and cooperation-inducing institutions is that they necessitate and facilitate political bargaining between winners and losers of investment policies. They also give actors a longer time horizon and a more cooperative attitude as being forced to cooperate now means one is most likely also forced to cooperate in the future. This mitigates both the cross-sectional and the intertemporal trade-offs associated with long-term policymaking and thus allows for the realization of ‘collective gains’ [@Hicks.1998; @Lindvall.2017].
The prime example of such a power-sharing and cooperation-inducing institutional arrangement is neocorporatism, understood here as the “institutionalized and privileged integration of organized interests in the preparation and/or implementation of public policies” [@Christiansen.2020, p. 161]. Corporatist institutions can aid “compromises that are more socially acceptable (that do not provoke an adverse response from social actors) and more sustainable (that reduce the risk of policy reversals by future governments)” [@Lindvall.2017, p. 133] - and thus increase long-term investments. If actors have the ability to veto policy change if they are not compensated, this incentivizes governments to give them a seat on the table. This, in turn, makes it less likely that social partners act confrontationally and opportunistically, not least because they know they can be vetoed themselves in the future. Over time, this leads to repeated, compromise-oriented, and often positive-sum interactions, which increases mutual trust and habituates actors into a collaborative mindset. I therefore hypothesize that
higher levels of corporatism lead to higher levels of investments in knowledge-based capital (H1).
There are a number of ways to illustrate this argument. First, game-theoretical modeling has shown that there is no trade-off between the involvement of all social partners in the policymaking process and the ability to non-opportunistically adjust to external change [@Tommasi.2014]. This is because having more potential veto players “means not only more veto players today, but also in the future; this affects the likelihood that any current veto player is also a veto player in the future, and this might lead to different choices than if there was no tomorrow. [M]ore veto players at one point in time might [also] make deviations from cooperative equilibria less appealing and lead to more cooperative policymaking” [@Tommasi.2014, p. 224].
Second, there is the neocorporatist literature, old and new. @Katzenstein.1985 [p.30] famously argued that the secret behind the politico-economic success of corporatist states is to compensate enough to maintain a political consensus but not so much as to impair economic efficiency. This allows for proactive adaption to (as opposed to resistance against) change. @Ornston.2012 recently took up this argument, arguing that far from inhibiting the redistribution of resources into high-tech industries, or only being conducive to incremental innovation in low- and medium-technology industries, corporatist institutions have enabled sizable investments in human and innovational capital and “supported unprecedented movement into new, high-technology industries” [@Ornston.2013, p. 706]. This ‘creative corporatism’ relies on repurposing or converting corporatist institutions into vehicles for the “construction of new supply-side resources” [@Ornston.2013, p. 710]. Ornston thus documents the continued success story of small corporatist states in today’s knowledge economy.
The Danish reforms of the last decades can help illustrate this argument. Before the 1990s, Denmark was characterized as ‘a small state in big trouble’ [@Schwartz.1994]. Shortly after, it experienced an economic ‘miracle’ [@Schwartz.2001], having massively expanded investments in knowledge-based capital and successfully moved into knowledge-intensive markets [@Ornston.2012, pp. 92-125]. Crucial to this success story was Denmark’s ability to re-purpose its corporatist institutions to foster supply-side investments. Denmark’s “history of constructive collaboration (…) enabled policymakers to move beyond distributive bargaining to tackle sensitive issues such as financing, skill formation, and research” [@Ornston.2012, p. 198]. For example, the tripartite Zeuthen Commission “linked social benefit reform to active labor market expenditure and greater collaboration in training”; it thus created a “focal point (…) for subsequent bargaining”, which helped to mobilize a “broad consensus for investments in human capital” [@Ornston.2012, p. 103].
I further put this argument to the test by formulating three follow-up hypotheses. First, Katzenstein argued that the ability of corporatist states “to live with change” [@Katzenstein.1985, p. 211] instead of resisting it, to equitably adjust to it instead of bitterly fighting over it was grounded not only in formal corporatist institutions but also in an informal “ideology of social partnership” [@Katzenstein.1985, p. 32]. For him, an important - although not sufficient - factor in bringing about this ideology was the relative ‘smallness’ of many corporatist countries. Thus, the ideology of social partnership - the “glue” [@Katzenstein.2003, p. 11] behind the corporatist states collaborative style of policymaking - was partly born out of the small European states’ perceived vulnerability to economic and political crises. Smallness, in other words, fosters a shared sense of vulnerability and lowers barriers to collective action [@Katzenstein.2003]. “Traveling around small states”, @Katzenstein.2003 [p.11] notes, “is not time-consuming. And if you give a party in the capital, you can easily invite all the important political players. This makes a difference to both politics and policy.” I thus argue that
smaller states have higher levels of investment in knowledge-based capital (H2a)
Second, there is a question whether one really needs a collaborative style of policymaking or whether power-sharing and the concomitant difficulty of reversing policy is enough. Following the neocorporatist literature, I argue that it is really a sense of “‘shared ownership’ of policy problems” [@Hemerijck.2001 p.227] that provides corporatist countries with the ability to make sacrifices now to collectively benefit in the future. Ultimately, corporatism works not by locking in commitments, but by instilling a “culture of compromise” that couples “narrowly conceived group interests with shared interpretations of the collective good” [@Katzenstein.1985, p. 32]. The alternative hypothesis, which I argue against here, is that institutional constraints themselves, by making policy reversal less likely, will lead to higher public investments. @Henisz.2002, for example, has argued precisely that, showing how political institutions that limit the feasibility of policy change (e.g., independent branches of government) lead to higher overall investments in infrastructure. I, however, do not expect such institutions to have an an independent effect as, unlike corporatist institutions, they do not necessarily create a culture of compromise and sense of common ownership of policy problems. I therefore posit that
higher institutional constraints on the feasibility of policy change themselves do not lead to higher levels of investment in knowledge-based capital (H2b).
Third, in line with the Katzenstein-Ornston argument about the ability of (small) corporatist states “general capacity to adapt” [@Hemerijck.2001 p.227], I argue that the existence of strong corporatist institutions should help countries to better react to technological and economic change. @Jensen.2011 hit on a similar point, showing that the impact of deindustrialization is conditional on a country’s variety of capitalism. In coordinated market economies, where skills are more specific, deindustrialization is a greater threat to workers. And since expanding education is a promising avenue for re-skilling, demand for it will be higher, although the precise direction of spending will differ even among coordinated market economies [@Thelen.2019]. Similarly, I argue that corporatist countries - reinventing their corporatist institutions to meet new challenges - will tend to increase supply-side investments in the face of deindustrialization. I therefore hypothesize that corporatism not only leads to overall higher levels of investments in knowledge-based capital but also that
corporatism moderates the effect of deindustrialiaztion on investment spending in that investments are decreased (increased) at low (high) levels of corporatism (H2c).
To test my argument – and to test it against existing explanations – I compiled a dataset for 32 advanced capitalist democracies from 1995 to 2018, and for 20 of these countries from 1981 to 2018.3 These data are well suited to answer the question of how countries responded to the rise of the knowledge economy, which emerged in the 1980s, took off in the 1990s, and further accelerated in the 2010s.
The dependent variable of this study is an index that captures investment in human and innovational knowledge-based capital, plotted in Figure 3.1. It is composed of three sub-indicators: spending on education to measure investments in human capital, spending on R&D to measure investments in innovational capital, and spending on active labor market policies (ALMP) to measure investments in both human (retraining) and innovational capital (start-up incentives). These spending variables are measured as a share of GDP [@Streeck.2011a, pp. 6–7]. The indicators were added up and normalized (for details, see appendix A14.1.1).
The first explanatory variable – the partisan composition of government – was operationalized in two different ways, reflecting disagreements in the literature. Indirectly, as the proportion of cabinet shares held by social-democratic parties; and directly, as the average issue emphasis on investment issues of all cabinet parties, weighted by their respective seat shares [@Garritzmann.2016]. The latter category is operationalized as the relative combined emphasis parties place on public investments in research and development, infrastructure, and education and on an active, involved role of the state in the economy (for details, see appendix A24.1.2).
The second explanatory variable – corporatism – is constructed based on Jahn’s [-@Jahn.2016] index of corporatism, which takes into account the organizational structure of collective actors, the functional relationship between collective actors and the state, and the scope or coverage of collective bargaining. This definition operationalizes corporatism as a politico-economic gestalt, understanding it as both a tool for economic coordination and the integration of organized interests in policymaking [@Christiansen.2020, p. 161]. However, while the paper uses the encompassing definition of corporatism, the appendix replicates the analysis with a more narrow operationalization that only takes into account corporatism’s functional aspects (see appendix A34.1.3). Corporatism is compared to and contrasted with an institutional constraints variable which measures the feasibility of policy change, i.e. “the extent to which a change in the preferences of any one political actor may lead to a change in government policy” [@Henisz.2002, p. 363]. Small stateness is a dummy variable indicating whether or not a country’s population is smaller than 6 million (loosely based on Katzenstein’s analysis). Appendix B44.2.4 shows an alternative specification.
The remaining variables were measured as follows: Trade Openness is measured as the average of exports and imports as a share of GDP [@Busemeyer.2009]. Deindustrialization, following @Jensen.2011, is measured as the share of people working in the service sector. Deficit is measured using cyclically adjusted budget deficits to control out the effect of economic conditions, with positive values indicating a surplus. The debt rule variables is collected from the corresponding IMF dataset and is a dummy variable with 1 indicating that a debt rules exist and that there is no investment exception. EU membership, and unemployment are self-explanatory. The time dimension was modeled with cubic splines to account for non-linear dynamics [@Garritzmann.2020b]
Missing data were handled with multiple imputation whereby several complete, rectangular datasets were created with missing observations estimated from all available data. This was done using the Amelia algorithm, which explicitly takes into account the time-series-cross-sectional nature of the data [@Honaker.2010]. After running the model on each imputed dataset, results were combined using Rubin’s rules whereby coefficient estimates as well as goodness-of-fit statistics are averaged across multiple imputations while standard errors were combined in a way that both averages uncertainty across models and accounts for disagreement in the estimated values across the models. Multiple imputation avoids the inefficiencies and potential biases associated with dropping missing values but also reflects the uncertainty that comes from using imputed missing values. Appendix B4.2 provides more details on the imputation process as well as diagnostics that help evaluate the validity of the imputations.
Empirically, I use within-between mixed-effects models [@Bell.2015; @Bell.2018; @Bell.2019]. This has three main advantages over standard time-series-cross-section regressions on annual observational data that use country fixed-effects. First, it more accurately models the nested structure of the data [@Garritzmann.2020b]. Governments do not change annually. Using country-years as the unit of analyses therefore artificially inflates the number of observations, which leads to anti-conservative estimates. An alternative would be to use cabinet terms as the unit of analysis [@Garritzmann.2016]. This approach, however, ‘sacrifices’ information as many variables do indeed vary annually but have to be aggregated to the cabinet-term level. By treating annual observations as nested in government terms which are in turn nested in countries, mixed-effects models allow for the “simultaneous estimation of the effects of variables with different time intervals – that is, variables that vary annually, over several years, or not at all within countries” [@Garritzmann.2020b, p. 631].
Second, using mixed-effects models allows for the separation of within and between effects (as well as for the inclusion of time-constant variables). The common approach to modeling clustered time-series-cross-section data is to use cluster (e.g. country) fixed-effects. This neutralizes the statistical problems associated with pooling clustered data at the price of controlling out all between-cluster variation. However, the between-effects of variables are often as theoretically interesting as their within-effects – and can go in a different direction [@Bartels.2015]. Moreover, fixed-effects models make it impossible to estimate the effects of time-invariant variables as all the degrees of freedom at the higher level have been consumed by the cluster dummies [@Bell.2015, p. 139].
Standard random-effects models, meanwhile, partition the unexplained residual variance into a higher-level variance between entities and a lower-level variance within these entities, assuming that higher-level entities come from a single (normal) distribution which is estimated from the data. They do not, however, separate the within effect from the between effect but rather estimate a weighted average of the two, which has little substantive meaning [@Bell.2019, p. 1057]. However, by including group-mean centered lower-level predictors (country-averaged annual observations in this case), one can recognize the possibility of and explicitly model differences between within and between effects [@Bell.2015, p. 141; @Bell.2018].
Third, within-between mixed models have additional statistical advantages. By partially pooling information across countries, they strike a balance between fixed-effects models, in which nothing can be known about any higher-level entity (i.e. country) from knowledge about all or any of the others; and completely pooled models in which it is assumed that there are no differences between higher-level entity and so knowing one means knowing all (Bell et al. 2019, p. 1061). Instead, higher-level entities are treated as distinct but not completely different. In effect, the estimates for the random intercepts are shrunk towards their mean, with the most extreme (and least reliable) estimates being shrunk the most. This allows us to estimate more reliable residuals for higher-level entities, estimate coefficients for higher-level variables, and estimate how much variance there is at different levels [@Bell.2015, p. 144; @Bell.2019, p. 1061]. Furthermore, mixed-effect models allow for modeling heterogeneity in the effect of lower-level variables via random slopes and cross-level interactions. This can be used to assess whether the effect of a lower-level variable X depends on a higher-level variable Z, or even whether the within-cluster effect of X depends on between-cluster variation in X [@Bartels.2015].4
In the paper, I estimate three increasingly complex models. The first model is a three-level random intercept model without separate within and between effects:
\[y_{tgc} = \beta_0 + \beta_{1}x_{tgc} + \beta_{2}w_{gc} +\beta_3z_c + \nu_{00c} + u_{0gc} + \epsilon_{tgc}\] Variables are measured at multiple occasions (\(t\)), for multiple governments (\(g\)), in multiple countries (\(c\)). \(y_{tgc}\) is the dependent variable; \(x_{tgc}\) is a vector of annually observed (i.e. level-one) variables; \(w_{gc}\) is a vector of government-term (i.e. level-two) variables; and \(z_c\) is a vector of country-specific (i.e. level-three) variables. This is the fixed part of the mixed-effects model. The random part consists of a country-level error term (\(\nu_{00c}\)), a government-level error term (\(u_{0gc}\)) and a occasion-level error term (\(\epsilon_{tgc}\)). The residuals thus capture unexplained variability at three nested levels.
The second model separates out the within and between effects but assumes homogeneous effects of the level-one independent variables across higher-level entities.
\[y_{tgc} = \beta_0 + \beta_{1W}(x_{tgc}-\bar{x}_c) + \beta_{2B}\bar{x}_c + \beta_{3}w_{gc} +\beta_4z_c + \nu_{00c} + u_{0gc} + \epsilon_{tgc}\]
Here \(\beta_{1W}\) represents the average within effect of level-one independent variables, while \(\beta_{2B}\) represents the between effect of level-one independent variables. \(\beta_3\) represents the effect of country-specific (time-invariant) variables and therefore also captures a between effect (higher-level variables cannot have a within effect since they do not vary over time). The separation of within and between effect is accomplished by group-mean centering the level-one independent variables \(x_{tgc}-\bar{x}_c\). This is similar to what fixed-effects regressions do, but allows us to additionally model the between effect by including the group mean of the level-one covariates \(\bar{x}_c\).
The third model is equivalent to model 2 but does not assume homogeneous effects across higher-level entities. It attaches a random effect not only to the intercept but also to the within slope that allows for heterogeneity in the effect of the level-one independent variables. Including random slopes is not only substantively interesting. Simulations have shown that a failure to include random slopes when the homogeneity-of-effects-across-units assumption is violated can lead to anti-conservative estimates of the within effects as standard errors are underestimated [@Bell.2019]. Moreover, including cross-level interactions between lower and higher-level variables similarly leads to anti-conservative estimates if random slopes on the lower-level components of those interactions are not included [@Heisig.2019].
\[y_{tgc} = \beta_0 + \beta_{1W}(x_{tgc}-\bar{x}_c) + \beta_{2B}\bar{x}_c + \beta_{3}w_{gc} +\beta_4z_c + \nu_{00c} + \nu_{10c}(x_{tc}-\bar{x}_c) + u_{0gc} + \epsilon_{tgc}\]
Table ?? shows the results of the different model specifications. All continuous variables are normalized to both aid model convergence and ensure better interpretability of coefficients. One advantage of mixed-effects models is that they provide us with the basic partition of the variability in the data between different levels. For this purpose, we can estimate a three-level random intercept model without explanatory variables. This empty model shows that the bulk of the variance stems from the country level. In other words, there is much more variance between countries than there is between governments or within countries. This is perhaps unsurprising given path-dependencies within countries. But it also makes it all the more necessary to explicitly model between effects and group-level variables. In a way, much of what we need to explain is why different countries invest so differently in knowledge-based capital, more than why they – or different governments within these countries – invest more or less over time.
texreg::htmlreg(
c(texreg_melded[[1]], texreg_melded[[2]], texreg_melded[[3]], texreg_melded[[4]], texreg_melded[[16]]),
custom.model.names = c("Empty", "Model 1", "Model 2", "Model 3", "Model 4"),
label = "tab:models",
use.packages = F,
single.row = F,
stars = c(0.001, 0.01, 0.05, 0.1),
symbol = "\\circ",
booktabs = T,
scalebox = 0.79,
digits = 3,
caption = "Mixed-Effect Models",
bold = 0.05,
custom.coef.map = list(
"(Intercept)" = NA,
"dii_score_gdp_lag_normal" = "Lagged Dependent Variable",
"gov_seat_share_normal" = "Social Democratic Party",
"Investment Emphasis" = "Weighted Emphasis Investment",
"corp_index_normal" = "Corporatism",
"corp_index_within_normal" = "Corporatism (within)",
"corp_index_between_normal" = "Corporatism (between)",
"h_polcon5_normal" = "Institutional Contraints",
"capb_normal" = "Adjusted Deficit",
"capb_within_normal" = "Adjusted Deficit (within)",
"capb_between_normal" = "Adjusted Deficit (between)",
"deindustrialization_normal" = "Deindustrialization",
"deindustrialization_within_normal" = "Deindustrialization (within)",
"deindustrialization_between_normal" = "Deindustrialization (between)",
"ratio_normal" = "State Identity",
"trade_open_normal" = "Trade Openness",
"unemployment_normal" = "Unemployment",
"share_elderly_normal" = "Share 65+",
"small_state_binary_2" = "Small State",
"hard_debt_rule" = "Debt Rule",
"eu" = "EU Member",
"deindustrialization_within_normal:corp_index_between_normal" = "Corporatism*Deindustrialization",
"gdp_capita_normal" = "GDP/Capita"),
custom.gof.names = c("AIC",
"N (Total)",
"Variance Government Level",
"Variance Country Level",
"Residual Variance",
"N (Government)",
"N (Country)",
"Covariance Random Slope/Intercept",
"Variance Random Slope"),
reorder.gof = c(1,6,7,2,3,4,5,9,8))
| Empty | Model 1 | Model 2 | Model 3 | Model 4 | |
|---|---|---|---|---|---|
| (Intercept) | -0.015 | -0.958*** | -0.964*** | -0.874*** | -0.754*** |
| (0.150) | (0.196) | (0.180) | (0.201) | (0.213) | |
| Social Democratic Party | -0.005 | -0.005 | -0.002 | 0.001 | |
| (0.016) | (0.016) | (0.015) | (0.015) | ||
| Corporatism | 0.033 | ||||
| (0.024) | |||||
| Corporatism (within) | 0.012 | 0.009 | 0.001 | ||
| (0.010) | (0.009) | (0.010) | |||
| Corporatism (between) | 0.319* | 0.350** | 0.537*** | ||
| (0.131) | (0.131) | (0.148) | |||
| Institutional Contraints | 0.001 | 0.001 | -0.009 | 0.001 | |
| (0.020) | (0.020) | (0.028) | (0.020) | ||
| Adjusted Deficit | -0.097*** | -0.098*** | -0.100*** | -0.088*** | |
| (0.016) | (0.016) | (0.016) | (0.016) | ||
| Deindustrialization | 0.187*** | ||||
| (0.051) | |||||
| Deindustrialization (within) | 0.098** | 0.139* | 0.158* | ||
| (0.034) | (0.062) | (0.077) | |||
| Deindustrialization (between) | 0.493*** | 0.503*** | 0.619*** | ||
| (0.122) | (0.121) | (0.139) | |||
| Trade Openness | -0.053 | -0.055 | -0.227*** | -0.355*** | |
| (0.042) | (0.042) | (0.051) | (0.059) | ||
| Unemployment | 0.153*** | 0.160*** | 0.117*** | 0.130*** | |
| (0.021) | (0.022) | (0.021) | (0.022) | ||
| Small State | 0.959*** | 0.915*** | 0.815*** | 0.814* | |
| (0.230) | (0.212) | (0.223) | (0.372) | ||
| Debt Rule | -0.041 | -0.039 | -0.017 | -0.029 | |
| (0.034) | (0.034) | (0.035) | (0.044) | ||
| EU Member | 0.076 | 0.073 | 0.090 | 0.148 | |
| (0.051) | (0.051) | (0.062) | (0.087) | ||
| Corporatism*Deindustrialization | 0.108* | 0.153* | |||
| (0.047) | (0.063) | ||||
| AIC | 1056.412 | 623.384 | 622.367 | 483.502 | 237.280 |
| N (Government) | 441 | 441 | 441 | 441 | 298 |
| N (Country) | 32 | 32 | 32 | 32 | 20 |
| N (Total) | 1167 | 1167 | 1167 | 1167 | 836 |
| Variance Government Level | 0.294 | 0.153 | 0.154 | 0.093 | 0.098 |
| Variance Country Level | 0.690 | 0.670 | 0.484 | 0.482 | 0.367 |
| Residual Variance | 0.048 | 0.034 | 0.034 | 0.032 | 0.026 |
| Variance Random Slope | 0.056 | 0.065 | |||
| Covariance Random Slope/Intercept | 0.017 | 0.039 | |||
| p < 0.001; p < 0.01; p < 0.05; p < 0.1 | |||||
The next step is to include explanatory variables. Model 1 does so by modeling the relationship between investments in knowledge-based capital and the explanatory variables in a three-level mixed effects model without separate within and between effects. A first finding is that the composition of government does not seem to have an effect on investment spending. This is true regardless of whether we measure government composition as the share of social democratic parties in government, or as the relative emphasis that government parties put on investment (see appendix B44.2.4 for this specification). This is consistent with the recent literature, which argues that if we accurately model partisan factors (with governments not years as the units of observation), and if we look at the more recent, institutionally denser past, we should not find (strong) partisan effects on investment spending [@Garritzmann.2016; @Garritzmann.2020b].
Moving on to the central argument of this paper, the corporatism index in model 1 shows no significant association with investment spending. However, model 2 and model 3 separate within and between effects, which were lumped together in the model 1. The within-between models reveal that the effect of corporatism is not a within but a between effect, and that this between effect is strong and highly significant. Countries that are one standard deviation more corporatist have around a third of a standard deviation more investments, while becoming more corporatist does not have this effect. Importantly, while these models use the structural, functional, and scope dimensions of corporatism, the results are the same if we use the functional dimension only, i.e., the degree of concertation, which is the most important dimension for the theoretical argument (see appendix B44.2.4).
This is strong evidence in support of H1 on the the importance of corporatist institutions for investments in knowledge-based capital. I extensively discussed why I think this should be the case in section 3, building on the theoretical and empirical literature on corporatism. However, it ultimately requires detailed qualitative evidence to really understand how this works on the ground - evidence that I cannot provide here. However, by testing the follow-up hypotheses, one can nonetheless dig a bit deeper. To start with, one can look at whether non-corporatist institutional constraints like the number of independent branches of government or the degree of legislative fractionalization have an effect on investment spending. If this were the case, it would lend support to the power-sharing argument and suggest that corporatism might just be another way in which the feasibility of policy change affects investment spending [cf. @Henisz.2002, p. 363]. This, however, is not the case, even when we separate within and between effects (see appendix B44.2.4).
While power-sharing institutions seem to make parties prioritize investments in their manifestos [@Jacques.2021], they do not increase investment spending independent of the effect of corporatism. This is evidence in favor of H2b. It is also a hint that corporatist institutions are not just about ensuring credible commitments through power-sharing. Instead, the results suggest, it is the collaborative style of policymaking that they induce that leads to higher investments. Investments are more likely in countries where social actors have an “ideology of social partnership” [@Katzenstein.1985, p. 32] and a sense of “‘shared ownership’ of policy problems” [@Hemerijck.2001, p. 227] that allow them to overcome intertemporal trade-offs and tap into the positive-sum potential of investment policies. If this were the case, we would also expect smallness to lead to more investments, as smallness is conducive to mutual trust and collaboration as hypothesized in H2a. And this is indeed what we find: small states tend to have much higher levels of investment compared to larger ones. However, there are no clear guidelines for how to operationalize ‘smallness’, so this finding should be interpreted with some caution (for alternative specifications, see appendix B44.2.4).
Another important finding relates to the way in which corporatism moderates the effect of deindustrialization on investment spending. Similar to @Jensen.2011, I find a sizable and highly significant effect of deindustrialization on investment spending. This is both a between effect, that is, countries that are more deindustrialized spend more on investments in knowledge-based capital; and a within effect, that is, countries that industrialize also invest more. Crucially, as suggested by Jensen himself and as argued in the theoretical discussion of the adaptive benefits of corporatist institutions, the within effect of deindustrialization depends on institutional variables and differs across countries.
Model 3 shows a interaction effect between the within effect of deindustrialization and the between effect of corporatism. If we only focused on advanced Western democracies (for which we have longer time-series), we see that this interaction effect becomes even stronger (see model 4). Figure 3.2, which is based on model 3, shows that an increase in deindustrialization leads to the same or even lower spending in countries with low levels of corporatism. The higher the levels of corporatism, meanwhile, the stronger the positive effect of deindustrialization on investment spending. While we need to interpret these results with some caution given the relatively low number of observations of the moderator variable [@Hainmueller.2019], they do lend further tentative support to Ornston’s argument that corporatist countries can reinvent their corporatist institutions to foster supply-side investment in the face of technological and economic change.
interaction <- models_imputations %>%
dplyr::select(model_3) %>%
mutate(
interaction = model_3 %>% map(
~ interplot::interplot(m=., var1 = "deindustrialization_within_normal", var2 = "corp_index_between_normal")$data))%>%
unnest(interaction)%>%
dplyr::select(-model_3)%>%
mutate(index = seq(1,32))%>%# we create an index variable for the 32 countries to then summarize the coefficients by country
group_by(index)%>%
summarise(across(c(fake, coef1, lb, ub), mean))%>%
ungroup()%>%
dplyr::select(-index)
interaction %>%
ggplot() +
geom_histogram(
aes(x = fake,
y = ..count../30),
bins = 12,
alpha = 0.3,
position = "identity",
linetype = 1,
fill = "gray",
color = "white"
) +
geom_line(aes(x = fake, y = coef1+.5)) +
geom_ribbon(aes(
x = fake,
y = coef1+.5,
ymin = lb+.5,
ymax = ub+.5
),
linetype = 2,
alpha = 0.1) +
#geom_bar(aes(x = fake))+
geom_hline(yintercept = .5, linetype = "dashed") +
scale_y_continuous(labels = function(x) x -.5)+
labs(x = "Corporatism Index", y = "Estimated Coefficeint of Deindustrialization") +
theme_minimal()
Figure 3.2: Effect of deindustrialization on investment spending conditional on level of corporatism (based on model 3). Averaged across imputations
Second, we can also observe the heterogeneity in responses to deindustrialization if we include random slopes for the within slope of deindustrialization. The slope standard deviation is \(\sqrt0.056 = 0.24\). Given that the average slope is 0.139, this implies that the effect of deindustrialization can be quite different from the effect in other countries. For example, in a country with the top 2.5% of the country-dependent effect, a one-unit increase in deindustrialization is associated with a ~ 0.619 (\(0.139 + 2*0.24\)) standard deviation increase in knowledge investments, while in a country with a low effect, it is associated with a ~ 0.341 standard deviation decrease.
Figure 3.3 plots the random slopes for the selected countries for four different models with either the full investment index as the dependent variable or individual components (see appendix B44.2.4 for the full models and appendix B64.2.6 for random slopes for all countries and models). We see that while deindustrialization has led to further increases in investment spending across categories in Denmark, despite already high levels, it has led to only small increases in the UK, with decreases in R&D spending and active labor market policies being compensated by increases in education spending. Interestingly, there are also different trajectories for corporatist countries. Echoing the qualitative findings by @Ibsen.2017, it seems that Denmark doubled down on its ‘supply-side egalitarianism’ across all dimension of knowledge investments while Sweden only increased its education investments and seemed to have reduced investments in R&D and active labor market policies, although from relatively high levels. Germany maintained high levels of investment in R&D, reflecting its ambitious innovation policy [@Thelen.2019, p. 303-304]. However, it only mildly increased its already rather low education spending. Thus, while corporatism generally leads to higher investments in knowledge-based capital, the transition trajectories of corporatist countries into the new knowledge economy differ, depending on the coalitional dynamics within corporatist institutions [@Ibsen.2017; @Thelen.2019].
random_slope_ave_maindv <- models_imputations %>%
dplyr::select(model_3) %>%
mutate(
ranslo = model_3 %>% map(
~ coef(.)$Country %>%
rownames_to_column(var = "Country") %>%
dplyr::select(Country, `(Intercept)`, deindustrialization_within_normal)
),
coeff = model_3 %>% map( ~ broom.mixed::tidy(., effects = c("fixed")))
) %>%
unnest(c(ranslo)) %>%
dplyr::select(-model_3) %>%
group_by(Country) %>%
summarise(
intercept = mean(`(Intercept)`),
deindustrialization = mean(deindustrialization_within_normal)
)%>%
ungroup()%>%
mutate(mean_slope = mean(deindustrialization)) %>%# this is just the average, equivalent to the coeffiecient estimate in the regression table
mutate(deindustrialization_slope = mean_slope + deindustrialization)%>%
mutate(model = "Total")
random_slope_ave_rd <- models_imputations_robust_4 %>%
dplyr::select(model_0002) %>%
mutate(
ranslo = model_0002 %>% map(
~ coef(.)$Country %>%
rownames_to_column(var = "Country") %>%
dplyr::select(Country, `(Intercept)`, deindustrialization_within_normal)
),
coeff = model_0002 %>% map( ~ broom.mixed::tidy(., effects = c("fixed")))
) %>%
unnest(c(ranslo)) %>%
dplyr::select(-model_0002) %>%
group_by(Country) %>%
summarise(
intercept = mean(`(Intercept)`),
deindustrialization = mean(deindustrialization_within_normal)
)%>%
ungroup()%>%
mutate(mean_slope = mean(deindustrialization)) %>%# this is just the average, equivalent to the coeffiecient estimate in the regression table
mutate(deindustrialization_slope = mean_slope + deindustrialization)%>%
mutate(model = "R&D Investments")
random_slope_ave_ed <- models_imputations_robust_4 %>%
dplyr::select(model_0003) %>%
mutate(
ranslo = model_0003 %>% map(
~ coef(.)$Country %>%
rownames_to_column(var = "Country") %>%
dplyr::select(Country, `(Intercept)`, deindustrialization_within_normal)
),
coeff = model_0003 %>% map( ~ broom.mixed::tidy(., effects = c("fixed")))
) %>%
unnest(c(ranslo)) %>%
dplyr::select(-model_0003) %>%
group_by(Country) %>%
summarise(
intercept = mean(`(Intercept)`),
deindustrialization = mean(deindustrialization_within_normal)
)%>%
ungroup()%>%
mutate(mean_slope = mean(deindustrialization)) %>%# this is just the average, equivalent to the coeffiecient estimate in the regression table
mutate(deindustrialization_slope = mean_slope + deindustrialization)%>%
mutate(model = "Education Investments")
random_slope_ave_alp <- models_imputations_robust_4 %>%
dplyr::select(model_0004) %>%
mutate(
ranslo = model_0004 %>% map(
~ coef(.)$Country %>%
rownames_to_column(var = "Country") %>%
dplyr::select(Country, `(Intercept)`, deindustrialization_within_normal)
),
coeff = model_0004 %>% map( ~ broom.mixed::tidy(., effects = c("fixed")))
) %>%
unnest(c(ranslo)) %>%
dplyr::select(-model_0004) %>%
group_by(Country) %>%
summarise(
intercept = mean(`(Intercept)`),
deindustrialization = mean(deindustrialization_within_normal)
)%>%
ungroup()%>%
mutate(mean_slope = mean(deindustrialization)) %>%# this is just the average, equivalent to the coeffiecient estimate in the regression table
mutate(deindustrialization_slope = mean_slope + deindustrialization)%>%
mutate(model = "Active Labor Market Investments")
full_random_slope_ave <- random_slope_ave_rd%>%
rbind(random_slope_ave_ed)%>%
rbind(random_slope_ave_alp)%>%
rbind(random_slope_ave_maindv)%>%
mutate(model = fct_relevel(model,
"Total", "Education Investments", "R&D Investments",
"Active Labor Market Investments"))
max <- max(full_random_slope_ave$intercept)+0.25
min <- min(full_random_slope_ave$intercept)
full_random_slope_ave%>%
arrange(desc(model))%>%
filter(Country %in% c("Sweden", "Denmark", "Germany", "United Kingdom"))%>%
ggplot()+
scale_y_continuous(limits=c(min, max))+
geom_abline(aes(slope=deindustrialization_slope,intercept=intercept, linetype = model, color = model), size = 1.1, show.legend = T)+
facet_wrap(~Country, ncol = 4, scales = "free")+
theme_minimal()+
scale_color_grey()+
theme(legend.position = "bottom")+
labs(color = "",
linetype = "")
Figure 3.3: Random slopes for deindustrialization across selected countries and different models
It is important to note that corporatist countries are not free of conflicts, even in small states. There are diverging interests not just between but also within governments, employers, and unions [@Schwartz.1994; @Katzenstein.2003, p. 18]. However, the defining feature of corporatism is not the absence of interests and power, but a hybrid style of bargaining that is neither pure power nor pure persuasion [@Mansbridge.1992]. In fact, the “shift from distributional to supply side issues” [@Thelen.2014, p. 65] involved making deals - but these deals were negotiated in a collaborative mindset where actors knew that they could and had to cooperate with one another. This forces actors to seek common ground, and common ground is best found where positive-sum, collective gains can be realized.
Danish social partners, for example, reached a compromise that involved a “trade-off in which organized labor conceded cuts in the duration of unemployment support and stricter eligibility rules in return for the government’s commitment to skill formation – institutionalizing a ‘right and obligation’ to training” [@Thelen.2014, p. 146]. In other words, trade unions and Social Democrats agreed to liberalizing reforms “in return for large investments in active labor market training programs. Without this compensation mechanism, the reform would not have been possible” [@Lindvall.2017, p. 27]. Corporatism thus made compromise necessary, but this compromise took an investive, future-oriented form whose benefits both parties had the time horizon and trust to appreciate the benefits of.
In addition to confirming my argument on corporatism, my findings also show that higher cyclically adjusted budget deficits are associated with lower investment spending. The existence of a hard debt rule might also has a negative effect on investments but is not significant in most model specifications. Adverse economic conditions thus make it harder for governments to invest in the digital future. This is in line with the recent literature which finds a detrimental effect of austerity on investment spending [@Bremer.2021; @Breunig.2012; @Streeck.2011a; @Ronchi.2018; @Jacques.2020]. I also find that unemployment has a positive (within) effect on investment spending. This might indicate that rising unemployment levels might make policymakers more inclined to invest in knowledge-based capital (controlling for deficits) - this is supported by the fact that the effect of unemployment on investment spending is only significant for education and ALMP (see appendix B44.2.4). Conversely, EU membership seems to increase R&D investments but not education or ALMP investments.
As already indicated and as appendix B44.2.4 further demonstrates, my main findings are robust to different model specifications.5 They hold whether or not I include a lagged dependent variable, include GDP per capita as a control (which I did not do because of potential multicollinearity issues, see appendix B314.2.3.1), use different specifications of the dependent variable, use a different measure of the partisan variable, use different and more ‘conservative’ selections of time-series and/or cross-sectional units, among other things. Results also largely hold when I use only education spending or only R&D spending for my dependent variable, although there is some heterogeneity across different categories of knowledge investments, which warrants further research (see also @Jacques.2020 and @Kraft.2017 on differences between long-term investment policies with more or less immediate, concrete, and concentrated benefits).
Knowledge-based capital - be it in the form of individually-held human capital or collectively-held innovational capital - is often underprovided by private actors due to various kinds of market failures. Not all governments, however, are equally willing or capable to step in and compensate for the lack of private investments due to cross-sectional and intertemporal trade-offs. Against this background, this paper has addressed the question why some governments invest more in knowledge-based capital than others.
I have argued that in order to explain this variation, we need to take corporatism seriously. Corporatist institutions necessitate and facilitate negotiations between winners and losers of change, thus, over time, nourishing a more collaborative style of policymaking. This helps countries avoid the snares of future-oriented policymaking and unlock the ‘collective gain’ [@Hicks.1998] contained in investment policies. I find strong support for the claim that corporatism, rather than being an obstacle to adaptation and change, can be harnessed for the “construction of new supply-side resources” [@Ornston.2013, p. 710].
This chimes well with recent findings that political trust is associated with higher support for future-oriented social investment policies and that countries with higher levels of trust also have higher levels of social investments [@Garritzmann.2021a]. Future research could look at how corporatism and trust co-produce future-oriented policies as corporatist arrangements can both create mutual trust but trust can also grease the wheels of or sustain corporatism. I also find that austerity has a negative effect on investment spending, while the partisan composition of government does not seem to have an effect (anymore) - although this might be different on the local level or under specific conditions [@Bremer.2021].
In addition its theoretical and empirical contributions on the importance of corporatism for long-term policymaking, the paper also makes a methodological contribution. Taking up and combining arguments by @Bell.2015 and @Garritzmann.2020b, the paper demonstrates the potential of using within-between mixed-effects models for time-series-cross-sectional data. Not only do they allow for a more accurate modeling of the nested structure of many comparative politics datasets. They also allow for modeling the between (and not just the within effects) of variables, the influence of time-invariant or cluster-level variables, and the heterogeneity of effects across higher-level entities. They thus provide a viable alternative to standard fixed effects models with annual observations [@Garritzmann.2020b; @Bell.2015].
Future research should address some of the shortcomings of this paper. First, the paper remains somewhat agnostic about how exactly corporatist institutions are translated into political outcomes [cf. @Finnegan.2022]. While theory, quantitative, and qualitative evidence from this and other studies provide first insights, it remains somewhat unclear how exactly a more collaborative style of policymaking emerges from corporatist practices and how a sense of common ownership of policy problems manifests itself ‘on the ground’. In-depth case studies are needed to illuminate these processes as well as differences among corporatist countries.
Second. the paper does not pay sufficient attention to how variables that change over time interact with country-specific characteristics that are slow-changing or even time-invariant. Future studies should therefore look more systematically at heterogeneity in the effects of such transformations across countries and at the country-level characteristics that cause this heterogeneity. Moreover, future studies should look more closely at heterogeneous effects for different types of investments, including but not limited to differences between individually and collectively-held knowledge-based capital.
Given the pressing realities of climate change, pandemic risks, and digitalization, policymaking for the long term becomes ever more important. This study study has shown how corporatist institutions - and the compensation and collaboration they necessitate and facilitate - might help countries better live up to these challenges and invest more in an uncertain future.
Table 4.1 gives a descriptive overview of the continous variables used in the analysis and their source [see @Dahlberg.2020; @Visser.2019; @Doring.2019; @Volkens.2020]. Three (sets of) variables require further elaboration as their compilation was more complex: the dependent variable; the government position variables; and the corporatism index.
sources <-
data.frame(
Source = c(
"OECD",
"ICTWSS (Visser 2019)",
"CPDS",
"OECD",
"OECD and Unesco",
"OECD",
"OECD",
"OECD",
"CMP (Volkens et al. 2020) and ParlGov (Döring and Manow 2019)",
"QoG (Dahlberg et al. 2020)",
"OECD",
"OECD",
"ParlGov (Döring and Manow 2019)",
"OECD",
"OECD"
)
)
datasummary(
((`Active Labor Market Spending/GDP` = alp_gdp) + (`Corporatism Index` = corp_index) + (`Cyclically Adjusted Deficit` = capb) + (`Deindustrialization` = deindustrialization) + (`Education Spending/GDP` = edu_exp3_gdp) + (`Employment Rate` = employment) + (Growth = Growth) + (Inflation = Inflation) + (`Investment Priorities` = investment_weighted) + (`Political Constraints Index` = h_polcon5) ) + (`R&D Spending/GDP` = rd_gdp) + (`Share 65+` = share_elderly) + (`Social Democratic Seat Share` = gov_seat_share) + (`Trade Openess` = trade_open) + (`Unemployment Rate` = unemployment) ~ Mean + SD + Min + Max,
data = full_data,
fmt = "%.3f",
output = "kableExtra",
title = 'Descriptive statistics for the main variables',
add_columns = sources
)%>%
column_spec(1, width = "8.5em")%>%
column_spec(6, width = "10em")
| Mean | SD | Min | Max | Source | |
|---|---|---|---|---|---|
| Active Labor Market Spending/GDP | 0.005 | 0.004 | 0.000 | 0.039 | OECD |
| Corporatism Index | −0.006 | 0.606 | −1.109 | 1.339 | ICTWSS (Visser 2019) |
| Cyclically Adjusted Deficit | −0.185 | 3.031 | −25.868 | 10.230 | CPDS |
| Deindustrialization | 63.163 | 12.404 | 0.000 | 90.343 | OECD |
| Education Spending/GDP | 0.056 | 0.015 | 0.011 | 0.107 | OECD and Unesco |
| Employment Rate | 66.804 | 6.319 | 48.475 | 80.475 | OECD |
| Growth | 2.861 | 3.047 | −14.839 | 25.176 | OECD |
| Inflation | 6.714 | 36.776 | −4.478 | 1020.621 | OECD |
| Investment Priorities | 14.068 | 5.816 | 0.000 | 36.530 | CMP (Volkens et al. 2020) and ParlGov (Döring and Manow 2019) |
| Political Constraints Index | 0.767 | 0.118 | 0.000 | 0.894 | QoG (Dahlberg et al. 2020) |
| R&D Spending/GDP | 0.006 | 0.002 | 0.001 | 0.017 | OECD |
| Share 65+ | 0.141 | 0.036 | 0.031 | 0.291 | OECD |
| Social Democratic Seat Share | 28.578 | 37.171 | 0.000 | 100.000 | ParlGov (Döring and Manow 2019) |
| Trade Openess | 80.969 | 49.179 | 10.757 | 380.104 | OECD |
| Unemployment Rate | 7.375 | 4.171 | 0.556 | 27.466 | OECD |
The knowledge investment index comprises three subindicators, which were operationalized as follows:
Investments in education were measured as the share of GDP spend on primary, secondary and tertiary education. To obtain that measure with as few missing values as possible, I combined the OECD’s COFOG (Classification of the Functions of Government) spending data with UNESCO data on education expenditure. For the COFOG data I selected the subcategory of total education spending. I also included the social protection subcategory family and children for both substantive reasons and to make the data more compatible with the UNESCO data. This is because COFOG data are based on ISCED-97 while the UNESCO data use ISCED-2011. One of two main differences between the datasets is that the UNESCO data include education expenditure that COFOG classifies according to its main purpose as child care services under social protection, not under education expenditure.
The other main difference is that the UNESCO data include in education expenditure any research conducted in tertiary educational institutions. On the other hand, COFOG classifies R&D expenditure conducted in tertiary educational institutions to the respective functions (e.g. 01.4 basic research, 07.5 R&D health), and only includes R&D spending on education directly, i.e. pedagogy broadly conceived. The measures are thus highly but not perfectly correlated, which poses problems if data are not missing at random. I decided to prioritize data availability over potential bias (especially because data for some countries are entirely missing), but not only retained the individual measures for robustness checks but also averaged values when values from both measures were available.
Investments in R&D were measured using the OECD’s GBARD (Government budget allocations for R&D) data. The index captures overall spending on R&D as this almost per definition is meant to create knowledge-based capital. I also crated an alternative measurement that only measures spending on specific categories directly relevant for the knowledge economy - but this not only comes at the cost of data availability for some countries but might also be seen as substantively questionable.
Investments on active labor market policies were measured using the OECD’s LMPEXP dataset. Included was only spending on active (as opposed to passive) spending. In addition, administrative spending was excluded. Included was thus spending on training, job rotation and job sharing, employment incentives, sheltered and supported employment and rehabilitation, direct job creation, and start-up incentives. These categories measure investments that foster the creation and maintenance of both individually and collectively-held knowledge-based capital. The categories were just added up but results do not change if we weight the components in a number of ways that roughly reflect their absolute size.
Government positions are measured either indirectly as the share of social-democratic parties in government or directly through their expressed preferences [@Garritzmann.2016; @Schmitt.2016]. In the latter case, the emphasis of party manifestos on either of the following four categories were summed up: per404 (favorable mentions of long-standing economic planning by the government); per410 (need for government to encourage or facilitate greater production and to take measures to aid economic growth); per411 (importance of science and technological developments in industry and need for training and research within the economy as well as calls for public infrastructure spending); per506 (need to expand and/or improve educational provision at all levels). Additionally, category per507 (limiting state expenditure on education) was subtracted. These categories capture, respectively, whether parties see room for an active and leading role of the state in the economy [@Mazzucato.2013] and the importance they assign to the public provision of (knowledge-based) public goods (R&D, infrastructure, and education).
To do this, I used data from the Comparative Manifesto Project (CMP) [@Volkens.2020] as well as data on the partisan composition of cabinets from the ParlGov database (data for the United States, which is missing from the ParlGov database, were added manually) [@Doring.2019]. This allowed me to calculate the relative share of different party families in cabinets and to then weigh them by the number of days they were in office in a given year. The relative issue emphasis parties put on, or the relative importance parties they assign to, different categories - a more reasonable conceptualization of the CMP data [@Gemenis.2013, p. 19] - was calculated for each government by combining the relative emphasis of the governing parties weighted by their seat share. In years with multiple cabinets, values were taken from whichever cabinet was in office for more days.
The corporatism index used in the study is a reconstruction of Jahn’s [-@Jahn.2016] index of corporatism, which is itself based on data from the ICTWSS database complied by @Visser.2019. Jahn’s index stands out among other conceptions of corporatism not only because it uses variables that are available over many decades and for many capitalist countries; but also because it offers a parsimonious or narrow definition of corporatism that does not contain what it might be used to explain, i.e. things like small open economies, consensual or even consociational political tradition, dominance of a unified social democratic party, high level of social expenditure, and successful economic performance [@Jahn.2016, p. 51]. Rather, it focuses on the structural aspects of corporatism, i.e., the hierarchical centralization of collective bargaining; its functional aspect, i.e., “the role these organizations play vis-à-vis the state” and the “style of interest mediation by the state” [@Jahn.2016, p. 51]; and the scope of corporatism which focuses on the output side and captures who is actually affected by corporatist arrangements. The robustness checks in Appendix 4.2.4 include a version of the corporatism variable that only takes its functional dimension into account.
I additionally included variables that cover whether in a given year a (tripartite) social pact or a (nation-wide) agreement was signed. Somewhat confusingly, they are part of the do-file made available by the Jahn but are explicitly excluded from the index because there are no data on their long-term effects and because including them might lead to double counting similar effects [@Jahn.2016, p. 56]. I nonetheless included them because, as Jahn himself notes, they are meaningful indicators of corporatism and also play an important role in Ornston’s [-@Ornston.2012] conception of corporatism. The inclusion of such variables, however, does not result in noticeable differences in the index itself. Table 4.2 summarizes this conceptualization and shows how the three aspects of corporatism - structure, function, scope - are operationalized.
The reason why I had to reconstruct Jahn’s index in the first place is that the original index provided by Jahn only goes until 2010. Next to the inclusion of social pacts and collective agreements (which are, however, also part of Jahn’s do-file), there are two additional differences between Jahn’s original index and my reconstruction. First, the linear interpolation of missing data led to implausible values at least when done in R, so I was more conservative than Jahn here and only interpolated values when the maximum number of missing values was less than 4. Second, because of small differences in the normalization of the variables, my index has somewhat less variance than Jahn’s, i.e. it compresses values somewhat more to their mean, which however, should only lead to conservative estimates. Figure 4.1 plots Jahn’s original index next to my reconstruction and clearly shows that all remaining differences are very small. Both indices clearly capture the same phenomenon.
data.frame(
aspect = c("Structure", "Function", "Scope"),
description = c(
"Degree of hierarchical centralization",
"Degree of concertation with the state",
"Degree to which agreements encompass broader segments of society"
),
operationalization = c(
"Organizational structure of collective actors (measure of centralization of wage bargaining) (CENT variable), Structure of work council representation (WC_struct variable, Rights of work councils (WC_rights variable",
"Government intervention in wage bargaining (Govint variable), Dominant level of wage bargaining (Level variable), routine involvement of unions and employers in government decisions (RI variable), social pact or collective agreement signed (Pactsign and AgrSign variables)",
"Coordination of wage bargaining (measure of bindingness of norms regarding maximum or minimum wage rates or wage increases) (Coord variable), Mandatory extension of collective agreements (Ext variable)"
)
) %>%
rename("Aspect" = aspect,
"Description" = description,
"Operationalization" = operationalization)%>%
knitr::kable(longtable = F,
booktabs = T,
caption = "Corporatism Index",
) %>%
column_spec(1, width = "6em", bold = T)%>%
column_spec(2, width = "7.5em")%>%
column_spec(3, width = "22em")%>%
row_spec(0,bold=TRUE)
| Aspect | Description | Operationalization |
|---|---|---|
| Structure | Degree of hierarchical centralization | Organizational structure of collective actors (measure of centralization of wage bargaining) (CENT variable), Structure of work council representation (WC_struct variable, Rights of work councils (WC_rights variable |
| Function | Degree of concertation with the state | Government intervention in wage bargaining (Govint variable), Dominant level of wage bargaining (Level variable), routine involvement of unions and employers in government decisions (RI variable), social pact or collective agreement signed (Pactsign and AgrSign variables) |
| Scope | Degree to which agreements encompass broader segments of society | Coordination of wage bargaining (measure of bindingness of norms regarding maximum or minimum wage rates or wage increases) (Coord variable), Mandatory extension of collective agreements (Ext variable) |
corporatism_index_recreation <- corporatism_index%>%
filter(year<2011)%>%
group_by(country)%>%
mutate(mean_index_recreation = mean(corp_index, na.rm = T))%>%
dplyr::select(country, year, corp_index, mean_index_recreation)
#create rolling mean to make more comparable
corporatism_index_recreation%<>%
arrange(country, year) %>%
mutate(corp_index_rollmean=rollapply(corp_index,5,mean,align='right',fill=NA))
#combine the two datasets: the original one loaded from visser and the one i created
index_cor <- right_join(corporatism_index_recreation, corporatism_index_original)%>%
pivot_longer(c(z_Corp_Jahn_sm_add, corp_index_rollmean))
index_cor%>%
filter(year>1980)%>%
ggplot(aes(year, value, color = name))+
geom_line()+
facet_wrap(~country)+
scale_x_continuous(breaks = c(1980, 1995, 2010))+
labs(x = "",
y = "",
color = "")+
scale_color_brewer( labels = c("Reconstructed Index", "Original Index"), palette = "Set1")+
theme_minimal()+
theme(legend.position = "bottom", panel.spacing.x = unit(5, "mm"))# to ensure that x-axis labels don't overlap
Figure 4.1: Comparing Jahn’s original to my own corporatism index
Missing data are a perennial problem of quantitative comparative political research. Most statistical methods assume the absence of missing values, that is, they require rectangular datasets. However, ‘rectangularizing’ a dataset by dropping all partially observed observations from the analysis can lead to biases, inefficient use of the existing information, and incorrect uncertainty estimates. For this reason, multiple imputation techniques are widely considered the royal road to handling missing data. The idea is to extract as much information as possible from the available data, to use that information to construct multiple, complete datasets where the observed values are the same and the imputations vary depending on the estimated uncertainty in predicting each missing value, and to then combine the results [@Honaker.2010, p.561].
I used Amelia, a multiple imputation technique and package specifically designed to handle missing data in time-series-cross-sectional datasets by allowing to impose smoothness over time-series variables (by including q-order polynomials), shifts over cross sectional variables, and interactions between the two where the time-trends can vary across cross-sectional units [@Honaker.2010; @Honaker.2019]. Since imputations are predictive and not causal, I included all available variables as well as their lags and leads. I also included a degree one polynomial indicating linear time effects. Because some variables are strongly correlated (the investment index and its subcategories), I applied a ridge prior of 1 percent of the rows of the data to shrink the covariances and aid the stability of the EM algorithm, basically trading an increase in bias for an increase in efficiency [@Honaker.2019, p. 23].
Overall, only around 10% of all used cells were missing. Data rarely had to be imputed over more than a few years and in these cases imputation uncertainty is reflected in the standard errors of the regression models.
There are a number of tools to evaluate the imputations. One is to visually inspect the mean and variances of the imputations across time and over countries and compare them to the observed values. Figure 4.2 does just that for a number of countries and for R&D investment. Figure 4.3 does the same for deindustrialization (for the sake of transparency, I plotted countries with rather many missing values next to those with no missing values to illustrate the plausibility of the imputations). What we can gather from this (as well as from doing the same for other variables) is that imputations are quite sensible. The range of imputed values falls well within what we would find plausible. Moreover, the imputation take into account uncertainty when imputation takes place over several missing values, which is reflected in the models themselves.
tscsPlot(amelia.out, cs = c("Australia", "Italy", "Netherlands", "Poland", "Sweden", "United States"), var = "rd_gdp", xlim = c(1981, 2018))
Figure 4.2: TSCS Plot for R&D Investment. The black points represent observed values, the red represent the mean of the imputations, the red lines represent 95% confidence bands of the imputation distribution
tscsPlot(amelia.out, cs = c("Austria", "Germany", "France", "United States", "Denmark", "Portugal"), var = "deindustrialization", xlim = c(1981, 2018))
Figure 4.3: TSCS Plot for Deindustrialization. The black points represent observed values, the red represent the mean of the imputations, the red lines represent 95% confidence bands of the imputation distribution
Another thing we can do is to overimpute, that is, to “sequentially treat each of the observed values as if they had actually been missing” [@Honaker.2019, p. 31]. We can then multiply impute these values and thus construct a confidence interval of what the imputed values would have been had the actually observed data been missing. This allows us to evaluate whether the observed data “fall within the region where it would have been imputed had it been missing” [@Honaker.2019, p. 31]. Figure 4.4 shows the results for the investment index, Figure 4.5 does the same for the corporatism index. For those as well as for the other variables, the vast majority of confidence intervals fall on the \(x = y\) line, and for all variables most of them do. This gives us confidence in the predictive validity of the imputation model [@Honaker.2019, p. 31].
overimpute(amelia.out, var = "rd_gdp", main = "Observed versus R&D Investments")
Figure 4.4: Overimputation Diagnostic Graph. If all imputed values fall on the x = y line, the imputation model would be a perfect predictor of the true value. If most confidence intervals (>90%) fall on this line, this gives us confidence in the imputation model. The colors of the line represent the fraction of missing observations in the pattern of missingness for that observation
overimpute(amelia.out, var = "corp_index", main = "Observed versus Imputed Values for Corporatism Index")
Figure 4.5: Overimputation Diagnostic Graph. If all imputed values fall on the x = y line, the imputation model would be a perfect predictor of the true value. If most confidence intervals (>90%) fall on this line, this gives us confidence in the imputation model. The colors of the line represent the fraction of missing observations in the pattern of missingness for that observation
A final way to evaluate the imputations is to compare the distribution of imputed values to the distribution of observed values. Figure 4.6 and Figure 4.7 are examples of such density plots, assuring us at least that the most imputations fall within the known bounds (the density distributions can also ‘correctly’ differ if there is a systematic reason why values for certain observations are missing). For the corporatism index, the imputed values a somewhat more centered than the observed ones, which would is less problematic as it decreases variance in a conservative manner and without a directional bias.
compare.density(amelia.out, var = "rd_gdp", main = "Observed and Imputed Values for R&D Investments")
Figure 4.6: Density Plot. The distribution of mean imputations is shown in red, the distribution of observed values is shown in blue
compare.density(amelia.out, var = "corp_index", main = "Observed and Imputed Values for Corporatism Index")
Figure 4.7: Density Plot. The distribution of mean imputations is shown in red, the distribution of observed values is shown in blue
There are a few model assumptions that require discussion. First, in fixed-effects regressions of time-series-cross-sectional data, heteroskedasticity (unequal error variance across countries) and contemporaneous error correlation (due to common shocks, etc.) are often a problem as they bias estimates [@Beck.1995]. However, because they already partition the error into within- and between-country error components, this should be less of a problem for within-between models. @Bartels.2015 shows that this is indeed the case and the estimates from within-between models are quite similar to those from fixed-effects models with panel-corrected standard errors.
Second, even though mixed models assume that higher-level entities are drawn from an Normal distribution, @Beck.2007a show that they handle even highly non-normal distributions very well.
Third, the within-between model thus offers a substantive solution to a central objection to random-effects model, namely that they assume that lower-level (here occasion-level) covariates are uncorrelated with the random effects term such that \(cov(x_{tgc}, u_{0gc}) = 0\) [@Bartels.2015; @Bell.2015]. Not only do simulations show that “even in the presence of rather extreme violations of this assumption, the random-effects estimator can still be preferable to (or at least no worse than) the fixed-effects estimator” [@Clark.2015, p. 407]. It also the case that the within-between specification prevents biased lower-level coefficients due to omitted variables at the higher level. This is because “there can be no correlation between level 1 variables included in the model and the level 2 random effects – such biases are absorbed into the between effect” [@Bell.2019, p. 1059]. This is also why the Hausmann test, a positive result of which is commonly taken as a reason to prefer a fixed- over a random-effect specification, is insufficient to decide between the two [@Clark.2015, p. 403]. In fact, “a negative result in a Hausmann test tells us only that the between effect is not significantly biasing an estimate of the within effect”; the explicit modeling of the difference between those effects thus “makes the Hausmann test, as a test of FE against RE, redundant” [@Bell.2015, p. 138]. There can of course still be bias in the between effects and the effects of higher-level variables due to unmeasured higher-level characteristics. But this is a problem mainly if we want to know the direct causal effect of a higher-level variable. If we instead interpret these coefficients as “proxies for a range of unmeasured social processes” [@Bell.2019, p. 1059] the coefficient estimates can still be valuable provided their interpretation is theoretically sound.
Fourth, although @Stegmueller.2013 has influentially argued that maximum-likelihood estimators produce severely overconfident estimates when there are fewer than 15-20 higher-level entities (and has recommended using a Bayesian approach instead), recent follow-up work has identified flaws in Stegmueller’s simulation study [@Elff.2020]. The authors find that maximum-likelihood estimators generally provide unbiased coefficient estimates in linear multilevel models even with few higher-level entities. Moreover, restricted maximum-likelihood estimators, together with using a heavier-tailed t distribution with limited degrees of freedom instead of the standard normal distribution, provide much-improved estimators of variance parameters (over standard maximum-likelihood estimates), especially for very small cluster sizes (5-10 higher level entities).
Finally, if variables have a unit-root, coefficient estimates can be spurious. While an Augmented Dickey-Fuller test for the country-averaged investment index rejects the null hypothesis of a unit root (p-value = 0.38), visual inspection reveals an upward trend in the data. I included cubic splines to account for time trends [cf. @Garritzmann.2020b] and I also run additional robustness checks that model time differently, including with a third-order polynomial of time [as suggested by Kelvyn Jones here]. But I cannot fully exclude the possibility of non-stationarity – not least because it is unclear how well standard tests for stationarity perform for time-series-cross sectional data with relatively low numbers of annual observations. Transforming variables to their first differences could be a technical fix to eliminate potential non-stationarity. However, this would come at a theoretical cost as we lose the ability to estimate meaningful between-effects (which are all about levels, not change). There are also theoretical considerations following from the structure of time-series-cross-sectional data [@Beck.2011a, pp. 342–44]. In particular, stationarity is constrained because of natural bounds. For example, the share of conservative parties in government is constrained between 0-100, and spending variables as a share of GDP can realistically only go so high, which also bounds their variances. This also implies that political economy data that show an increasing trend cannot continue this trend indefinitely. That is, data that are non-stationary in a certain time-period may not be so be over a longer (or shorter) period. Given all this, I’m reasonable confident to have correctly modeled the data.
As all models, mixed effects models rely on a number of assumptions that need to be met or approximated to get unbiased estimates. Here, I present a number of such model diagnostics - all values being averaged across the multiply imputed datasets.
To detect multicollinearity, I calculated the variance inflation factor (VIF) for the different variables in the imputed models to estimate how much the variance of a regression coefficient is inflated due to multicollinearity in the respective models. Table 4.3 shows the averaged values for the different variables in the respective models. It shows that the VIF are very low (around 1) to moderate (for the deindustrialization and share of elderly people variables). None of the VIFs is very high, which gives us confidence that multicollinearity does not bias the results (common rules of thumb argue for excluding variables with VIF of 4 or higher, or even 10 or higher). However, including GDP per capita as a control leads to relatively high VIFs for this variable as well as the deindustrialization variable (VIFs of between 4 and 6). I therefore excluded it as a control variable. Importantly, as the next section shows, including GDP per capita does not change any of the main findings.
models_imputations %>%
dplyr::select(model_3)%>%
mutate(vif = model_3 %>% map( ~ as.data.frame(car::vif(.)) %>%
rownames_to_column(var = "term")))%>%
unnest(vif)%>%
group_by(term)%>%
summarise(vif = mean(GVIF))%>%
arrange(desc(vif))%>%
rename("Variable" = "term", "Variance Inflation Factor" = "vif")%>%
mutate(Variable = recode(Variable,
"dii_score_gdp_lag_normal" = "Lagged Dependent Variable",
"gov_seat_share_normal" = "Social Democratic Party",
"Investment Emphasis" = "Weighted Emphasis Investment",
"corp_index_normal" = "Corporatism",
"corp_index_within_normal" = "Corporatism (within)",
"corp_index_between_normal" = "Corporatism (between)",
"h_polcon5_normal" = "Institutional Contraints",
"deindustrialization_within_normal" = "Deindustrialization (within)",
"deindustrialization_between_normal" = "Deindustrialization (between)",
"capb_normal" = "Adjusted Deficit",
"eu" = "EU Member",
"trade_open_normal" = "Trade Openness",
"trade_open_within_normal" = "Trade Openness (within)",
"trade_open_between_normal" = "Trade Openness (between)",
"unemployment_normal" = "Unemployment",
"small_state_binary_2" = "Small State",
"share_elderly_normal" = "Share 65+",
"hard_debt_rule" = "Debt Rule",
"splines::bs(Year, degree = 3)" = "Year",
"deficit_normal" = "Deficit",
"deindustrialization_within_normal:corp_index_between_normal" = "Corporatism (between)*Deindustrialization (within)"
))%>%
filter(Variable != "Year")%>%
kable(booktabs = T,
longtable = T,
caption = "Variance Inflation Factors")%>%
kable_styling()
| Variable | Variance Inflation Factor |
|---|---|
| Deindustrialization (within) | 1.678966 |
| Trade Openness | 1.410212 |
| EU Member | 1.234968 |
| Debt Rule | 1.166376 |
| Unemployment | 1.147798 |
| Institutional Contraints | 1.099673 |
| Adjusted Deficit | 1.095275 |
| Social Democratic Party | 1.060313 |
| Corporatism (within) | 1.044121 |
| Corporatism (between) | 1.029282 |
| Corporatism (between)*Deindustrialization (within) | 1.025481 |
| Small State | 1.022393 |
| Deindustrialization (between) | 1.011625 |
Figure 4.8 and Figure 4.9 show that the residuals - again averaged across models - are homoscedastic and approximately normally distributed.
resid <- models_imputations %>%
dplyr::select(model_3) %>%
mutate(resid = model_3 %>% map( ~ as.data.frame(resid(.)) %>%
rownames_to_column()))%>%
unnest(resid)%>%
group_by(rowname)%>%
summarise(resid = mean(`resid(.)`))
fit_val <- models_imputations %>%
dplyr::select(model_3) %>%
mutate(fit_val = model_3 %>% map( ~ as.data.frame(fitted.values(.)) %>%
rownames_to_column()))%>%
unnest(fit_val)%>%
group_by(rowname)%>%
summarise(fit_val = mean(`fitted.values(.)`))
resid_fitt <- resid%>%
left_join(fit_val)
resid_fitt%>%
ggplot()+
geom_jitter(aes(x=fit_val, y=resid), color = "dodgerblue", shape = 1, size = 2)+
geom_hline(yintercept = 0, alpha = 0.8)+
labs(x = "Fitted Values",
y = "Residuals")+
theme_classic()
Figure 4.8: Residuals versus fitted values
resid_fitt%>%
ggplot()+
geom_histogram(aes(x = resid), bins = 50, color = "black", fill = "dodgerblue")+
labs(x = "Residuals",
y = "Frequency")+
theme_classic()
Figure 4.9: Histogramm of Residuals
I ran a number of alternative model specifications to ensure the robustness of my main findings. The first model in Table ?? is equivalent to Model 3 in the main paper but uses a direct measure of partisan preferences instead of the share of social democratic parties. The results remain the same: at least in recent years and decades, the partisan composition of government and the positions of governing parties had no significant influence on investment spending. The second model includes a GDP per capita variable as an additional control variable, which was excluded from the main model because of potential multicollinearity issues. As we can see, however, including it does not substantially alter any of the main results, although it is interesting that richer countries seem invest less rather than more in knowledge-based capital - all else being equal. The third model includes a lagged dependent variable. While this comes with many issues of its own, some argue that this might help avoid anti-conservative estimates of the error terms due to autocorrelation while producing good estimates even in the presence of minor residual autocorrelation [@Keele.2006; cf. @Beck.2011a]. Naturally, including the LDV absorbs a lot of variance and reduces effect sizes and pushes the interaction effect of corporatism and deindustrialization to the 0.1 significance level. However, even this does not affect the main findings of the paper, in particular the one on the effect of corporatism. Model 4 uses a version of the investment index that only uses education data from UNESCO - instead of the version where education data are combined with COFOG data from the OECD (see Appendix 4.1.3). Again, the main results hold.
The first model in Table ?? includes a measure of foreign direct investment (FDI) as it is plausible to assume that countries invest in knowledge-based capital to remain attractive to foreign investors. This is measured as inflowing FDI as a share of GDP. However, I do not find any effect in either direction. The second model changes the corporatism variable by only including its functional elements, i.e. those that pertain to the role social partners play vis-à-vis the state, such as the involvement of unions and employers in government decisions. We find that this more parsimonious operationalization yields very similar results, crucially corroborating the main argument. Interestingly, if we include employment instead of unemployment levels, we find a significant negative effect of employment on investments. Like the effect of unemployment, this is purely a within effect. This suggests that while countries increase investments in especially individually-held knowledge-based capital when unemployment increases, they may decrease spending as employment levels get higher controlling for everything else, especially fiscal capacity. One explanation is that as countries increase their employment levels, there is less pressure on governments to further invest in knowledge-based capital while countries with increasing unemployment levels are pressured to step up their investments in order to ensure the viability of their tax base and contribution systems. This, however, should be further explored in future studies. Finally, including debt levels instead of deficit does not change any of the main results either, although debt levels instead of deficits remain not significant.
The first model in table ?? shows the results of using an alternative measure of institutional constraints (also from @Henisz.2002), which does not have an effect on investments either. The second model shows that there is also no effect if we separate the within and between effects of the (original) institutional constraints variable. The between effect is - as we would expect - positive but not significant. Table ?? also shows results when using alternative specifications of the small state variable (third and fourth model). They show that the strong and significant positive effect is limited to countries with fewer than 6 million inhabitants. There is no such effect for countries with less than 10 million inhabitants (third model) or for those with between 6 and 20 million inhabitants (in the fourth which takes large states as a baseline category). The last model Table ?? includes an additional control variable that measures the share of the population over 65, which seems to have a positive effect on investment but does not influence any of the main results.
Finally, table ??, shows the results when using only selected categories of R&D investment or only the subcomponents of the knowledge investment index as dependent variables. Again the results are robust even if we only use the subcomponents, although there are some small but relevant differences, especially with regard to the within effect of deindustrialization and its interaction with corporatism. Moreover, R&D (and ALMP) investments are not affect by the smallness of a state, but rather by fiscal capacity, including the existence of a debt rule. This points to some heterogeneity in the determinants of investment spending for different categories of (knowledge) investments, which future research should explore further.
output <- texreg::htmlreg(
c(texreg_melded[[5]], texreg_melded[[6]], texreg_melded[[7]], texreg_melded[[8]]),
custom.model.names = c("Direct Measure", "With GDP/Capita", "With Lagged DV", "Alterantive DV"),
use.packages = F,
single.row = F,
label = "tab:robmodels1",
stars = c(0.001, 0.01, 0.05, 0.1),
symbol = "\\circ",
booktabs = T,
scalebox = 0.75,
caption = "Mixed-Effect Models",
bold = 0.05,
custom.coef.map = list(
"(Intercept)" = NA,
"dii_score_gdp_lag_normal" = "Lagged Dependent Variable",
"dii_score2_gdp_lag_normal" = "Lagged Dependent Variable",
"gov_seat_share_normal" = "Social Democratic Party",
"investment_weighted_normal" = "Weighted Emphasis Investment",
"corp_index_normal" = "Corporatism",
"corp_index_within_normal" = "Corporatism (within)",
"corp_index_between_normal" = "Corporatism (between)",
"h_polcon5_normal" = "Institutional Contraints",
"capb_normal" = "Adjusted Deficit",
"capb_within_normal" = "Adjusted Deficit (within)",
"capb_between_normal" = "Adjusted Deficit (between)",
"deindustrialization_normal" = "Deindustrialization",
"deindustrialization_within_normal" = "Deindustrialization (within)",
"deindustrialization_between_normal" = "Deindustrialization (between)",
"ov_mean_normal" = "Sentiment",
"ov_mean_between_normal" = "Sentiment (between)",
"ov_mean_within_normal" = "Sentiment (within)",
"ratio_normal" = "State Identity",
"trade_open_normal" = "Trade Openness",
"trade_open_within_normal" = "Trade Openness (within)",
"trade_open_between_normal" = "Trade Openness (between)",
"unemployment_normal" = "Unemployment",
"share_elderly_normal" = "Share 65+",
"small_state_binary_2" = "Small State",
"hard_debt_rule" = "Debt Rule",
"eu" = "EU Member",
"deindustrialization_within_normal:corp_index_between_normal" = "Corporatism*Deindustrialization",
"gdp_capita_normal" = "GDP/Capita"),
custom.gof.names = c("AIC",
"N (Total)",
"Variance Government Level",
"Variance Country Level",
"Covariance Random Slope/Intercept",
"Variance Random Slope",
"Residual Variance",
"N (Government)",
"N (Country)"),
reorder.gof = c(1, 8, 9, 2, 3, 4, 7, 6, 5)) #to add a control line: custom.gof.rows = list("Other Controls" = c("NO", "YES", "YES"))
output <- gsub("\\begin{center}", "",output, fixed = TRUE)
gsub("\\end{center}", "", output, fixed = TRUE)
| Direct Measure | With GDP/Capita | With Lagged DV | Alterantive DV | |
|---|---|---|---|---|
| (Intercept) | -0.88*** | -1.51*** | -0.30*** | -0.55* |
| (0.20) | (0.22) | (0.08) | (0.22) | |
| Lagged Dependent Variable | 0.77*** | |||
| (0.03) | ||||
| Social Democratic Party | -0.01 | 0.01 | -0.02 | |
| (0.02) | (0.01) | (0.02) | ||
| Weighted Emphasis Investment | -0.00 | |||
| (0.02) | ||||
| Corporatism (within) | 0.01 | 0.01 | 0.01 | 0.01 |
| (0.01) | (0.01) | (0.01) | (0.01) | |
| Corporatism (between) | 0.35** | 0.46*** | 0.09* | 0.33* |
| (0.13) | (0.14) | (0.04) | (0.13) | |
| Institutional Contraints | -0.01 | -0.01 | 0.02 | 0.02 |
| (0.03) | (0.03) | (0.02) | (0.04) | |
| Adjusted Deficit | -0.10*** | -0.10*** | -0.06*** | -0.09*** |
| (0.02) | (0.02) | (0.01) | (0.02) | |
| Deindustrialization (within) | 0.14* | 0.14* | 0.03 | 0.08 |
| (0.06) | (0.07) | (0.03) | (0.06) | |
| Deindustrialization (between) | 0.50*** | 0.73*** | 0.12*** | 0.53*** |
| (0.12) | (0.13) | (0.04) | (0.12) | |
| Trade Openness | -0.23*** | -0.15** | -0.09** | -0.16* |
| (0.05) | (0.05) | (0.03) | (0.07) | |
| Unemployment | 0.12*** | 0.07*** | 0.01 | 0.16*** |
| (0.02) | (0.02) | (0.01) | (0.02) | |
| Small State | 0.81*** | 0.71** | 0.24*** | 0.62** |
| (0.22) | (0.22) | (0.07) | (0.24) | |
| Debt Rule | -0.02 | -0.01 | -0.00 | -0.06 |
| (0.04) | (0.04) | (0.03) | (0.05) | |
| EU Member | 0.09 | 0.06 | 0.04 | 0.05 |
| (0.06) | (0.06) | (0.03) | (0.08) | |
| Corporatism*Deindustrialization | 0.11* | 0.15** | 0.03 | 0.09 |
| (0.05) | (0.05) | (0.02) | (0.05) | |
| GDP/Capita | -0.52*** | |||
| (0.07) | ||||
| AIC | 482.84 | 434.17 | 22.53 | 734.64 |
| N (Government) | 441 | 441 | 441 | 441 |
| N (Country) | 32 | 32 | 32 | 32 |
| N (Total) | 1167 | 1167 | 1166 | 1167 |
| Variance Government Level | 0.09 | 0.09 | 0.00 | 0.09 |
| Variance Country Level | 0.48 | 0.52 | 0.03 | 0.51 |
| Residual Variance | 0.03 | 0.03 | 0.04 | 0.05 |
| Variance Random Slope | 0.06 | 0.08 | 0.00 | 0.06 |
| Covariance Random Slope/Intercept | 0.02 | 0.05 | 0.00 | 0.03 |
| p < 0.001; p < 0.01; p < 0.05; p < 0.1 | ||||
output <- texreg::htmlreg(
c(texreg_melded[[9]], texreg_melded[[10]], texreg_melded[[11]], texreg_melded[[15]]),
custom.model.names = c("With FDI", "Corporatism (functional)", "Employment", "Debt Instead of Deficit"),
use.packages = F,
single.row = F,
label = "tab:robmodels2",
stars = c(0.001, 0.01, 0.05, 0.1),
symbol = "\\circ",
booktabs = T,
scalebox = 0.8,
caption = "Mixed-Effect Models",
bold = 0.05,
custom.coef.map = list(
"(Intercept)" = NA,
"dii_score_gdp_lag_normal" = "Lagged Dependent Variable",
"gov_seat_share_normal" = "Social Democratic Party",
"Investment Emphasis" = "Weighted Emphasis Investment",
"corp_index_normal" = "Corporatism",
"corp_index_within_normal" = "Corporatism (within)",
"corp_index_between_normal" = "Corporatism (between)",
"corp_index_fun_within_normal" = "Corporatism functional (within)",
"corp_index_fun_between_normal" = "Corporatism functional (between)",
"h_polcon5_normal" = "Institutional Contraints",
"capb_normal" = "Adjusted Deficit",
"debt_normal" = "Debt Level",
"fdi_inflows_normal" = "FDI Inflows",
"capb_within_normal" = "Adjusted Deficit (within)",
"capb_between_normal" = "Adjusted Deficit (between)",
"deindustrialization_normal" = "Deindustrialization",
"deindustrialization_within_normal" = "Deindustrialization (within)",
"deindustrialization_between_normal" = "Deindustrialization (between)",
"ov_mean_normal" = "Sentiment",
"ov_mean_between_normal" = "Sentiment (between)",
"ov_mean_within_normal" = "Sentiment (within)",
"ratio_normal" = "State Identity",
"trade_open_normal" = "Trade Openness",
"trade_open_within_normal" = "Trade Openness (within)",
"trade_open_between_normal" = "Trade Openness (between)",
"unemployment_normal" = "Unemployment",
"employment_normal" = "Employment",
"employment_within_normal" = "Employment (within)",
"employment_between_normal" = "Employment (between)",
"share_elderly_normal" = "Share 65+",
"small_state_binary_2" = "Small State",
"hard_debt_rule" = "Debt Rule",
"eu" = "EU Member",
"deindustrialization_within_normal:corp_index_between_normal" = "Corporatism*Deindustrialization",
"deindustrialization_within_normal:corp_index_fun_between_normal" = "Corporatism(functional)*Deindustrialization",
"gdp_capita_normal" = "GDP/Capita",
"employment" = "Employment Levels"),
custom.gof.names = c("AIC",
"N (Total)",
"Variance Government Level",
"Variance Country Level",
"Covariance Random Slope/Intercept",
"Variance Random Slope",
"Residual Variance",
"N (Government)",
"N (Country)"),
reorder.gof = c(1, 8, 9, 2, 3, 4, 7, 6, 5)) #to add a control line: custom.gof.rows = list("Other Controls" = c("NO", "YES", "YES"))
output <- gsub("\\begin{center}", "",output, fixed = TRUE)
gsub("\\end{center}", "", output, fixed = TRUE)
| With FDI | Corporatism (functional) | Employment | Debt Instead of Deficit | |
|---|---|---|---|---|
| (Intercept) | -0.87*** | -0.85*** | -0.85*** | -0.79*** |
| (0.20) | (0.21) | (0.21) | (0.20) | |
| Social Democratic Party | 0.00 | -0.00 | -0.00 | 0.00 |
| (0.01) | (0.01) | (0.01) | (0.02) | |
| Corporatism (within) | 0.01 | 0.01 | 0.01 | |
| (0.01) | (0.01) | (0.01) | ||
| Corporatism (between) | 0.35** | 0.33* | 0.35** | |
| (0.13) | (0.13) | (0.13) | ||
| Corporatism functional (within) | 0.00 | |||
| (0.01) | ||||
| Corporatism functional (between) | 0.28* | |||
| (0.14) | ||||
| Institutional Contraints | -0.01 | -0.01 | -0.01 | -0.03 |
| (0.03) | (0.03) | (0.03) | (0.02) | |
| Adjusted Deficit | -0.10*** | -0.10*** | -0.09*** | |
| (0.02) | (0.02) | (0.02) | ||
| Debt Level | 0.01 | |||
| (0.03) | ||||
| FDI Inflows | -0.01 | |||
| (0.01) | ||||
| Deindustrialization (within) | 0.14* | 0.14* | 0.19** | 0.14* |
| (0.06) | (0.06) | (0.06) | (0.06) | |
| Deindustrialization (between) | 0.50*** | 0.51*** | 0.51*** | 0.50*** |
| (0.12) | (0.13) | (0.12) | (0.12) | |
| Trade Openness | -0.23*** | -0.22*** | -0.24*** | -0.27*** |
| (0.05) | (0.05) | (0.05) | (0.05) | |
| Unemployment | 0.12*** | 0.12*** | 0.11*** | |
| (0.02) | (0.02) | (0.02) | ||
| Employment | -0.11** | |||
| (0.04) | ||||
| Small State | 0.82*** | 0.79*** | 0.82*** | 0.87*** |
| (0.22) | (0.23) | (0.23) | (0.22) | |
| Debt Rule | -0.02 | -0.02 | -0.02 | -0.02 |
| (0.03) | (0.04) | (0.04) | (0.04) | |
| EU Member | 0.09 | 0.09 | 0.07 | 0.09 |
| (0.06) | (0.06) | (0.06) | (0.06) | |
| Corporatism*Deindustrialization | 0.11* | 0.11* | 0.11* | |
| (0.05) | (0.05) | (0.05) | ||
| Corporatism(functional)*Deindustrialization | 0.11* | |||
| (0.05) | ||||
| AIC | 491.44 | 486.50 | 503.29 | 542.74 |
| N (Government) | 441 | 441 | 441 | 441 |
| N (Country) | 32 | 32 | 32 | 32 |
| N (Total) | 1167 | 1167 | 1167 | 1167 |
| Variance Government Level | 0.09 | 0.09 | 0.10 | 0.10 |
| Variance Country Level | 0.48 | 0.52 | 0.49 | 0.48 |
| Residual Variance | 0.03 | 0.03 | 0.03 | 0.03 |
| Variance Random Slope | 0.06 | 0.08 | 0.06 | 0.05 |
| Covariance Random Slope/Intercept | 0.02 | 0.05 | 0.02 | 0.01 |
| p < 0.001; p < 0.01; p < 0.05; p < 0.1 | ||||
output <- texreg::htmlreg(
c( texreg_melded[[13]], texreg_melded[[14]], texreg_melded[[18]], texreg_melded[[19]], texreg_melded[[23]]),
custom.model.names = c("Alt. Contraints", "Constraints W-B", "Alt. Small State 1", "Alt. Small State 2", "Includes Share Elderly"),
use.packages = F,
single.row = F,
label = "tab:robmodels3",
stars = c(0.001, 0.01, 0.05, 0.1),
symbol = "\\circ",
booktabs = T,
scalebox = 0.68,
caption = "Mixed-Effect Models",
bold = 0.05,
custom.coef.map = list(
"(Intercept)" = NA,
"dii_score_gdp_lag_normal" = "Lagged Dependent Variable",
"gov_seat_share_normal" = "Social Democratic Party",
"Investment Emphasis" = "Weighted Emphasis Investment",
"corp_index_normal" = "Corporatism",
"corp_index_within_normal" = "Corporatism (within)",
"corp_index_between_normal" = "Corporatism (between)",
"h_polcon5_normal" = "Institutional Contraints",
"h_polcon3_normal" = "Alternative Institutional Contraints",
"h_polcon5_between_normal" = "Institutional Contraints (between)",
"h_polcon5_within_normal" = "Institutional Contraints (within)",
"capb_normal" = "Adjusted Deficit",
"capb_within_normal" = "Adjusted Deficit (within)",
"capb_between_normal" = "Adjusted Deficit (between)",
"deindustrialization_normal" = "Deindustrialization",
"deindustrialization_within_normal" = "Deindustrialization (within)",
"deindustrialization_between_normal" = "Deindustrialization (between)",
"ov_mean_normal" = "Sentiment",
"ov_mean_between_normal" = "Sentiment (between)",
"ov_mean_within_normal" = "Sentiment (within)",
"ratio_normal" = "State Identity",
"trade_open_normal" = "Trade Openness",
"trade_open_within_normal" = "Trade Openness (within)",
"trade_open_between_normal" = "Trade Openness (between)",
"unemployment_normal" = "Unemployment",
"share_elderly_normal" = "Share 65+",
"small_state_binary_2" = "Small State",
"small_state_binary_1" = "Small State (under 10 Mil)",
"factor(small_state_three)0" = "Large State (larger than 20 Mil)",
"factor(small_state_three)1" = "Medium-sized state (between 6-20 Mil)",
"factor(small_state_three)2" = "Small State (under 6 Mil)",
"hard_debt_rule" = "Debt Rule",
"eu" = "EU Member",
"deindustrialization_within_normal:corp_index_between_normal" = "Corporatism*Deindustrialization",
"gdp_capita_normal" = "GDP/Capita"),
custom.gof.names = c("AIC",
"N (Total)",
"Variance Government Level",
"Variance Country Level",
"Covariance Random Slope/Intercept",
"Variance Random Slope",
"Residual Variance",
"N (Government)",
"N (Country)"),
reorder.gof = c(1, 8, 9, 2, 3, 4, 7, 6, 5)) #to add a control line: custom.gof.rows = list("Other Controls" = c("NO", "YES", "YES"))
output <- gsub("\\begin{center}", "",output, fixed = TRUE)
gsub("\\end{center}", "", output, fixed = TRUE)
| Alt. Contraints | Constraints W-B | Alt. Small State 1 | Alt. Small State 2 | Includes Share Elderly | |
|---|---|---|---|---|---|
| (Intercept) | -0.87*** | -0.85*** | -0.57** | -0.91** | -0.67** |
| (0.20) | (0.20) | (0.20) | (0.31) | (0.21) | |
| Social Democratic Party | -0.00 | -0.00 | -0.00 | -0.00 | -0.00 |
| (0.01) | (0.01) | (0.01) | (0.01) | (0.01) | |
| Corporatism (within) | 0.01 | 0.01 | 0.01 | 0.01 | 0.01 |
| (0.01) | (0.01) | (0.01) | (0.01) | (0.01) | |
| Corporatism (between) | 0.35** | 0.38** | 0.38* | 0.34** | 0.30* |
| (0.13) | (0.13) | (0.15) | (0.13) | (0.13) | |
| Institutional Contraints | -0.01 | -0.01 | -0.01 | ||
| (0.03) | (0.03) | (0.03) | |||
| Alternative Institutional Contraints | 0.00 | ||||
| (0.02) | |||||
| Institutional Contraints (between) | 0.18 | ||||
| (0.12) | |||||
| Institutional Contraints (within) | -0.01 | ||||
| (0.01) | |||||
| Adjusted Deficit | -0.10*** | -0.10*** | -0.10*** | -0.10*** | -0.10*** |
| (0.02) | (0.02) | (0.02) | (0.02) | (0.02) | |
| Deindustrialization (within) | 0.14* | 0.14* | 0.13* | 0.14* | 0.15* |
| (0.06) | (0.06) | (0.06) | (0.06) | (0.06) | |
| Deindustrialization (between) | 0.50*** | 0.46*** | 0.50*** | 0.50*** | 0.51*** |
| (0.12) | (0.12) | (0.14) | (0.12) | (0.12) | |
| Trade Openness | -0.23*** | -0.23*** | -0.22*** | -0.23*** | -0.23*** |
| (0.05) | (0.05) | (0.05) | (0.05) | (0.05) | |
| Unemployment | 0.12*** | 0.12*** | 0.12*** | 0.12*** | 0.12*** |
| (0.02) | (0.02) | (0.02) | (0.02) | (0.02) | |
| Share 65+ | 0.18** | ||||
| (0.06) | |||||
| Small State | 0.81*** | 0.80*** | 0.82*** | ||
| (0.22) | (0.22) | (0.22) | |||
| Small State (under 10 Mil) | -0.03 | ||||
| (0.06) | |||||
| Large State (larger than 20 Mil) | |||||
| Medium-sized state (between 6-20 Mil) | 0.05 | ||||
| (0.27) | |||||
| Small State (under 6 Mil) | 0.87** | ||||
| (0.32) | |||||
| Debt Rule | -0.02 | -0.02 | -0.02 | -0.02 | -0.02 |
| (0.03) | (0.04) | (0.04) | (0.04) | (0.03) | |
| EU Member | 0.09 | 0.09 | 0.08 | 0.09 | 0.08 |
| (0.06) | (0.06) | (0.06) | (0.06) | (0.06) | |
| Corporatism*Deindustrialization | 0.11* | 0.11* | 0.12* | 0.11* | 0.11* |
| (0.05) | (0.05) | (0.05) | (0.05) | (0.05) | |
| AIC | 484.35 | 486.66 | 502.31 | 488.85 | 480.23 |
| N (Government) | 441 | 441 | 441 | 441 | 441 |
| N (Country) | 32 | 32 | 32 | 32 | 32 |
| N (Total) | 1167 | 1167 | 1167 | 1167 | 1167 |
| Variance Government Level | 0.09 | 0.09 | 0.10 | 0.09 | 0.09 |
| Variance Country Level | 0.48 | 0.45 | 0.66 | 0.48 | 0.50 |
| Residual Variance | 0.03 | 0.03 | 0.03 | 0.03 | 0.03 |
| Variance Random Slope | 0.06 | 0.06 | 0.06 | 0.06 | 0.06 |
| Covariance Random Slope/Intercept | 0.02 | 0.02 | 0.05 | 0.02 | 0.04 |
| p < 0.001; p < 0.01; p < 0.05; p < 0.1 | |||||
output <- texreg::htmlreg(
c(texreg_melded[[12]], texreg_melded[[20]], texreg_melded[[21]], texreg_melded[[22]]),
custom.model.names = c("Only Selected R\\&D", "R\\&D as DV", "Education as DV", "ALMP as DV"),
use.packages = F,
single.row = F,
label = "tab:robmodels4",
stars = c(0.001, 0.01, 0.05, 0.1),
symbol = "\\circ",
booktabs = T,
scalebox = 0.8,
caption = "Mixed-Effect Models",
bold = 0.05,
custom.coef.map = list(
"(Intercept)" = NA,
"rd_gdp_normal" = "R&D Expenditure",
"edu_exp3_gdp_normal" = "Education Expenditure",
"edu_exp3_gdp_lag_normal" = "Lagged Dependent Variable",
"rd_gdp_lag_normal" = "Lagged Dependent Variable",
"alp_gdp_lag_normal" = "Lagged Dependent Variable",
"dii_score_gdp_lag_normal" = "Lagged Dependent Variable",
"gov_seat_share_normal" = "Social Democratic Party",
"Investment Emphasis" = "Weighted Emphasis Investment",
"corp_index_normal" = "Corporatism",
"corp_index_within_normal" = "Corporatism (within)",
"corp_index_between_normal" = "Corporatism (between)",
"corp_index_fun_within_normal" = "Corporatism functional (within)",
"corp_index_fun_between_normal" = "Corporatism functional (between)",
"h_polcon5_normal" = "Institutional Contraints",
"h_polcon5_between_normal" = "Institutional Contraints (between)",
"h_polcon5_within_normal" = "Institutional Contraints (within)",
"capb_normal" = "Adjusted Deficit",
"debt_normal" = "Debt Level",
"capb_within_normal" = "Adjusted Deficit (within)",
"capb_between_normal" = "Adjusted Deficit (between)",
"deindustrialization_normal" = "Deindustrialization",
"deindustrialization_within_normal" = "Deindustrialization (within)",
"deindustrialization_between_normal" = "Deindustrialization (between)",
"ratio_normal" = "State Identity",
"trade_open_normal" = "Trade Openness",
"trade_open_within_normal" = "Trade Openness (within)",
"trade_open_between_normal" = "Trade Openness (between)",
"unemployment_normal" = "Unemployment",
"employment_normal" = "Employment",
"employment_within_normal" = "Employment (within)",
"employment_between_normal" = "Employment (between)",
"share_elderly_normal" = "Share 65+",
"small_state_binary_2" = "Small State",
"small_state_binary_1" = "Small State (under 10 Mil)",
"factor(small_state_three)0" = "Large State (larger than 20 Mil)",
"factor(small_state_three)1" = "Medium-sized state (between 6-20 Mil)",
"factor(small_state_three)2" = "Small State (under 6 Mil)",
"hard_debt_rule" = "Debt Rule",
"eu" = "EU Member",
"deindustrialization_within_normal:corp_index_between_normal" = "Corporatism*Deindustrialization",
"gdp_capita_normal" = "GDP/Capita",
"fdi_inflows" = "FDI Inflows",
"employment" = "Employment Levels"),
custom.gof.names = c("AIC",
"N (Total)",
"Variance Government Level",
"Variance Country Level",
"Covariance Random Slope/Intercept",
"Variance Random Slope",
"Residual Variance",
"N (Government)",
"N (Country)"),
reorder.gof = c(1, 8, 9, 2, 3, 4, 7, 6, 5)) #to add a control line: custom.gof.rows = list("Other Controls" = c("NO", "YES", "YES"))
output <- gsub("\\begin{center}", "",output, fixed = TRUE)
gsub("\\end{center}", "", output, fixed = TRUE)
| Only Selected R&D | R&D as DV | Education as DV | ALMP as DV | |
|---|---|---|---|---|
| (Intercept) | -0.87*** | -0.22 | -0.97*** | -0.29 |
| (0.20) | (0.21) | (0.20) | (0.27) | |
| Social Democratic Party | -0.00 | -0.01 | -0.00 | -0.00 |
| (0.01) | (0.02) | (0.02) | (0.02) | |
| Corporatism (within) | 0.01 | 0.00 | 0.00 | 0.02 |
| (0.01) | (0.01) | (0.01) | (0.01) | |
| Corporatism (between) | 0.35** | 0.27* | 0.25 | 0.45** |
| (0.13) | (0.12) | (0.13) | (0.14) | |
| Institutional Contraints | -0.01 | -0.06 | 0.00 | -0.01 |
| (0.03) | (0.04) | (0.03) | (0.03) | |
| Adjusted Deficit | -0.10*** | -0.07*** | -0.09*** | -0.07*** |
| (0.02) | (0.02) | (0.02) | (0.02) | |
| Deindustrialization (within) | 0.13* | 0.09 | 0.14* | 0.01 |
| (0.06) | (0.10) | (0.06) | (0.08) | |
| Deindustrialization (between) | 0.49*** | 0.40*** | 0.45*** | 0.19 |
| (0.12) | (0.11) | (0.12) | (0.13) | |
| Trade Openness | -0.22*** | -0.17* | -0.28*** | 0.14* |
| (0.05) | (0.07) | (0.05) | (0.07) | |
| Unemployment | 0.12*** | 0.01 | 0.10*** | 0.13*** |
| (0.02) | (0.02) | (0.02) | (0.03) | |
| Small State | 0.82*** | -0.16 | 0.98*** | 0.13 |
| (0.22) | (0.19) | (0.23) | (0.26) | |
| Debt Rule | -0.02 | -0.11* | 0.02 | -0.10 |
| (0.04) | (0.05) | (0.03) | (0.05) | |
| EU Member | 0.09 | 0.20* | 0.04 | 0.11 |
| (0.06) | (0.08) | (0.06) | (0.09) | |
| Corporatism*Deindustrialization | 0.11* | 0.15 | 0.10* | 0.01 |
| (0.05) | (0.08) | (0.05) | (0.05) | |
| AIC | 488.06 | 622.15 | 641.41 | 1001.31 |
| N (Government) | 441 | 441 | 441 | 441 |
| N (Country) | 32 | 32 | 32 | 32 |
| N (Total) | 1167 | 1167 | 1167 | 1167 |
| Variance Government Level | 0.09 | 0.08 | 0.11 | 0.13 |
| Variance Country Level | 0.49 | 0.43 | 0.50 | 0.57 |
| Residual Variance | 0.03 | 0.04 | 0.04 | 0.06 |
| Variance Random Slope | 0.05 | 0.19 | 0.06 | 0.06 |
| Covariance Random Slope/Intercept | 0.02 | -0.07 | 0.01 | -0.07 |
| p < 0.001; p < 0.01; p < 0.05; p < 0.1 | ||||
Figure 4.10 to Figure 4.12 show descritpive statistics for the individual subcomponents of the knowledge investment index.
full_data_imp <- bind_rows(unclass(amelia.out$imputations), .id = "m")%>%
filter((Year>1994 | Country %in% countries.selected & Year >1980) & Year <2019)%>%
group_by(m)%>%
mutate(edu_exp3_gdp = scale(edu_exp3_gdp))%>%
group_by(Country, Year)%>%
summarise(across(c(edu_exp3_gdp), mean))
full_data_imp %>%
filter(!is.na(edu_exp3_gdp)) %>%
mutate(Period = ifelse(
Year %in% (1980:1989),
"1980s",
ifelse(
Year %in% (1990:1999),
"1990s",
ifelse(Year %in% (2000:2009), "2000s", "2010s")
)
)) %>%
group_by(Period, Country) %>%
dplyr::summarise(edu_exp3_gdp = mean(edu_exp3_gdp)) %>%
ungroup() %>%
ggplot() +
geom_col(
aes(reorder(Country, -edu_exp3_gdp), edu_exp3_gdp),
data = . %>% filter(Period == "2010s"),
show.legend = F,
alpha = 0.4,
fill = "#377eb8"
) +
geom_point(
aes(
x = reorder(Country, -edu_exp3_gdp),
y = edu_exp3_gdp,
shape = Period,
color = Period
),
data = . %>% filter(Period %in% c("1980s", "1990s", "2000s", "2010s"))
) +
ggthemes::theme_tufte() +
scale_color_brewer(palette = "Set2")+
theme(
axis.text.x = element_text(angle = 45, hjust = 0.9),
text = element_text(size = 12),
legend.position = "top"
) +
labs(
x = "",
y = "Normalized Index for Education Investments",
color = "",
shape = ""
)
Figure 4.10: Normalized Investment in Education (1980s-2010s). Values are averaged across multiple imputations.
full_data_imp <- bind_rows(unclass(amelia.out$imputations), .id = "m")%>%
filter((Year>1994 | Country %in% countries.selected & Year >1980) & Year <2019)%>%
group_by(m)%>%
mutate(rd_gdp = scale(rd_gdp))%>%
group_by(Country, Year)%>%
summarise(across(c(rd_gdp), mean))
full_data_imp %>%
filter(!is.na(rd_gdp)) %>%
mutate(Period = ifelse(
Year %in% (1980:1989),
"1980s",
ifelse(
Year %in% (1990:1999),
"1990s",
ifelse(Year %in% (2000:2009), "2000s", "2010s")
)
)) %>%
group_by(Period, Country) %>%
dplyr::summarise(rd_gdp = mean(rd_gdp)) %>%
ungroup() %>%
ggplot() +
geom_col(
aes(reorder(Country, -rd_gdp), rd_gdp),
data = . %>% filter(Period == "2010s"),
show.legend = F,
alpha = 0.4,
fill = "#377eb8"
) +
geom_point(
aes(
x = reorder(Country, -rd_gdp),
y = rd_gdp,
shape = Period,
color = Period
),
data = . %>% filter(Period %in% c("1980s", "1990s", "2000s", "2010s"))
) +
ggthemes::theme_tufte() +
scale_color_brewer(palette = "Set2")+
theme(
axis.text.x = element_text(angle = 45, hjust = 0.9),
text = element_text(size = 12),
legend.position = "top"
) +
labs(
x = "",
y = "Normalized R&D Investments",
color = "",
shape = ""
)
Figure 4.11: Normalized Investment in Research and Development (1980s-2010s). Values are averaged across multiple imputations.
full_data_imp <- bind_rows(unclass(amelia.out$imputations), .id = "m")%>%
filter((Year>1994 | Country %in% countries.selected & Year >1980) & Year <2019)%>%
group_by(m)%>%
mutate(alp_gdp = scale(alp_gdp))%>%
group_by(Country, Year)%>%
summarise(across(c(alp_gdp), mean))
full_data_imp %>%
filter(!is.na(alp_gdp)) %>%
mutate(Period = ifelse(
Year %in% (1980:1989),
"1980s",
ifelse(
Year %in% (1990:1999),
"1990s",
ifelse(Year %in% (2000:2009), "2000s", "2010s")
)
)) %>%
group_by(Period, Country) %>%
dplyr::summarise(alp_gdp = mean(alp_gdp)) %>%
ungroup() %>%
ggplot() +
geom_col(
aes(reorder(Country, -alp_gdp), alp_gdp),
data = . %>% filter(Period == "2010s"),
show.legend = F,
alpha = 0.4,
fill = "#377eb8"
) +
geom_point(
aes(
x = reorder(Country, -alp_gdp),
y = alp_gdp,
shape = Period,
color = Period
),
data = . %>% filter(Period %in% c("1980s", "1990s", "2000s", "2010s"))
) +
ggthemes::theme_tufte() +
scale_color_brewer(palette = "Set2")+
theme(
axis.text.x = element_text(angle = 45, hjust = 0.9),
text = element_text(size = 12),
legend.position = "top"
) +
labs(
x = "",
y = "Normalized Active Labor Market Investments",
color = "",
shape = ""
)
Figure 4.12: Normalized Investment in Active Labor Market Policies (1980s-2010s). Values are averaged across multiple imputations.
Figure 4.13 to Figure 4.16 show the random slopes for deindustrialization for all countries. Figure 4.13 is based on the main model with the index for investments in knowledge-based capital, the other figures use data from models with the individual sub-components of this index as dependent variables.
random_slope_ave <- models_imputations %>%
dplyr::select(model_3) %>%
mutate(
ranslo = model_3 %>% map(
~ coef(.)$Country %>%
rownames_to_column(var = "Country") %>%
dplyr::select(Country, `(Intercept)`, deindustrialization_within_normal)
),
coeff = model_3 %>% map( ~ broom.mixed::tidy(., effects = c("fixed")))
) %>%
unnest(c(ranslo)) %>%
dplyr::select(-model_3) %>%
group_by(Country) %>%
summarise(
intercept = mean(`(Intercept)`),
deindustrialization = mean(deindustrialization_within_normal)
)%>%
ungroup()%>%
mutate(mean_slope = mean(deindustrialization)) %>%# this is just the average, equivalent to the coeffiecient estimate in the regression table
mutate(deindustrialization_slope = mean_slope + deindustrialization)
random_slope_ave%>%
ggplot()+
scale_y_continuous(limits=c(min(random_slope_ave$intercept), max(random_slope_ave$intercept+0.5)))+
geom_abline(aes(slope=deindustrialization_slope,intercept=intercept), size = 1.1, show.legend = F)+
facet_wrap(~Country, ncol = 8)+
theme_minimal()+
labs(title = "Full Index")
Figure 4.13: Random slopes for deindustrialization across countries. Based on the main model with the full dependent variable
random_slope_ave <- models_imputations_robust_4 %>%
dplyr::select(model_0003) %>%
mutate(
ranslo = model_0003 %>% map(
~ coef(.)$Country %>%
rownames_to_column(var = "Country") %>%
dplyr::select(Country, `(Intercept)`, deindustrialization_within_normal)
),
coeff = model_0003 %>% map( ~ broom.mixed::tidy(., effects = c("fixed")))
) %>%
unnest(c(ranslo)) %>%
dplyr::select(-model_0003) %>%
group_by(Country) %>%
summarise(
intercept = mean(`(Intercept)`),
deindustrialization = mean(deindustrialization_within_normal)
)%>%
ungroup()%>%
mutate(mean_slope = mean(deindustrialization)) %>%# this is just the average, equivalent to the coeffiecient estimate in the regression table
mutate(deindustrialization_slope = mean_slope + deindustrialization)
random_slope_ave%>%
ggplot()+
scale_y_continuous(limits=c(min(random_slope_ave$intercept), max(random_slope_ave$intercept+0.5)))+
geom_abline(aes(slope=deindustrialization_slope,intercept=intercept), size = 1.1, show.legend = F)+
facet_wrap(~Country, ncol = 8)+
theme_minimal()+
labs(title = "Education Investments")
Figure 4.14: Random slopes for deindustrialization across countries. Based on the main model with the full dependent variable
random_slope_ave <- models_imputations_robust_4 %>%
dplyr::select(model_0002) %>%
mutate(
ranslo = model_0002 %>% map(
~ coef(.)$Country %>%
rownames_to_column(var = "Country") %>%
dplyr::select(Country, `(Intercept)`, deindustrialization_within_normal)
),
coeff = model_0002 %>% map( ~ broom.mixed::tidy(., effects = c("fixed")))
) %>%
unnest(c(ranslo)) %>%
dplyr::select(-model_0002) %>%
group_by(Country) %>%
summarise(
intercept = mean(`(Intercept)`),
deindustrialization = mean(deindustrialization_within_normal)
)%>%
ungroup()%>%
mutate(mean_slope = mean(deindustrialization)) %>%# this is just the average, equivalent to the coeffiecient estimate in the regression table
mutate(deindustrialization_slope = mean_slope + deindustrialization)
random_slope_ave%>%
ggplot()+
scale_y_continuous(limits=c(min(random_slope_ave$intercept), max(random_slope_ave$intercept+0.5)))+
geom_abline(aes(slope=deindustrialization_slope,intercept=intercept), size = 1.1, show.legend = F)+
facet_wrap(~Country, ncol = 8)+
theme_minimal()+
labs(title = "R&D Investments")
Figure 4.15: Random slopes for deindustrialization across countries. Based on the main model with the full dependent variable
random_slope_ave <- models_imputations_robust_4 %>%
dplyr::select(model_0004) %>%
mutate(
ranslo = model_0004 %>% map(
~ coef(.)$Country %>%
rownames_to_column(var = "Country") %>%
dplyr::select(Country, `(Intercept)`, deindustrialization_within_normal)
),
coeff = model_0004 %>% map( ~ broom.mixed::tidy(., effects = c("fixed")))
) %>%
unnest(c(ranslo)) %>%
dplyr::select(-model_0004) %>%
group_by(Country) %>%
summarise(
intercept = mean(`(Intercept)`),
deindustrialization = mean(deindustrialization_within_normal)
)%>%
ungroup()%>%
mutate(mean_slope = mean(deindustrialization)) %>%# this is just the average, equivalent to the coeffiecient estimate in the regression table
mutate(deindustrialization_slope = mean_slope + deindustrialization)
random_slope_ave%>%
ggplot()+
scale_y_continuous(limits=c(min(random_slope_ave$intercept), max(random_slope_ave$intercept+0.5)))+
geom_abline(aes(slope=deindustrialization_slope,intercept=intercept), size = 1.1, show.legend = F)+
facet_wrap(~Country, ncol = 8)+
theme_minimal()+
labs(title = "Active Labor Market Investments")
Figure 4.16: Random slopes for deindustrialization across countries. Based on the main model with the full dependent variable
As discussed in the main paper, I had originally included an ideational explanation - in addition to the institutional one focusing on corporatism. I report the theory behind it, the data collected, and the analysis here for transparency reasons. While I found some weakly robust support that a more positive discourse on public debt, investments, and technological change might be associated with higher levels of investments in knowledge-based capital, I did not really trust these results. Descriptively plotting the sentiment of discourse, for example, did not provide intuitive results and could have been influenced by all kinds of things that don’t really capture state identities or debt cultures. Most importantly, however, garbage-in-garbage-out also and perhaps especially applies to text-as-data methods. And while my textual data were not garbage, they were very broad in what their coverage as the underlying search strings were too broad (they also had to be to get enough articles from each country for most years). Interpreting these results is indeed like ‘reading tea leaves’ [@Chang.2009], and feeling uncomfortable with ones data is a good sign not to use them. If I don’t trust them, how can I expect others to? There is, however, much potential, I still believe, in using text-as-data methods in similar designs. It is important however, to get good and relatively precise/narrow data first [@Nicholls.2020]
Often overlooked, Katzenstein’s argument is as much ideational as it is institutional.6 Here, I want to spin this argument further by more systematically theorizing the role of state identities and politico-economic cultures in mediating the causal chain between challenges and responses. Ideas matter because they help actors understand their interests and coalitional options in a world of uncertainty [@Blyth.2003a]. “To the extent that economic reality is uncertain - which in real life is nearly always - cognitive elements affect decision making” [@Gourevitch.1986, p. 63]. Political actors therefore “experiment into an open horizon, often driven by myopic conceptions of group interests, without anyone’s being able to predict today whether the path pursued will actually pay off in the longer run either for (1) the political actors and their constituencies advancing the reforms right now and/or for (2) the macroeconomic performance of the polities (or regions) in which these reforms prevail” [@Beramendi.2015, p. 60].
Investment policies are therefore a matter of ‘puzzling’ as much as of ‘powering’ [@Heclo.1974, p. 305], of “conflicting identities” as much as of “conflicting interests” [@Ziegler.1997, p. viii]. In this context, three questions are of particular importance. First, how is the state’s role in the economy understood? Second, how is the relationship between public debt or deficits and public investments construed? And third, is technological change seen a threat or an opportunity?
The first question shapes how public investments are viewed. Are they seen as essential and essentially positive in an economy in which markets regularly fail to provide important goods? Can governments legitimately act as investors or even entrepreneurs in their own right [@Mazzucato.2013]? Or are they seen as circumspect, as a symptom of an overreaching government incapable of making the right investments and discontent with limiting itself to administering markets? Mazzucato herself points to the central importance – and self-fulfilling nature – of the ‘discursive battles’ [@Mazzucato.2013, p. 3] around the proper understanding of government. In the US, for example, the discursive war on the very notion of government has not only produced a large-scale shift in how government is portrayed and talked about [@George.2013]; but it has also changed the confidence of, resources allocated to, and therefore effectiveness of the governments, which reinforces the discursive shift [@Hacker.2016].
The second question concerns how public debt and public deficits are viewed. Notions of public spending are profoundly intertwined with ”contending representations of state virtue” [@Dyson.2014, p. 263], which are themselves anchored in different ideologies of debt and economic cultures. Dyson distinguishes between two ideologies of debt, one that ”represents debt as shameful and potentially poisonous to virtue”, and one that values debt for its ”productive use” [@Dyson.2014, p. 268]. In combination with different economic cultures – the culture of elite magnificence, stability culture, consumer culture, social welfare culture, and welfare protection culture – these ideologies give rise to five different representations of state virtue: the dignified state, the ascetic state, the permissive state, the protective state, and the inclusive state [@Dyson.2014, pp. 269–83]. While the dignified state mostly belongs to the past, the latter four of these representations of state virtue offer a useful typology of modern state identities.
The third question relates to how technological change is viewed. Already in @Shonfield.1965 we find the notion that states’ reactions to technological and economic change depend on the “broad stance that a variety of national actors take to the economy, which in turn is based on culturally specific orientations deeply rooted in national history” [@Hall.1997, p. 185]. Dobbin and Ziegler echo this view when they point to the importance of historically rooted ‘industrial cultures’ [@Dobbin.1994] and the professional identities of administrative and technical elites [@Ziegler.1997] in assimilating novel problems to old ways of thinking, and therefore in shaping political responses to technological and economic change. The Swedish “policy style” [@Richardson.2013], for example, has been characterized as one of ‘principled pragmatism’ [@Heclo.1987] and applied, ‘secular rationalism’ [@Tomasson.1970, pp. 291–92]. Perhaps unsurprisingly, then, the Swedish reactions to recent technological upheavals has been relatively forward-looking, with an emphasis on manageable opportunities rather than threats [@Goodman.2017; @Marenco.2021].
How countries answer these three questions may thus depend on their identities and broader politico-economic culture. These ideational forces can be expected to influence how states think about digitalization, and consequently their role in shaping it. What Dyson said about public debt also applies to public investments and technological change: their “relationship [with] political rule remains pre-eminently a realm of subjective knowledge, conveyed by storytelling. Stories perform vital functions. They offer a compass in navigating radical economic and political uncertainty, as well as a sanctuary for retreat in the face of sheer complexity and passionate contestation. Stories also have a moral function. They distribute praise and blame [but] also serve as distorting prisms through which responsibility is evaded” [@Dyson.2014, p. 7]. These stories, as Vivien Schmidt has argued, are told in discourse, where visions of what is empirically and morally right are articulated and state identities and politico-economic cultures are reflected and shaped [@Schmidt.2008].
To test the ideational explanation, I collected 88136 newspaper articles for 30 countries. Newspaper articles were collected via factiva and Nexis Uni based on three sets of search strings.
a search string capturing discourse on technological change with references to technological change or technological progress
a search string capturing discourse on pubic debt and deficits with references to public debt or government debt or public deficit or government deficit
a search string capturing discourse on public investments references to public investment or government investment
These search strings had to appear at least once in an article within 2 words from each other (i.e. public-sector investment also counted). Translations of these search strings were verified by native speakers of the respective languages, who sometimes also added particular terms that are used in their country’s debates on these issues (e.g. Staatsschulden in Germany). All newspaper articles additionally had to contain at least one reference to the country in questions in order to make it less likely to collect articles that a solely about discourses in other countries (although this is not per se problematic as the way in which countries talk about, say, public deficits in another country also reflects the way they think about it themselves). If searches led to a particularly high number of articles (>10000 for one topic in one country), the search strings were made somewhat more restrictive, i.e. they had to contain at least two references to the above-mentioned terms.
For many countries, it was relatively easy to find articles from the countries’ main newspapers of the center-left and center-right, i.e. those that can in combination be considered representative of the national discourse. In those cases, it was also possible to collect articles going back to the 1990s and thus have continuous time series over 20 years or so. For some countries, however, it was more difficult to obtain such time series, and for a few others still it was also not possible to get access to the countries main newspapers but only to their English-language versions or to English-language newspapers that specifically cover the region. Thus, while for the United States we have continuous coverage from the New York Times, the Washington Post, and the Wall Street Journal since the 1980s, for Sweden the articles only reach back to the early 2000s. For Greece, I used the English edition of Kathimerini, one of the country’s main newspapers. For South Korea, I used some of the main English-speaking outlets such as the Korea Times. Often, newspaper were also complemented by press wires.
However, in all these cases, I manually made sure that only such newspapers or news agencies were included in the sample that reliably conveyed a good picture of the national discourse, i.e. those that were either translations from original-language articles or contained many quotes by national social actors and were thus trying to depict national political debates. Articles that mainly contained technical or economic information (such as the latest unemployment statistics) were excluded. Table 4.4 gives an overview of the newspaper included in the sample.
number_newspapers <- full_text_translated%>%
count(newspaper = newspaper,
country = country)%>%
arrange(country, desc(n))%>%
rename(Newspaper = newspaper,
"Number of Articles" = n)
number_newspapers%>%
dplyr::select(-country) %>%
knitr::kable(longtable = T, booktabs = T, caption = "Newspaper Corpus Overview")%>%
pack_rows(index = table(number_newspapers$country))%>%
kable_styling(latex_options = c("repeat_header"))
| Newspaper | Number of Articles |
|---|---|
| Australia | |
| Sydney Morning Herald | 2752 |
| The Daily Telegraph | 380 |
| Canberra Times | 14 |
| The Australian | 1 |
| Austria | |
| Austria Presse Agentur | 2175 |
| Die Presse | 1185 |
| Der Standard | 679 |
| Wirtschaftsblatt | 522 |
| Salzburger Nachrichten | 321 |
| Kurier | 74 |
| Belgium | |
| Agentschap Belga | 531 |
| SeeNews Belgium | 43 |
| Canada | |
| The Globe and Mail | 5149 |
| The Toronto Star | 2741 |
| National Post | 2148 |
| La Presse Canadienne | 309 |
| The Financial Post | 61 |
| Czech Republic | |
| Hospodárské Noviny | 1124 |
| Lidové Noviny | 251 |
| Denmark | |
| Politiken | 1135 |
| Ritzau General News Service | 395 |
| ErhvervsBladet | 178 |
| Webnews - Danish | 178 |
| Jyllands-Posten | 107 |
| Estonia | |
| Baltic Business Daily | 472 |
| The Baltic Times | 92 |
| Baltic Daily - Political/Social News | 76 |
| BNS Baltic Business News | 53 |
| Baltic Business Weekly | 39 |
| Baltic Business News | 23 |
| Finland | |
| Kauppalehti | 529 |
| Suomen Tietotoimisto | 192 |
| France | |
| Le Monde | 2811 |
| Le Figaro | 1614 |
| L’Humanité | 649 |
| La Croix | 308 |
| Libération | 36 |
| Germany | |
| Handelsblatt | 863 |
| Süddeutsche Zeitung | 739 |
| taz, die tageszeitung | 313 |
| Der Tagesspiegel | 237 |
| WirtschaftsWoche Online | 212 |
| Die ZEIT | 158 |
| Greece | |
| Kathimerini English Edition | 472 |
| Greek Reporter | 66 |
| Hungary | |
| Világgazdaság | 933 |
| Napi Gazdaság | 378 |
| Ireland | |
| The Irish Times | 3608 |
| Irish Independent | 1556 |
| Irish Examiner | 903 |
| Sunday Business Post | 646 |
| Evening Herald | 8 |
| Israel | |
| The Jerusalem Post | 620 |
| Globes | 548 |
| The Times of Israel | 63 |
| Italy | |
| Corriere della Sera | 2027 |
| La Stampa | 1786 |
| La Repubblica | 1443 |
| Japan | |
| Jiji Press | 1492 |
| The Nikkei | 674 |
| The Daily Yomiuri | 437 |
| The Japan Times | 260 |
| The Japan Economic Journal | 197 |
| The Japan News | 57 |
| Report From Japan | 53 |
| Japanese Business Digest | 5 |
| WebNews - Japanese | 1 |
| Latvia | |
| Baltic Business Daily | 914 |
| Baltic Daily - Political/Social News | 95 |
| BNS Baltic Business News | 73 |
| The Baltic Times | 63 |
| Baltic Business News | 29 |
| Baltic Business Weekly | 19 |
| Lithuania | |
| Baltic Business Daily | 474 |
| BNS Baltic Business News | 49 |
| The Baltic Times | 43 |
| Baltic Daily - Political/Social News | 35 |
| Baltic Business Weekly | 29 |
| Baltic Business News | 5 |
| Netherlands | |
| NRC Handelsblad | 1066 |
| Het Financieele Dagblad | 982 |
| de Volkskrant | 532 |
| De Telegraaf | 220 |
| Vrij Nederland | 34 |
| De Groene Amsterdammer | 22 |
| New Zealand | |
| The New Zealand Herald | 1677 |
| The Dominion Post | 445 |
| The Press | 364 |
| Waikato Times | 205 |
| Norway | |
| Dagens Næringsliv | 542 |
| Norsk Telegrambyrå | 254 |
| TDN Nyhetsbyrå | 94 |
| Aftenposten | 35 |
| Bergens Tidende | 17 |
| Stavanger Aftenblad | 16 |
| Norsk Telegrambyr | 5 |
| Vestnytt | 3 |
| Poland | |
| Rzeczpospolita | 1566 |
| Gazeta Wyborcza | 857 |
| Gazeta Prawna | 718 |
| Gazeta.pl | 61 |
| Portugal | |
| Publico | 1811 |
| Jornal de Notícias | 501 |
| Correio da Manhã | 404 |
| Slovakia | |
| Slovenska Tlacova Agentura | 497 |
| Výber správ zo Slovenska | 270 |
| Dennik N | 60 |
| Slovenia | |
| The Slovenia Times | 228 |
| Esmerk Slovenia News | 21 |
| Slovenia Today | 15 |
| M-Brain Slovenia News | 11 |
| News Bites - Central and Eastern Europe: Slovenia | 5 |
| Spain | |
| ABC | 1334 |
| El Periódico | 1323 |
| El Pais | 1153 |
| El Mundo | 609 |
| La Vanguardia.com | 290 |
| El Diario.es | 63 |
| Sweden | |
| Nyhetsbyrån Direkt | 922 |
| Dagens Nyheter | 187 |
| Helsingborgs Dagblad | 42 |
| Sydsvenskan | 18 |
| Switzerland | |
| NZZ | 1192 |
| Tages-Anzeiger | 305 |
| Blick | 13 |
| United Kingdom | |
| The Guardian | 3696 |
| The Times | 2424 |
| The Daily Telegraph (UK) | 1479 |
| United States | |
| The New York Times | 4122 |
| The Washington Post | 2626 |
| The Wall Street Journal | 870 |
The paper uses a dictionary-based approach to sentiment analysis but complements it with natural language process in order to account for negators, amplifiers and deamplifiers. I used standard negators, amplifiers and deamplifiers obtained from the lexicon package.
The sentiment scores represent the unweighted average of four different dictionaries:
– the AFINN dictionary developed by [@Nielsen.2011];
– the Bing sentiment lexicon developed by @Hu.2004;
– the NRC Word-Emotion Association Lexicon developed by @Mohammad.2010; and
– the syuzhet dictionary (and accompanying R package) developed by Matthew Jockers and the Nebraska Literary Lab [@Jockers.2017].
While these dictionaries are widely used and relatively general in purpose, I combined them to make sure that the results are not driven by the particularities of any one of these dictionaries. In case of the NRC dictionary, I did not use their emotion-based dictionaries (such as those for anger, fear, or hope) but only those for positive and negative terms. The afinn and syuzhet dictionaries have a higher resolution than bing and nrc by scoring words not just as negative (-1) and positive (+1) but allowing more gradation. I transformed these higher-resolution scales to a binary positive-negative score for both technical reasons and to provide more robust estimates. After all, whether a word is positive or negative is a much more straightforward question than whether a positive word is quite (+3), very (+4) or extremely (+5) positive, especially across different contexts and for machine-translated documents.
The topic models included only articles about public debt/deficit and public investment as they were meant to capture different state identities, which revolve around debt cultures and conceptions of the role of the state in the economy. For pre-processing, I used annotated part-of-speech tags to select nouns, adjectives, and verbs. I discarded punctuation and stopwords as well as semantically less meaningful parts of speech like determiners or names entities like dates. I also included a list of 184 n-grams, which was manually compiled based on the most frequent collocations identified in the text (with log-frequency biased mutual dependency used as the ordering metric). I lowercased but did not stem our document feature matrix as the difference between singular and plural forms can be meaningful while the difference between uppercased and lowercased words is most likely not – at least in the types of policy and newspaper documents I look at. In addition, I removed remaining word trash such as html tags, common untranslated words, as well as country-specific information using the named entity information. This latter removal is meant to ensure that differences in topic prevalence are, as much as possible, the result of substantive differences and not of local vernaculars or parochial word usage. Lastly, I removed words that appeared in more than 50 per cent or less than 0.5 per cent of documents. While this is a somewhat arbitrary (although commonly used) standard, qualitative inspection revealed but proofed to be a useful threshold that removed many very specific and rare terms while still retaining un-common but not unimportant words.
I chose a topic model with k = 45 topics. This decision was assisted by several metrics. Figure 4.17 plots four metrics – semantic coherence, exclusivity, residuals, and held-out-likelihood – for models with different ks. The range of k was theoretically decided as topics should be broad enough to be at least potentially relevant in different countries, but narrow enough to capture interesting frames of public debt or public investment. This suggests a number of topics somehwere between 20 and 80. Semantic coherence is a metric that measures how often the most frequent words in a topic actually co-occur in a document. While semantic coherence has been shown to correlate well with human judgments of topic quality, it has been shown to increase when topics are dominated by very common words [@Roberts.2018]. Exclusivity, by contrast, penalizes models with few dominant top words. It measures the share of top words which are distinct to a given topic, thus creating something of a trade-off with semantic coherence. The residuals capture overdispersion of the variance of the multinomial in stm’s data generating process [@Roberts.2018]. Higher values indicate overdispersed residuals, implying that the latent topics cannot account for the overdispersion and more topics may be needed to use up the extra variance. Held-out likelihood estimates the probability that words appear in a document when these words have been removed before the estimation. It is a measure of predictive performance, with higher values indicating better performance. Hence, we want semantic coherence, exclusivity, and held-out likelihood to be as high and the residuals to be as low as possible. Figure 4.17 suggest that a topic model with k = 45 should be a good choice, and one that falls squarely within the realm of what we would expect.
storage_df <- storage$results %>%
dplyr::select(
K = K,
`Held-out likelihood` = heldout,
Residuals = residual,
`Semantic coherence` = semcoh,
Exclusivity = exclus,
`Lower bound` = lbound
)%>%
gather(metric, value, `Held-out likelihood`:`Lower bound`)%>%
mutate(metric = factor(metric, levels = c(
"Semantic coherence",
"Exclusivity",
"Residuals",
"Held-out likelihood",
"Lower bound"
)))
storage_df%>%
mutate(K = as.numeric(K),
value = as.numeric(value))%>%
filter(metric != "Lower bound")%>%
ggplot( aes(x = K, y = value, color = metric)) +
geom_line(size = 1.5,
alpha = 0.65,
show.legend = FALSE) +
geom_point(aes(shape = metric, size = .8), show.legend = F)+
facet_wrap(~metric,
scales = "free",
ncol = 2
)+
labs(x = "Number of Topics",
y = NULL)+
scale_color_brewer(palette = "Set1")+
theme_minimal()
Figure 4.17: Model diagnostics for different numbers of topics (20 to 80)
I allowed the country variable and the date variable to influence the prevalence of topics. The topics were then labeled based on the most FRequent and EXclusive Words (FREX). Lastly, topics were assigned to either the ascetic state category or the inclusive state category or they were not assigned at all. Based on @Dyson.2014, topics were assigned to the ascetic state category if they were about balanced budgets, credit ratings, structural reforms, or the like. They were assigned the inclusive state category if they were about investments in infrastructure, green technologies, research, education, or worker protection. Figure 4.18 plots wordclouds with the most common FREX terms for the topics that make up the inclusive state (red) or ascetic state category (blue).
topic_terms_identity <-
labelTopics(model.stm,
c(5, 17, 22, 30, 37, 41, 42),
n = 15,
frexweight = 0.5)[1:4] %>%
lapply(as.data.frame) %>%
lapply(rownames_to_column) %>%
bind_rows(.id = "type") %>%
pivot_longer(cols = V1:V15, values_to = "term") %>%
rename(topic = rowname) %>%
filter(type %in% c("frex")) %>%
mutate(name = str_sub(name, 2)) %>%
filter(topic %in% c(5, 17, 22, 30, 37, 41, 42)) %>%
mutate(
topic = recode(
topic,
"5" = "R&D",
"17" = "Worker Protection",
"22" = "Social Democracy",
"30" = "Green Investments",
"37" = "Higher Education",
"41" = "Transport Infrastructure",
"42" = "General Infrastucture"
)
) %>%
mutate(category = "Inclusive") %>%
rbind(
labelTopics(
model.stm,
c(3, 8, 9, 20, 25, 27, 29),
n = 15,
frexweight = 0.5
)[1:4] %>%
lapply(as.data.frame) %>%
lapply(rownames_to_column) %>%
bind_rows(.id = "type") %>%
pivot_longer(cols = V1:V15, values_to = "term") %>%
rename(topic = rowname) %>%
filter(type %in% c("frex")) %>%
mutate(name = str_sub(name, 2)) %>%
filter(topic %in% c(3, 8, 9, 20, 25, 27, 29)) %>%
mutate(
topic = recode(
topic,
"3" = "Structural Reform",
"8" = "Budget Balance",
"9" = "Ratings",
"20" = "Fiscal Situation",
"25" = "Sustainability of Pensions",
"27" = "Financial Crisis",
"29" = "Government Bonds"
)
) %>%
mutate(category = "Ascetic")
)
topic_terms_identity%>%
mutate(topic = fct_reorder(topic, category))%>%
ggplot(aes(label = term, size = name, color = category)) +
ggwordcloud::geom_text_wordcloud() +
scale_color_brewer(palette = "Set1", direction = -1)+
theme_minimal()+
facet_wrap(~topic, ncol = 7)
Figure 4.18: Wordcloud with top FREX terms for topics assigned to the inclusive state (red) or ascetic state category (blue)
Cofog stands for “CLASSIFICATION OF THE FUNCTIONS OF GOVERNMENT”. A detailed documentation can be found here: https://ec.europa.eu/eurostat/documents/3859598/10142242/KS-GQ-19-010-EN-N.pdf/ed64a194-81db-112b-074b-b7a9eb946c32↩︎
There is also variation across the components of the index. For example, South Korea, Germany or Japan invest much more in R&D than in public education or active labor market policies, relatively speaking. I will discuss some of these differences below but also provide separate descriptive statistics and analysis for individual components in appendices B44.2.4, B54.2.5, and B64.2.6.↩︎
I provide an accompanying html/Rmarkdown document that allows to replicate the entire analysis from data collection to analysis to visualization and gives further details on data collection.↩︎
Appendix B24.2.2 further explains and justifies within-between mixed-effects models and their assumptions.↩︎
Model diagnostics further show that the residuals are homoscedastic and approximately normally distributed (see appendix B324.2.3.2).↩︎
In fact, Katzenstein himself notes that “the impermeability of the field of political economy to considerations of identity persists to date” [@Katzenstein.2003, p. 11].↩︎