Init

library(kirkegaard)
## Loading required package: tidyverse
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.4     ✔ readr     2.1.5
## ✔ forcats   1.0.0     ✔ stringr   1.5.1
## ✔ ggplot2   3.5.1     ✔ tibble    3.2.1
## ✔ lubridate 1.9.3     ✔ tidyr     1.3.1
## ✔ purrr     1.0.2     
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
## Loading required package: magrittr
## 
## 
## Attaching package: 'magrittr'
## 
## 
## The following object is masked from 'package:purrr':
## 
##     set_names
## 
## 
## The following object is masked from 'package:tidyr':
## 
##     extract
## 
## 
## Loading required package: weights
## 
## Loading required package: Hmisc
## 
## 
## Attaching package: 'Hmisc'
## 
## 
## The following objects are masked from 'package:dplyr':
## 
##     src, summarize
## 
## 
## The following objects are masked from 'package:base':
## 
##     format.pval, units
## 
## 
## Loading required package: assertthat
## 
## 
## Attaching package: 'assertthat'
## 
## 
## The following object is masked from 'package:tibble':
## 
##     has_name
## 
## 
## Loading required package: psych
## 
## 
## Attaching package: 'psych'
## 
## 
## The following object is masked from 'package:Hmisc':
## 
##     describe
## 
## 
## The following objects are masked from 'package:ggplot2':
## 
##     %+%, alpha
## 
## 
## 
## Attaching package: 'kirkegaard'
## 
## 
## The following object is masked from 'package:psych':
## 
##     rescale
## 
## 
## The following object is masked from 'package:assertthat':
## 
##     are_equal
## 
## 
## The following object is masked from 'package:purrr':
## 
##     is_logical
## 
## 
## The following object is masked from 'package:base':
## 
##     +
load_packages(
  haven,
  readxl,
  googlesheets4
)

theme_set(theme_bw())

options(
    digits = 3
)

Data

#from OWID, but you can also use the same UN data we have loaded
fert = read_csv("data/children-per-woman-un.csv")
## Rows: 18722 Columns: 4
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (2): Entity, Code
## dbl (2): Year, Fertility rate - Sex: all - Age: all - Variant: estimates
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# NIQ = read_excel("data/hlopostharm.xlsx")
gs4_deauth()
NIQ2 = read_sheet("https://docs.google.com/spreadsheets/d/1cReoeIZLlbxOrN4_wnj52Q6UWFepXSJGi3Gj5m6ZAZg/edit?gid=0#gid=0")
## ✔ Reading from "National IQ datasets".
## ✔ Range 'Sheet1'.
#UN data
pop = read_excel("data/WPP2024_GEN_F01_DEMOGRAPHIC_INDICATORS_COMPACT.xlsx", skip = 16, guess_max = 10000) %>% 
  filter(!is.na(`ISO3 Alpha-code`)) %>% 
  df_legalize_names() %>%
  select(ISO3_Alpha_code, Year, Total_Population_as_of_1_January_thousands) %>% 
  rename(
    ISO = ISO3_Alpha_code,
    Population = Total_Population_as_of_1_January_thousands
  ) %>% mutate(
    Population = as.numeric(Population) * 1000
  )

#future estimates
pop_future = read_excel("data/WPP2024_GEN_F01_DEMOGRAPHIC_INDICATORS_COMPACT.xlsx", skip = 16, guess_max = 10000, sheet = 2) %>% 
  filter(!is.na(`ISO3 Alpha-code`)) %>% 
  df_legalize_names() %>%
  select(ISO3_Alpha_code, Year, Total_Population_as_of_1_January_thousands) %>% 
  rename(
    ISO = ISO3_Alpha_code,
    Population = Total_Population_as_of_1_January_thousands
  ) %>% mutate(
    Population = as.numeric(Population) * 1000
  )

#join
pop = bind_rows(
  pop,
  pop_future
)

#join
d = inner_join(
  fert %>% filter(Year == 2022) %>% df_legalize_names() %>% select(-Entity) %>% rename(ISO = Code),
  NIQ2 %>% df_legalize_names() %>% select(ISO, IQ_6datasets)
) %>% 
  mutate(
    name = pu_translate(ISO, reverse = T)
  ) %>% 
  rename(
    IQ = IQ_6datasets,
    fertility = Fertility_rate_Sex_all_Age_all_Variant_estimates
  )
## Joining with `by = join_by(ISO)`
#mean world IQ by year
pop_long = inner_join(
  pop,
  NIQ2 %>% df_legalize_names() %>% select(ISO, IQ_6datasets)
)
## Joining with `by = join_by(ISO)`
world_mean = pop_long %>%
  group_by(Year) %>%
  summarise(
    world_mean_IQ = wtd_mean(IQ_6datasets, Population)
  )

Analysis

#fertility vs IQ
GG_scatter(d, "IQ", "fertility", case_names = "name") +
  geom_smooth() +
  scale_x_continuous(breaks = seq(0, 200, 5)) +
  scale_y_continuous(breaks = seq(0, 10, 0.5)) +
  labs(
    x = "National IQ (6 dataset average)",
    y = "Fertility rate (2022, UN)",
    title = "National IQ and fertility rate"
  )
## `geom_smooth()` using formula = 'y ~ x'
## `geom_smooth()` using method = 'loess' and formula = 'y ~ x'

