Reads the raw data, creates the output folders, and defines every constant used later (industry codes, country groups, periods, figure style).
if (!dir.exists("Data")) {
stop(
"Working directory is not the project root.\n",
" Currently in: ", getwd(), "\n",
" Fix: open PKP26_manufacturing.Rproj in RStudio.",
call. = FALSE
)
}
getwd()
## [1] "/Users/pikaprincic/Documents/Magisterij /IMB /PKP /Data/PKP26_manufacturing"
required_packages <- c("dplyr", "ggplot2")
missing_packages <- required_packages[
!required_packages %in% rownames(installed.packages())
]
if (length(missing_packages) > 0) {
stop(
"Missing required package(s): ", paste(missing_packages, collapse = ", "), "\n",
" Please run:\n",
' install.packages(c("', paste(missing_packages, collapse = '", "'), '"))',
call. = FALSE
)
}
suppressPackageStartupMessages({
library(dplyr)
library(ggplot2)
})
output_dirs <- c("output", "output/tables", "output/figures", "output/clean")
for (d in output_dirs) {
if (!dir.exists(d)) dir.create(d, recursive = TRUE)
}
list.dirs("output")
## [1] "output" "output/clean" "output/figures" "output/tables"
Source: EUKLEMS & INTANProd (LUISS). Two objects:
klems - industry x country x year, 1995-2021. The
working dataset.annual - country x year, total economy, 2010-2025.
Macro context only.raw_data_file <- "Data/Luiss_datasets.RData"
if (!file.exists(raw_data_file)) {
stop("Raw data not found at: ", raw_data_file, call. = FALSE)
}
load(raw_data_file)
annual$year <- as.integer(annual$year)
dim(klems)
## [1] 61128 236
dim(annual)
## [1] 495 35
focus_sections <- c("C")
industry_labels <- c(
C = "Manufacturing"
)
industry_groups <- c(
C = "Manufacturing"
)
For Slovenia, official investment statistics (GFCF, capital stocks,
the tangible/intangible split, growth accounting) exist only at section
level. Below that, at division level, only value added and the
LUISS-estimated economic competencies (I_OrgCap,
I_Brand, I_Train, I_Design and
their capital stocks) are available.
Consequence for RQ3: the knowledge-intensive vs. traditional comparison cannot use the full tangible/intangible investment structure, only these four competency variables.
# Manufacturing only
division_parent <- c(
"C10-C12" = "C", "C13-C15" = "C", "C16-C18" = "C", "C19" = "C",
"C20" = "C", "C21" = "C", "C22-C23" = "C", "C24-C25" = "C",
"C26" = "C", "C27" = "C", "C28" = "C", "C29-C30" = "C", "C31-C33" = "C"
)
division_codes <- names(division_parent)
# Manufacturing knowledge-intensive vs traditional split (PKP3 RQ3). The
# 6 KI codes and 6 of the 7 Traditional codes below are from
# PKP3.docx's RQ3 table. C19 (coke and refined petroleum) is NOT
# classified anywhere in that table, it is neither listed under
# "Knowledge-intensive manufacturing" nor "Traditional manufacturing". Placing
# it under Traditional here as an unverified assumption.
manufacturing_division_group <- c(
"C20" = "Knowledge-intensive",
"C21" = "Knowledge-intensive",
"C26" = "Knowledge-intensive",
"C27" = "Knowledge-intensive",
"C28" = "Knowledge-intensive",
"C29-C30" = "Knowledge-intensive",
"C10-C12" = "Traditional",
"C13-C15" = "Traditional",
"C16-C18" = "Traditional",
"C19" = "Traditional", # UNCONFIRMED - see note above
"C22-C23" = "Traditional",
"C24-C25" = "Traditional",
"C31-C33" = "Traditional"
)
length(division_codes)
## [1] 13
table(division_parent)
## division_parent
## C
## 13
table(manufacturing_division_group)
## manufacturing_division_group
## Knowledge-intensive Traditional
## 6 7
# Only countries with usable tangible AND intangible investment data for the
# focus sections. PL, HR and IE have no intangibles at all; BE has tangibles
# but no intangibles; HU and EE have intangibles but no tangibles. Belgium and
# Ireland are usually described as intangible-intensive, so their absence is
# forced by coverage, not chosen.
country_groups <- list(
slovenia = "SI",
cee = c("CZ", "SK", "RO", "LV"),
frontier = c("SE", "DK", "FI", "NL"),
neighbour = c("AT", "IT"),
large = c("DE", "ES", "FR"),
outside = c("US", "JP")
)
peer_countries <- unlist(country_groups, use.names = FALSE)
# No EU aggregate carries the intangible investment variables, so the EU
# comparison for investment is built from member states. EU12 does carry
# growth accounting and excludes Slovenia, making it a clean comparator.
ga_benchmark <- "EU12"
“1995-2021” conceals four different periods.
periods <- list(
flows = c(1995, 2021),
stocks = c(2000, 2021),
contributions = c(2001, 2021),
tfp = c(2009, 2021)
)
periods
## $flows
## [1] 1995 2021
##
## $stocks
## [1] 2000 2021
##
## $contributions
## [1] 2001 2021
##
## $tfp
## [1] 2009 2021
Black and white only.
theme_pkp <- function(base_size = 11) {
theme_bw(base_size = base_size) +
theme(
panel.grid.minor = element_blank(),
panel.grid.major = element_line(colour = "grey85", linewidth = 0.3),
panel.border = element_rect(colour = "black", linewidth = 0.4),
strip.background = element_rect(fill = "grey92", colour = "black"),
legend.position = "bottom",
legend.title = element_blank(),
plot.title = element_text(face = "bold", size = base_size)
)
}
grey_palette <- c("black", "grey45", "grey70", "grey25", "grey85", "grey60")
save(focus_sections, industry_labels, industry_groups,
division_codes, division_parent, manufacturing_division_group,
country_groups, peer_countries, ga_benchmark, periods,
theme_pkp, grey_palette,
file = "output/clean/00_setup.RData")
cat("00_setup complete\n")
## 00_setup complete
cat(" klems :", nrow(klems), "rows x", ncol(klems), "columns |",
min(klems$year), "-", max(klems$year), "\n")
## klems : 61128 rows x 236 columns | 1995 - 2021
cat(" annual :", nrow(annual), "rows x", ncol(annual), "columns |",
min(annual$year), "-", max(annual$year), "\n")
## annual : 495 rows x 35 columns | 2010 - 2025
cat(" sections :", paste(focus_sections, collapse = " "), "\n")
## sections : C
cat(" divisions:", length(division_codes), "\n")
## divisions: 13
cat(" peers :", length(peer_countries), "countries\n")
## peers : 16 countries
output/clean/pkp_clean.rdsIndustries are matched exactly against the lists
from the setup section. Never by pattern, because the industry column
mixes four levels of one hierarchy. Countries are the usable comparators
plus EU12.
keep_geo <- c(peer_countries, ga_benchmark)
keep_nace <- c(focus_sections, division_codes)
dat <- klems %>%
filter(nace_r2_code %in% keep_nace,
geo_code %in% keep_geo)
nrow(dat)
## [1] 6426
table(dat$geo_code)
##
## AT CZ DE DK ES EU12 FI FR IT JP LV NL RO SE SI SK
## 378 378 378 378 378 378 378 378 378 378 378 378 378 378 378 378
## US
## 378
Critical. Section C contains
division C26; adding them together double-counts. Every row
is labelled section or division, and every
division records its parent. Always filter on level before
aggregating.
dat <- dat %>%
mutate(
level = if_else(nace_r2_code %in% focus_sections, "section", "division"),
parent = if_else(level == "section",
nace_r2_code,
unname(division_parent[nace_r2_code])),
manufacturing_group = if_else(
nace_r2_code %in% names(manufacturing_division_group),
unname(manufacturing_division_group[nace_r2_code]),
NA_character_
)
)
table(dat$level)
##
## division section
## 5967 459
table(dat$manufacturing_group, useNA = "ifany")
##
## Knowledge-intensive Traditional <NA>
## 2754 3213 459
wanted <- c(
"nace_r2_code", "nace_r2_name", "geo_code", "year", "level", "parent",
"manufacturing_group",
# output and labour input
"VA_CP", "VA_Q", "VAadj", "VAadj_q", "EMP", "H_EMP",
# investment, national accounts basis
"I_GFCF", "I_IT", "I_CT", "I_Soft_DB", "I_RD", "I_OIPP",
# investment, CHS basis
"I_Tang", "I_Intang", "I_NatAcc", "I_NonNatAcc",
"I_Innovprop", "I_EconComp",
"I_OrgCap", "I_Brand", "I_Train", "I_Design",
# investment in chained volumes (2015), needed for anything over time
"Iq_GFCF", "Iq_Tang", "Iq_Intang",
# capital stocks
"K_GFCF", "K_RD", "K_Soft_DB", "K_Tang",
"K_NatAcc", "K_NonNatAcc", "K_OrgCap", "K_Brand", "K_Train",
# growth accounting: capital contributions split tangible/intangible/ICT/non-ICT,
# labour quantity and quality, and both the TFP level indices and their
# growth contributions.
"CAPIntang_QI", "CAPTang_QI", "CAPICT_QI", "CAPNICT_QI",
"LAB", "LAB_QI",
"LP1TFP_I", "LP2TFP_I", "VATFP_I",
"LP1ConTFP", "LP2ConTFP", "VAConTFP"
)
wanted <- intersect(wanted, names(dat))
dat <- dat %>%
select(all_of(wanted)) %>%
rename(nace = nace_r2_code,
geo = geo_code)
length(wanted)
## [1] 53
All monetary variables are in millions of national currency, so
levels cannot be compared across countries, every indicator below is a
ratio. Two accounting bases exist and must not be mixed: national
accounts (I_GFCF over VA_CP) and CHS
(I_Intang, I_Tang over
VAadj).
# An INTENSITY (flow relative to output) means net disinvestment.
safe_intensity <- function(num, den) {
if_else(!is.na(den) & den > 0, 100 * num / den, NA_real_)
}
# A SHARE (part of a whole) must lie between 0 and 100 by definition. It can
# fall outside that range only when some component of the whole is negative.
# Such a figure is not meaningful, so it is set to NA and counted, never
# silently kept or clamped to a boundary.
safe_share <- function(part, whole) {
x <- if_else(!is.na(whole) & whole != 0, 100 * part / whole, NA_real_)
if_else(!is.na(x) & x >= 0 & x <= 100, x, NA_real_)
}
dat <- dat %>%
mutate(
# -- investment intensities (percent of value added) --------------------
inv_intensity = safe_intensity(I_GFCF, VA_CP), # national accounts basis
intang_intensity = safe_intensity(I_Intang, VAadj), # CHS basis
tang_intensity = safe_intensity(I_Tang, VAadj),
# -- the headline structural indicator ----------------------------------
intang_share = safe_share(I_Intang, I_Intang + I_Tang),
# -- CHS composition (shares of total intangible investment) ------------
sh_compinfo = safe_share(I_Soft_DB, I_Intang), # computerized information
sh_innovprop = safe_share(I_Innovprop, I_Intang), # innovative property
sh_econcomp = safe_share(I_EconComp, I_Intang), # economic competencies
# -- the measurement gap -------------------------------------------------
sh_nonNA = safe_share(I_NonNatAcc, I_Intang),
# -- individual assets, as shares of intangible investment ---------------
sh_rd = safe_share(I_RD, I_Intang),
sh_orgcap = safe_share(I_OrgCap, I_Intang),
sh_brand = safe_share(I_Brand, I_Intang),
sh_train = safe_share(I_Train, I_Intang),
sh_design = safe_share(I_Design, I_Intang),
# -- tangible composition: ICT vs non-ICT (national accounts basis) ------
ict_share = safe_share(I_IT + I_CT + I_Soft_DB, I_GFCF),
# -- labour productivity, CHS basis, real ---------------------------------
lp_hour = VAadj_q / H_EMP,
# -- reconstructed intangible capital stock -------------------------------
# K_Intang is unusable as delivered (one year for Slovenia). Its
# components are complete from 2000, and their sum reproduces the
# published figure exactly in the year it exists, so it is rebuilt here.
K_Intang_rebuilt = K_NatAcc + K_NonNatAcc,
# -- flag the known anomaly ----------------------------------------------
# Slovenian stock variables spike implausibly in 2020 (K_OrgCap roughly
# doubles and falls back). The anomaly is in the source LUISS module, not
# introduced here. Flow variables are unaffected.
stock_suspect = (geo == "SI" & year == 2020)
)
dat <- dat %>%
mutate(
industry = if_else(level == "section",
unname(industry_labels[nace]),
nace_r2_name),
group = unname(industry_groups[parent]),
is_focus_country = geo %in% peer_countries
) %>%
select(-nace_r2_name) %>%
relocate(nace, industry, level, parent, group, manufacturing_group, geo, year)
head(dat[dat$level == "division" & dat$parent == "C", 1:8])
## # A tibble: 6 × 8
## nace industry level parent group manufacturing_group geo year
## <chr> <chr> <chr> <chr> <chr> <chr> <chr> <dbl>
## 1 C10-C12 Manufacture of foo… divi… C Manu… Traditional AT 1995
## 2 C10-C12 Manufacture of foo… divi… C Manu… Traditional AT 1996
## 3 C10-C12 Manufacture of foo… divi… C Manu… Traditional AT 1997
## 4 C10-C12 Manufacture of foo… divi… C Manu… Traditional AT 1998
## 5 C10-C12 Manufacture of foo… divi… C Manu… Traditional AT 1999
## 6 C10-C12 Manufacture of foo… divi… C Manu… Traditional AT 2000
# 1. Does industry + country + year still uniquely identify a row?
stopifnot(nrow(dat) == nrow(distinct(dat, nace, geo, year)))
# 1b. Is every division assigned to a parent section?
stopifnot(!any(is.na(dat$parent)))
# 2. Does the CHS identity hold?
chs_gap <- dat %>%
filter(!is.na(I_Intang), I_Intang > 0) %>%
mutate(d = abs(I_Soft_DB + I_Innovprop + I_EconComp - I_Intang) / I_Intang) %>%
summarise(max_deviation_pc = 100 * max(d, na.rm = TRUE)) %>%
pull(max_deviation_pc)
# 3. Does the national-accounts split hold?
na_gap <- dat %>%
filter(!is.na(I_Intang), I_Intang > 0) %>%
mutate(d = abs(I_NatAcc + I_NonNatAcc - I_Intang) / I_Intang) %>%
summarise(max_deviation_pc = 100 * max(d, na.rm = TRUE)) %>%
pull(max_deviation_pc)
# 4. Are the shares in a sensible range?
share_range <- range(dat$intang_share, na.rm = TRUE)
# 4b. How many observations were set aside because a component was negative?
n_suppressed <- sum(!is.na(dat$I_Intang) & !is.na(dat$I_Tang) &
is.na(dat$intang_share))
cat("unique key .................. OK\n")
## unique key .................. OK
cat("CHS identity, max deviation :", round(chs_gap, 6), "percent\n")
## CHS identity, max deviation : 0 percent
cat("NA split, max deviation :", round(na_gap, 6), "percent\n")
## NA split, max deviation : 0 percent
cat("intangible share range ......", round(share_range[1], 1), "to",
round(share_range[2], 1), "percent\n")
## intangible share range ...... 2.7 to 100 percent
cat("shares set to NA (negative component):", n_suppressed, "\n")
## shares set to NA (negative component): 4
stopifnot(chs_gap < 0.01, na_gap < 0.01,
share_range[1] >= 0, share_range[2] <= 100)
saveRDS(dat, "output/clean/pkp_clean.rds")
cat("01_prepare_data complete\n")
## 01_prepare_data complete
cat(" rows :", nrow(dat), "\n")
## rows : 6426
cat(" columns :", ncol(dat), "\n")
## columns : 72
cat(" countries :", length(unique(dat$geo)), "\n")
## countries : 17
cat(" years :", min(dat$year), "-", max(dat$year), "\n")
## years : 1995 - 2021
Later sections begin with:
load("output/clean/00_setup.RData")
dat <- readRDS("output/clean/pkp_clean.rds")
One of these before aggregating:
sections <- dat %>% filter(level == "section") # the main analysis
divisions <- dat %>% filter(level == "division") # economic competencies only
Mixing the two levels in one total double-counts.
(TODO)
(TODO)
(TODO)
(TODO)
(TODO)