--- title: "Countries, regions and currency" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Countries, regions and currency} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) ``` ```{r setup} library(ezrsurvey) ``` Two columns make a multi-country study harder than a single-market one. The country question is usually free text, so it comes back holding every spelling a person can produce. And if respondents answered about money in their own currency, the amounts column cannot be averaged at all. ## The country column people typed On one real open salary survey of 26,232 people, nine thousand wrote "United States", eight thousand wrote "USA", two and a half thousand wrote "US", and several hundred more wrote "U.S.", "Usa" or "usa". Matching on the name as typed resolved about half the column. `recode_region()` folds the answer down before looking it up. Case, punctuation, accents and a leading "the" all stop mattering, and then a table of the spellings people actually use is tried. ```{r} recode_region(c("United States", "USA", "U.S.", "Estados Unidos")) ``` It carries the constituent countries of the United Kingdom, which a UK respondent is as likely to write as the country itself: ```{r} recode_region(c("England", "Scotland", "Wales", "Northern Ireland")) ``` Endonyms, because a survey fielded in more than one language collects them: ```{r} recode_region(c("Deutschland", "Brasil", "Espana", "Osterreich")) ``` And the official ISO 3166-1 names, which is what a questionnaire built on the standard puts in front of a respondent, in either word order: ```{r} recode_region(c("Viet Nam", "Syrian Arab Republic", "Republic of Moldova", "Cabo Verde", "Eswatini")) ``` The fold is done letter by letter rather than left to the platform's transliteration, so a name carrying an accent matches the same way on Windows, macOS and Linux: ```{r} recode_region(c("Côte d'Ivoire", "Réunion", "Türkiye")) ``` ## Adding the column `add_region()` does the same thing to a data frame, and `subregion = TRUE` adds the finer grouping alongside: ```{r} survey <- add_region(podracing_survey, demo_country, subregion = TRUE) calc_percentage(survey, region, sort = "desc") ``` ```{r} calc_percentage(survey, subregion, sort = "desc") ``` Anything that did not match comes back `NA` with a warning naming the values, because at that point what is left is genuine typos worth seeing rather than spellings worth supporting. ## Reporting against the standard A client who consolidates research across agencies wants countries coded to ISO 3166-1, not to whatever names this analyst happened to pick. A column already coded that way needs no preparation: ```{r} recode_region(c("US", "GBR", "DE", "JPN", "AUS")) ``` A two-letter code that is also an ordinary English word is only read as a country when it was typed in capitals, so `"NO"` is Norway and `"no"` is somebody answering a different question: ```{r} recode_region(c("NO", "no"), quiet = TRUE) ``` The bundled table carries both codes, so a country name can be replaced by its code on the way out. That is the table to join to, because country names differ between sources and codes do not: ```{r} head(country_region) ``` ```{r} survey %>% dplyr::left_join(dplyr::select(country_region, country, iso2, iso3), by = c("demo_country" = "country")) %>% dplyr::count(iso3, region, sort = TRUE) %>% head(8) ``` > Namibia's alpha-2 code is the two letters `NA`, not a missing value. It is > worth knowing before filtering that column, and before reading a country > file with anything other than `na.strings = ""`. The regions themselves follow the UN M49 sub-regions with two deliberate departures, because they are how consumer research buys these markets: the Middle East is a region of its own rather than part of Asia and Africa, and the Americas are split north and south. ## Money in eleven currencies A single amount converts with `convert_currency()`: ```{r} convert_currency(50000, from = "GBP", to = "USD") convert_currency(c(50000, 60000), from = c("EUR", "CAD"), to = "USD") ``` A whole column converts with `add_currency()`, which takes the currency from a second column, so each row is converted at its own rate: ```{r} pay <- tibble::tibble( respondent = 1:5, salary = c(52000, 61000, 48000, 75000, 39000), currency = c("GBP", "EUR", "USD", "CAD", "AUD") ) add_currency(pay, salary, from = currency, to = "EUR", into = "salary_eur") ``` The rates are bundled rather than fetched, so a figure computed today is the same figure next year. That is what a published number needs, and it is also why they are a dated snapshot rather than live rates. ```{r} head(list_currencies()) ``` When accuracy matters more than reproducibility, pass your own: ```{r} own_rates <- c(USD = 1, GBP = 0.79, EUR = 0.92) convert_currency(50000, from = "GBP", to = "EUR", rates = own_rates) ``` A code the table does not hold is reported rather than guessed at. Real currency columns contain things like `"AUD/NZD"` and `"Other"`, and those rows come back `NA` with a warning naming the codes.