GG_save("figures/IQ_fertility.png")
## `geom_smooth()` using formula = 'y ~ x'
## `geom_smooth()` using method = 'loess' and formula = 'y ~ x'
#test for heteroscedasticity
d$resid_spline = mgcv::gam(fertility ~ s(IQ), data = d) %>% resid()
test_HS(resid = d$resid_spline, d$IQ)
## number of knots in rcs defaulting to 5
## number of knots in rcs defaulting to 5
#world IQ decline
world_mean %>% 
  ggplot(aes(x = Year, y = world_mean_IQ, linetype = Year > 2023)) +
  geom_line() +
  geom_vline(xintercept = 2023, linetype = 2) +
  labs(
    x = "Year",
    y = "World mean IQ",
    title = "World mean IQ by year",
    linetype = "Forecast"
  )

GG_save("figures/world_mean_IQ.png")

Meta

#versions
write_sessioninfo()
## R version 4.4.2 (2024-10-31)
## Platform: x86_64-pc-linux-gnu
## Running under: Linux Mint 21.1
## 
## Matrix products: default
## BLAS:   /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.10.0 
## LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.10.0
## 
## locale:
##  [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
##  [3] LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
##  [5] LC_MONETARY=en_DK.UTF-8    LC_MESSAGES=en_US.UTF-8   
##  [7] LC_PAPER=en_DK.UTF-8       LC_NAME=C                 
##  [9] LC_ADDRESS=C               LC_TELEPHONE=C            
## [11] LC_MEASUREMENT=en_DK.UTF-8 LC_IDENTIFICATION=C       
## 
## time zone: Europe/Brussels
## tzcode source: system (glibc)
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
##  [1] googlesheets4_1.1.1   readxl_1.4.3          haven_2.5.4          
##  [4] kirkegaard_2025-01-08 psych_2.4.6.26        assertthat_0.2.1     
##  [7] weights_1.0.4         Hmisc_5.1-3           magrittr_2.0.3       
## [10] lubridate_1.9.3       forcats_1.0.0         stringr_1.5.1        
## [13] dplyr_1.1.4           purrr_1.0.2           readr_2.1.5          
## [16] tidyr_1.3.1           tibble_3.2.1          ggplot2_3.5.1        
## [19] tidyverse_2.0.0      
## 
## loaded via a namespace (and not attached):
##   [1] mnormt_2.1.1       gridExtra_2.3      sandwich_3.1-0    
##   [4] rlang_1.1.4        multcomp_1.4-26    polspline_1.1.25  
##   [7] compiler_4.4.2     mgcv_1.9-1         gdata_3.0.0       
##  [10] systemfonts_1.1.0  vctrs_0.6.5        quantreg_5.98     
##  [13] pkgconfig_2.0.3    shape_1.4.6.1      crayon_1.5.3      
##  [16] fastmap_1.2.0      backports_1.5.0    labeling_0.4.3    
##  [19] utf8_1.2.4         rmarkdown_2.28     tzdb_0.4.0        
##  [22] nloptr_2.1.1       ragg_1.3.2         MatrixModels_0.5-3
##  [25] bit_4.0.5          xfun_0.47          glmnet_4.1-8      
##  [28] jomo_2.7-6         cachem_1.1.0       jsonlite_1.8.8    
##  [31] highr_0.11         pan_1.9            broom_1.0.6       
##  [34] parallel_4.4.2     cluster_2.1.8      R6_2.5.1          
##  [37] bslib_0.8.0        stringi_1.8.4      boot_1.3-31       
##  [40] rpart_4.1.23       jquerylib_0.1.4    cellranger_1.1.0  
##  [43] Rcpp_1.0.13        iterators_1.0.14   knitr_1.48        
##  [46] zoo_1.8-12         base64enc_0.1-3    Matrix_1.7-1      
##  [49] splines_4.4.2      nnet_7.3-19        timechange_0.3.0  
##  [52] tidyselect_1.2.1   rstudioapi_0.16.0  yaml_2.3.10       
##  [55] codetools_0.2-19   curl_5.2.2         lattice_0.22-5    
##  [58] withr_3.0.1        evaluate_0.24.0    foreign_0.8-87    
##  [61] survival_3.7-0     pillar_1.9.0       mice_3.16.0       
##  [64] checkmate_2.3.2    foreach_1.5.2      generics_0.1.3    
##  [67] vroom_1.6.5        hms_1.1.3          munsell_0.5.1     
##  [70] scales_1.3.0       minqa_1.2.8        gtools_3.9.5      
##  [73] glue_1.7.0         rms_6.8-2          tools_4.4.2       
##  [76] data.table_1.16.0  SparseM_1.84-2     lme4_1.1-35.5     
##  [79] mvtnorm_1.2-6      fs_1.6.4           grid_4.4.2        
##  [82] colorspace_2.1-1   nlme_3.1-166       htmlTable_2.4.3   
##  [85] googledrive_2.1.1  Formula_1.2-5      cli_3.6.3         
##  [88] textshaping_0.4.0  fansi_1.0.6        gargle_1.5.2      
##  [91] gtable_0.3.5       sass_0.4.9         digest_0.6.37     
##  [94] TH.data_1.1-2      htmlwidgets_1.6.4  farver_2.1.2      
##  [97] htmltools_0.5.8.1  lifecycle_1.0.4    httr_1.4.7        
## [100] mitml_0.4-5        bit64_4.0.5        MASS_7.3-61