library(tidyverse)
gpfg_2021 <- read_csv("data/gpfg_2021.csv")
gpfg_2022 <- read_csv("data/gpfg_2022.csv")
gpfg_2023 <- read_csv("data/gpfg_2023.csv")
gpfg_2024 <- read_csv("data/gpfg_2024.csv")
gpfg_2025 <- read_csv("data/gpfg_2025.csv")6 Analysis II
6.1 Learning objectives
By the end of this chapter, you should be able to:
- explain why trend questions require multiple time points;
- import several annual CSV files;
- compare their names and types before combining them;
- combine tables with the same columns using
bind_rows(); - inspect time coverage, record counts, categories, and missing values;
- calculate annual and country-year summaries; and
- interpret changes without confusing holdings with flows or returns.
6.2 Add the missing time dimension
Chapter 5 used the clean 2025 snapshot to answer description, ranking, comparison, and relationship questions. It could not answer:
How did the total reported market value of NBIM’s equity holdings change from 2021 to 2025?
A trend needs the same measure at several dates. We will add four earlier year-end snapshots and analyse the five-year period from 2021 through 2025. Five files provide enough time points for a trend while keeping the import exercise manageable.
Open djr.Rproj and create 06-data-analysis-ii.Rmd. Keep the gpfg_2025.csv created in Chapter 4. Download gpfg_2021.csv, gpfg_2022.csv, gpfg_2023.csv, and gpfg_2024.csv into the same data folder. A ready-made gpfg_2025.csv is also available if needed.
6.3 Import the annual files
Repeat the local read_csv() pattern from Chapter 3:
The object names record which annual snapshot each table contains.
6.4 Check the structures before combining
Tables should describe the same variables before we place their rows together. Compare an early and late file:
glimpse(gpfg_2021)Rows: 9,338
Columns: 11
$ year <dbl> 2021, 2021, 2021, 2021, 2021, 2021, 2021, 2021, …
$ report_date <date> 2021-12-31, 2021-12-31, 2021-12-31, 2021-12-31,…
$ region <chr> "Oceania", "Oceania", "Oceania", "Oceania", "Oce…
$ country <chr> "Australia", "Australia", "Australia", "Australi…
$ company <chr> "29Metals Ltd", "A2B Australia Ltd", "ALS Ltd", …
$ industry <chr> "Basic Materials", "Financials", "Industrials", …
$ market_value_nok <dbl> 161952543, 6362419, 482302084, 13286938, 1039279…
$ market_value_usd <dbl> 18365506, 721502, 54693318, 1506746, 11785490, 1…
$ voting_pct <dbl> 1.71, 0.62, 1.19, 0.48, 0.49, 1.60, 0.43, 1.16, …
$ ownership_pct <dbl> 1.71, 0.62, 1.19, 0.48, 0.49, 1.60, 0.43, 1.16, …
$ incorporation_country <chr> "Australia", "Australia", "Australia", "Australi…
glimpse(gpfg_2025)Rows: 7,201
Columns: 11
$ year <dbl> 2025, 2025, 2025, 2025, 2025, 2025, 2025, 2025, …
$ report_date <date> 2025-12-31, 2025-12-31, 2025-12-31, 2025-12-31,…
$ region <chr> "Oceania", "Oceania", "Oceania", "Oceania", "Oce…
$ country <chr> "Australia", "Australia", "Australia", "Australi…
$ company <chr> "3P Learning Ltd", "ALS Ltd", "AMP Ltd", "ANZ Gr…
$ industry <chr> "Consumer Discretionary", "Industrials", "Financ…
$ market_value_nok <dbl> 34140465, 1044536415, 393367522, 16360856591, 13…
$ market_value_usd <dbl> 3384651, 103554273, 38998054, 1621998602, 131849…
$ voting_pct <dbl> 3.00, 1.39, 1.27, 2.22, 1.68, 1.28, 1.17, 3.23, …
$ ownership_pct <dbl> 3.00, 1.39, 1.27, 2.22, 1.68, 1.28, 1.17, 3.23, …
$ incorporation_country <chr> "Australia", "Australia", "Australia", "Australi…
The column names and types should match. Each file already contains a year column, so observations will remain distinguishable after combination.
If annual files use different names, types, units, or definitions, stacking them can create a misleading table. Resolve meaningful differences before analysing a trend.
6.5 Combine annual rows with bind_rows()
The five tables contain the same columns but different annual observations. bind_rows(table1, table2, ...) places their rows underneath one another. The table names are separated by commas, and their shared column names line up in the result:
gpfg <- bind_rows(
gpfg_2021,
gpfg_2022,
gpfg_2023,
gpfg_2024,
gpfg_2025
)One row still represents one reported holding in one year-end snapshot. The operation adds observations; it does not add new variables.
This is different from a join. Chapter 9 will use a shared key to add variables from another table.
6.6 Check the combined result
Are all expected years present?
gpfg |>
count(year)The result should contain five consecutive years. The number of reported holding records differs by year, so changes in totals should not be interpreted without considering changes in coverage.
What does one row represent now?
glimpse(gpfg)Rows: 43,285
Columns: 11
$ year <dbl> 2021, 2021, 2021, 2021, 2021, 2021, 2021, 2021, …
$ report_date <date> 2021-12-31, 2021-12-31, 2021-12-31, 2021-12-31,…
$ region <chr> "Oceania", "Oceania", "Oceania", "Oceania", "Oce…
$ country <chr> "Australia", "Australia", "Australia", "Australi…
$ company <chr> "29Metals Ltd", "A2B Australia Ltd", "ALS Ltd", …
$ industry <chr> "Basic Materials", "Financials", "Industrials", …
$ market_value_nok <dbl> 161952543, 6362419, 482302084, 13286938, 1039279…
$ market_value_usd <dbl> 18365506, 721502, 54693318, 1506746, 11785490, 1…
$ voting_pct <dbl> 1.71, 0.62, 1.19, 0.48, 0.49, 1.60, 0.43, 1.16, …
$ ownership_pct <dbl> 1.71, 0.62, 1.19, 0.48, 0.49, 1.60, 0.43, 1.16, …
$ incorporation_country <chr> "Australia", "Australia", "Australia", "Australi…
The same company can appear in several years. A row is therefore not a unique company across the full period, and the table does not contain transactions.
Are important values missing?
gpfg |>
filter(is.na(company) | is.na(market_value_nok))The | symbol means “or.” An empty result confirms that both fields are complete in the supplied annual files, although it does not prove that every published value is correct.
Do category labels look consistent?
gpfg |>
distinct(region) |>
arrange(region)For longer historical periods, country and industry definitions may change. Never assume that identically named columns are perfectly comparable across time without checking the source documentation.
6.7 Save the five-year table
Later chapters can begin from the completed combination step:
write_csv(gpfg, "data/gpfg_5_years.csv")The repository also provides a ready-made gpfg_5_years.csv for learners beginning with a visualization chapter.
6.8 Ask an overall trend question
How did the total reported market value of NBIM’s equity holdings change from 2021 through 2025?
The question needs year and market_value_nok. Group the observations by year and return one summary row for each annual snapshot:
annual_summary <- gpfg |>
group_by(year) |>
summarise(
holding_records = n(),
market_value_nok = sum(market_value_nok)
) |>
arrange(year)
annual_summaryTrack the changing row meaning:
- before
summarise(), one row represents one holding in one year; - after
summarise(), one row represents one annual snapshot.
Keeping both record count and market value visible helps us notice that a change in the total occurs alongside a changing number of reported holdings.
6.9 Combine trend and comparison
We can also ask:
How did the total reported market value of NBIM’s equity holdings in the United States, China, and Japan change from 2021 through 2025?
Create a vector containing the three selected markets. The expression country %in% selected_countries asks whether each country belongs to that vector and returns TRUE or FALSE; filter() keeps the TRUE rows:
selected_countries <- c("United States", "China", "Japan")
country_trends <- gpfg |>
filter(country %in% selected_countries) |>
group_by(year, country) |>
summarise(market_value_nok = sum(market_value_nok)) |>
arrange(country, year)
country_trendsOne row now represents one selected investment market in one year.
This table combines a comparison question—differences among markets—with a trend question—change across years. Chapter 8 will display the three series with separate colored lines.
6.10 Interpret trends carefully
The annual values are year-end market values of reported holdings. A change can reflect:
- security prices;
- exchange rates;
- purchases or sales;
- companies entering or leaving the portfolio; or
- changes in reporting coverage or classification.
The table does not isolate those causes. Describe the observed pattern first, then seek additional evidence before explaining it. Use “year-end market value,” not “money invested that year” or “investment return.”
data/gpfg_history.csv.gz contains the full 1998–2025 archive. It is useful for advanced reporting, but the longer period includes major coverage and classification changes. The five-year table is the main beginner dataset.
6.11 Questions now available
| Question | Single year needed? | Multiple years needed? |
|---|---|---|
| What was the median value of an NBIM company holding in 2025? | Yes | No |
| Which investment markets accounted for the largest 2025 totals? | Yes | No |
| Were ownership percentage and holding value associated in 2025? | Yes | No |
| Did the total value of NBIM’s reported equity holdings rise or fall? | No | Yes |
| Did the selected investment markets follow similar paths? | No | Yes |
More data do not replace a precise question. Use multiple years only when time is part of the question.
6.12 Practice
- Import the five annual files and compare the structures of 2021 and 2025.
- Combine them and confirm the available years with
count(). - Calculate one row per year containing record count and total USD value.
- Choose one country and calculate its annual NOK totals.
- Compare two industries across the five years.
- Write one supported trend finding and two possible explanations requiring additional reporting.
6.13 Takeaways
| Function or idea | What it does |
|---|---|
read_csv() |
Imports each annual CSV |
glimpse() |
Confirms that annual names and types match |
bind_rows() |
Places observations from similar tables underneath one another |
count(year) |
Checks year coverage and annual record counts |
write_csv() |
Saves the combined result for later chapters |
group_by(year) + summarise() |
Produces one summary row per year |
%in% |
Tests whether a value belongs to a selected vector |
group_by(year, country) |
Defines country-year groups for a comparative trend |
Chapter 7 will turn the checked annual summary into a line chart and the 2025 country comparison into a bar chart.