Format tables
Translate codes to text with DST’s SAS format files
The format tables on the server are the authority, not this page. The examples and code lists here are a starting point. DST updates the format catalogue without this guide knowing, and a code can change meaning while keeping its number. Load the current table from E:/Formater/ and check the values in your own delivered data before you rely on a mapping.
Several of the same code lists are also published outside DST, as classifications with a CSV download, which is the version Find a variable shows.
Prerequisite: This page uses left_join() to attach format tables to your data. If you are not familiar with joins yet, read Phase 12 - Assemble and prepare the dataset first.
Many variables in DST registers are stored as codes - municipality numbers, education codes, employment codes. To give them meaningful labels you use DST’s format tables: SAS files on the server that translate codes to text.
A format table always has at least two columns:
| Column | Contents | Example |
|---|---|---|
START |
The raw code from your register | 101 (municipality number) |
| Label column | The corresponding text label | "København" |
You join the format table onto your dataset with START as the key - exactly like a dictionary lookup.
Rows in your dataset without a match in the format table get NA in the label column - no error message. Always check with sum(is.na(data$label_column)) after the join.
Where are the format tables?
E:/Formater/SAS formater i Danmarks Statistik/SAS_datasaet/
The Star (*) on the Windows desktop inside the DST server opens an HTML guide for finding the right table. DST’s written guides sit here:
E:/Formater/SAS formater i Danmarks Statistik/Vejledning mv/
The one worth reading is Brugen af SAS formater i Danmarks Statistik.pdf (~2 MB, DST Consulting). It explains the naming systematics used below and has a section per topic - Uddannelserne, Brancherne, DISCO, Sundhed, Geokoder, DREAM. The same folder holds dated older editions (2012-2019) and a set of Allokering af formatbibliotek (*).sas scripts for pointing SAS at the format catalog - those are for SAS users and are not needed from R.
Two more folders one level up are worth knowing:
E:/Formater/SAS formater i Danmarks Statistik/HTML_oversigter/ ← browsable code lists
E:/Formater/SAS formater i Danmarks Statistik/PDF_lister/ ← the same as PDF
They let you look up what a code means without loading anything into R - useful when you just need to check a single value.
Subfolders are organised by topic - including:
Geokoder/ ← municipalities, regions
Times_personstatistik/ ← employment (socio13)
Uddannelser/ ← education (hfaudd)
Brancher/ ← industries
Sundhed/ ← health
Disced/ ← education, SAS format catalog (see note)
... and more
Education sits in two places, and the naming is confusing. The files you read from R are in SAS_datasaet/Uddannelser/. DST’s own SAS format catalog for the same thing is called DISCED, which is why the word turns up in the documentation and in a separate folder. From R you want Uddannelser/.
Find the specific filenames in the folder yourself. The base path and subfolder structure above are confirmed on DST. But the specific filenames and column names further down the page (e.g. c_kom_v4_t.sas7bdat, KOM_V4_T) are illustrative examples - naming varies, and you must find the right file in the relevant subfolder yourself. Use the Star guide / PDF guide to find the file, and names()/head() to see the actual column names.
Load a format table
Format tables are SAS files and are loaded with haven::read_sas():
library(haven) # read_sas - loading SAS files
mun_table <- read_sas(
# fetch format table as data frame
"E:/Formater/SAS formater i Danmarks Statistik/SAS_datasaet/Geokoder/c_kom_v4_t.sas7bdat"
)Format tables are loaded directly into R’s memory (not lazy evaluation). You must collect() DuckDB data before joining with them.
Two of these lookups already exist in R. The heaven package ships them as data, so you do not have to read a SAS format file at all:
data(edu_code): 4,621 education codes withhfauddmapped to categories in English and Danish, a 5-level grouping and ISCED codes.kommuneRegion(kommune): converts a numeric 3-digit municipality code straight to one of the five regions (valid from 2007). It gives you the region, not the municipality name - for the name you still need the format table below.
heaven is pre-installed on DST, and elsewhere it installs from GitHub with pak::pak("tagteam/heaven") (it is not on CRAN, so install.packages() will not find it). The format tables below are still the route for every code heaven does not cover, and they are what DST itself publishes.
The tables you will use most often
Municipality names
mun_table <- read_sas(
"E:/Formater/SAS formater i Danmarks Statistik/SAS_datasaet/Geokoder/c_kom_v4_t.sas7bdat"
)
# Columns: START (municipality number), KOM_V4_T (municipality name)
# Use for years after the 2007 municipal reform (V4)
bef_with_mun <- bef_data %>%
collect() %>% # collect BEFORE joining with SAS file
left_join(mun_table, by = c("kom" = "START")) # attach municipality name via the kom codeEmployment status (socio13)
To get the raw code labels from DST’s format table:
socio13_table <- read_sas(
# fetch label table from format folder
"E:/Formater/SAS formater i Danmarks Statistik/SAS_datasaet/Times_personstatistik/n_socio13_kt.sas7bdat"
)
# Columns: START (socio13 code), N_SOCIO13_KT (label)
akm_with_labels <- akm_data %>%
left_join(socio13_table, by = c("socio13" = "START")) # attach label per codeTo use the SEPLINE categorisation directly instead (recommended for analysis):
library(dplyr) # mutate, case_when
akm_categorised <- akm_data %>%
mutate(
occupation_cat = case_when(
# SEPLINE categories
socio13 %in% c(110:114, 120, 131:135, 139) ~ "Employed",
socio13 == 310 ~ "Student",
socio13 %in% c(210, 410) ~ "Unemployed",
socio13 %in% c(220, 321, 330) ~ "Outside labour market",
socio13 %in% c(322, 323) ~ "Retired",
TRUE ~ "Unknown" # unknown code or NA
)
)Education level (hfaudd)
hfaudd is the four-digit code for the specific education. Its level - the thing almost every analysis actually needs - lives in a separate lookup, and the filename tells you exactly which lookup you are getting.
These files are dictionaries, not data. A .sas7bdat in the format folders holds no people and no register records. It is a two-column translation table - one row per code, with the code and what it means - and they are tiny, a few hundred KB. You read one into R and left_join() it onto your own data, exactly like the municipality example above. Nothing about your cohort changes; you are only adding a column that says what a code stands for.
The filenames are systematic. DST’s own guide sets it out as $AUDD2011_L1L2_KT, read left to right:
| Part | Means |
|---|---|
c_ / n_ |
character or numeric - match your column’s type |
audd / udd |
afsluttet (completed) or igangværende/afbrudt (ongoing or interrupted) education |
2008 2011 2015 |
which version of the classification |
l1 |
the level you are coming from |
l5 |
the level you are going to |
_k _t _kt |
output: code only, text only, or code + text |
hfaudd is a completed education, so you want an audd file, not a udd one. DISCED-15 distinguishes between the code for an ongoing or interrupted education (UDD) and for a completed one (AUDD) - DST documents the two separately - and there are format files for both. The name gives it away: hfaudd is højest fuldførte AUDD, the highest completed education. A udd lookup joined to hfaudd will match some rows, miss others, and never tell you.
And the levels themselves. The Danish names are what you will see on the server; the English is what they mean:
| Level | Danish (as DST names it) | In English |
|---|---|---|
| 1 | Den 4-cifrede AUDD | the four-digit code for the specific education - this is hfaudd |
| 2 | Elementærniveau | elementary level - the finest grouping above the code itself |
| 3 | Undergruppe | subgroup |
| 4 | Mellemgruppe | intermediate group |
| 5 | Hovedgruppe | main group - the short/medium/long level almost every analysis wants |
So the file that turns hfaudd into short/medium/long is an L1 → L5 file. Level 5 is the grouping that comes out as 10 Grundskole, 20 Gymnasiale uddannelser, 30 Erhvervsfaglige uddannelser, 35 Adgangsgivende uddannelsesforløb, 40 KVU, 50 MVU, 60 Bachelor, 70 LVU, 80 Ph.d.
library(haven) # read_sas()
library(dplyr)
# Look first - the version in the filename varies, so do not copy this blindly
list.files("E:/Formater/SAS formater i Danmarks Statistik/SAS_datasaet/Uddannelser/")
# An L1 -> L5 file: from the 4-digit code to Hovedgruppe, code + text.
# c_ = character, so use n_audd2015_l1l5_kt.sas7bdat if hfaudd is numeric.
udda_level <- read_sas(
"E:/Formater/SAS formater i Danmarks Statistik/SAS_datasaet/Uddannelser/c_audd2015_l1l5_kt.sas7bdat"
)
names(udda_level) # find the START column and the label column
head(udda_level)
# Join it on, then check how many found no match
udda_data <- udda_data %>%
mutate(hfaudd = as.character(hfaudd)) %>% # match the type in the format table
left_join(udda_level, by = c("hfaudd" = "START"))
udda_data %>% summarise(unmatched = sum(is.na(.data[[names(udda_level)[2]]])), total = n())Three things to check before you trust the result.
- Use the newest version, and only that one. The folder holds several versions side by side -
2008,2011,2015and possibly newer - and it is tempting to think you need one per study year. You do not. DST’s own guide says the education statistics are updated every year with the newest codes backwards in time as well, so the latest version already covers the older codes. One file, for the whole study period. (From 2015 the classification is DISCED-15, which replaced the olderForspalte,ISCED1997andDUN.) - Character or numeric.
c_($in SAS) expects a character variable,n_a numeric one. Both exist for the same mapping. Pick the one matching your column, or convert - a type mismatch produces a join that matches nothing and fills the column withNAwithout any error. _kvs_tvs_kt._kgives you only the code,_tonly the text,_ktboth. For a categorical covariate you usually want_ktso you can see what the codes mean while you work.
Paths on DST. The E:/Formater/... path above is the same for everyone working on a DST research machine, so it should work as written - but check it yourself before you rely on it, and expect it to differ if you are on a hosted machine. DST’s own guide gives the network paths as \\srvfsenas1\data\formater\SAS formater i Danmarks Statistik (researcher machine) and \\srvfsenas5\formater\SAS formater i Danmarks Statistik (hosted). The full guide is the PDF “Brugen af SAS formater i Danmarks Statistik” under E:/Formater/SAS formater i Danmarks Statistik/Vejledning mv/.
Why the level has to be looked up at all - and what it costs to guess it from the digits - is in Overview of registers. The full extraction, from opening UDDA to a categorised variable, is in Socioeconomic variables, which also covers the heaven shortcut.
Tips for finding the right table
- Open the Star on the desktop or navigate to
E:/Formater/...in File Explorer - Look at the suffix:
_T= text label only_K= code only_KT= both code and text
- Load the table and look at the columns with
names()andhead()
names(mun_table) # see what the columns are called - find START and the label column
head(mun_table) # see the first rows and understand the structureSee also
- Socioeconomic variables: SEPLINE approach with code examples for AKM, FAIK and UDDA