Getting started with psgc

What is the PSGC?

The Philippine Standard Geographic Code (PSGC) is the official list of every geographic area in the Philippines — from the broadest (regions) down to the most granular (barangays). It is published and maintained by the Philippine Statistics Authority (PSA).

Each area is identified by a unique 10-digit code and a geographic level:

Level Description Example
Reg Region Region I – Ilocos Region
Prov Province Ilocos Norte
City City Laoag City
Mun Municipality Bacarra
SubMun Sub-municipality (Metro Manila component cities)
Bgy Barangay Brgy. 1, Laoag City

The PSA releases updated PSGC files several times a year as new cities are chartered, barangays are created, or codes are renumbered. This package bundles 12 releases from Q1 2023 through Q1 2026.


Checking available releases

list_releases()
#>  [1] "Q1_2023"    "Q4_2023"    "April_2024" "Q2_2024"    "Q3_2024"   
#>  [6] "Q4_2024"    "Q1_2025"    "Q2_2025"    "July_2025"  "Q3_2025"   
#> [11] "Q4_2025"    "Q1_2026"    "Q2_2026"
latest_release()
#> [1] "Q2_2026"

By default, every function in this package uses the latest release. You can always pass a specific release name to work with older data.


Getting the full PSGC list

get_psgc() returns the complete list of geographic areas for a given release.

ph <- get_psgc()
nrow(ph)
#> [1] 43768
head(ph)
#>    psgc_code                    area_name correspondence_code geographic_level
#> 1 0100000000     Region I (Ilocos Region)           010000000              Reg
#> 2 1000000000 Region X (Northern Mindanao)           100000000              Reg
#> 3 1001300000                     Bukidnon           101300000             Prov
#> 4 1001301000                      Baungon           101301000              Mun
#> 5 1001301001                     Balintad           101301001              Bgy
#> 6 1001301002                   Buenavista           101301002              Bgy
#>   old_name city_class income_classification urban_rural island_region
#> 1     <NA>       <NA>                  <NA>        <NA>             L
#> 2     <NA>       <NA>                  <NA>        <NA>             M
#> 3     <NA>       <NA>                   1st        <NA>             M
#> 4     <NA>       <NA>                   1st        <NA>             M
#> 5     <NA>       <NA>                  <NA>           R             M
#> 6     <NA>       <NA>                  <NA>           R             M

Filter by geographic level

You do not need to remember the exact code names — plain English works too:

regions <- get_psgc(geographic_level = "Region")
regions[, c("psgc_code", "area_name")]
#>        psgc_code                                               area_name
#> 1     0100000000                                Region I (Ilocos Region)
#> 2     1000000000                            Region X (Northern Mindanao)
#> 5519  1100000000                                Region XI (Davao Region)
#> 6736  1200000000                               Region XII (SOCCSKSARGEN)
#> 7887  1300000000                           National Capital Region (NCR)
#> 9634  1400000000                  Cordillera Administrative Region (CAR)
#> 10896 1600000000                                    Region XIII (Caraga)
#> 12287 1700000000                                         MIMAROPA Region
#> 13826 1800000000                              Negros Island Region (NIR)
#> 15246 1900000000 Bangsamoro Autonomous Region In Muslim Mindanao (BARMM)
#> 17546 0200000000                              Region II (Cagayan Valley)
#> 19956 0300000000                              Region III (Central Luzon)
#> 23199 0400000000                                Region IV-A (CALABARZON)
#> 27339 0500000000                                 Region V (Bicol Region)
#> 30931 0600000000                             Region VI (Western Visayas)
#> 34427 0700000000                            Region VII (Central Visayas)
#> 36843 0800000000                           Region VIII (Eastern Visayas)
#> 41358 0900000000                         Region IX (Zamboanga Peninsula)
provinces <- get_psgc(geographic_level = "Province")
nrow(provinces)
#> [1] 82
head(provinces[, c("psgc_code", "area_name")])
#>       psgc_code          area_name
#> 3    1001300000           Bukidnon
#> 490  1001800000           Camiguin
#> 554  1003500000    Lanao del Norte
#> 1039 1004200000 Misamis Occidental
#> 1547 1004300000   Misamis Oriental
#> 1997 0102800000       Ilocos Norte

You can filter for multiple levels at once by passing a vector:

city_mun <- get_psgc(geographic_level = c("City", "Municipality"))
nrow(city_mun)
#> [1] 1642

There is also a convenient shorthand, "city_mun", that does the same thing:

nrow(get_psgc(geographic_level = "city_mun"))
#> [1] 1642

Using a specific release

ph_2023 <- get_psgc("Q1_2023")
nrow(ph_2023)
#> [1] 43784

Looking up a specific code

If you already have a PSGC code and want its details, use psgc_info().

psgc_info("0100000000") # Region I
#>    psgc_code                area_name correspondence_code geographic_level
#> 1 0100000000 Region I (Ilocos Region)           010000000              Reg
#>   old_name city_class income_classification urban_rural island_region release
#> 1     <NA>       <NA>                  <NA>        <NA>             L Q2_2026

You can look up multiple codes at once:

psgc_info(c("0100000000", "0102800000"))
#>       psgc_code                area_name correspondence_code geographic_level
#> 1    0100000000 Region I (Ilocos Region)           010000000              Reg
#> 1997 0102800000             Ilocos Norte           012800000             Prov
#>      old_name city_class income_classification urban_rural island_region
#> 1        <NA>       <NA>                  <NA>        <NA>             L
#> 1997     <NA>       <NA>                   1st        <NA>             L
#>      release
#> 1    Q2_2026
#> 1997 Q2_2026

Short codes are accepted — the package pads the rest with trailing zeros, so you only need to provide enough digits to identify the area:

psgc_info("01")      # same as "0100000000" — Region I
#>    psgc_code                area_name correspondence_code geographic_level
#> 1 0100000000 Region I (Ilocos Region)           010000000              Reg
#>   old_name city_class income_classification urban_rural island_region release
#> 1     <NA>       <NA>                  <NA>        <NA>             L Q2_2026
psgc_info("01028")  # same as "0102800000" — Ilocos Norte
#>       psgc_code    area_name correspondence_code geographic_level old_name
#> 1997 0102800000 Ilocos Norte           012800000             Prov     <NA>
#>      city_class income_classification urban_rural island_region release
#> 1997       <NA>                   1st        <NA>             L Q2_2026

Population data

get_population() returns PSA census figures (2015, 2020, 2024) for all geographic areas in a release.

pop <- get_population()
head(pop)
#>    psgc_code year population
#> 1 1000000000 2015    4689302
#> 2 1000000000 2020    5022768
#> 3 1000000000 2024    5178326
#> 4 1001300000 2015    1415226
#> 5 1001300000 2020    1541308
#> 6 1001300000 2024    1601902

Add area names and geographic levels

Set details = TRUE to include the area name and level alongside the numbers:

pop_detailed <- get_population(details = TRUE)
head(pop_detailed)
#>    psgc_code                    area_name geographic_level year population
#> 1 1000000000 Region X (Northern Mindanao)              Reg 2015    4689302
#> 2 1000000000 Region X (Northern Mindanao)              Reg 2020    5022768
#> 3 1000000000 Region X (Northern Mindanao)              Reg 2024    5178326
#> 4 1001300000                     Bukidnon             Prov 2015    1415226
#> 5 1001300000                     Bukidnon             Prov 2020    1541308
#> 6 1001300000                     Bukidnon             Prov 2024    1601902

Filter by geographic level

Same aliases as get_psgc() work here too:

region_pop <- get_population(geographic_level = "Region", details = TRUE)
region_pop
#>     psgc_code                                               area_name
#> 1  1000000000                            Region X (Northern Mindanao)
#> 2  1000000000                            Region X (Northern Mindanao)
#> 3  1000000000                            Region X (Northern Mindanao)
#> 4  1100000000                                Region XI (Davao Region)
#> 5  1100000000                                Region XI (Davao Region)
#> 6  1100000000                                Region XI (Davao Region)
#> 7  1200000000                               Region XII (SOCCSKSARGEN)
#> 8  1200000000                               Region XII (SOCCSKSARGEN)
#> 9  1200000000                               Region XII (SOCCSKSARGEN)
#> 10 1300000000                           National Capital Region (NCR)
#> 11 1300000000                           National Capital Region (NCR)
#> 12 1300000000                           National Capital Region (NCR)
#> 13 1400000000                  Cordillera Administrative Region (CAR)
#> 14 1400000000                  Cordillera Administrative Region (CAR)
#> 15 1400000000                  Cordillera Administrative Region (CAR)
#> 16 1600000000                                    Region XIII (Caraga)
#> 17 1600000000                                    Region XIII (Caraga)
#> 18 1600000000                                    Region XIII (Caraga)
#> 19 1700000000                                         MIMAROPA Region
#> 20 1700000000                                         MIMAROPA Region
#> 21 1700000000                                         MIMAROPA Region
#> 22 1800000000                              Negros Island Region (NIR)
#> 23 1900000000 Bangsamoro Autonomous Region In Muslim Mindanao (BARMM)
#> 24 1900000000 Bangsamoro Autonomous Region In Muslim Mindanao (BARMM)
#> 25 1900000000 Bangsamoro Autonomous Region In Muslim Mindanao (BARMM)
#>    geographic_level year population
#> 1               Reg 2015    4689302
#> 2               Reg 2020    5022768
#> 3               Reg 2024    5178326
#> 4               Reg 2015    4893318
#> 5               Reg 2020    5243536
#> 6               Reg 2024    5389422
#> 7               Reg 2015    4545276
#> 8               Reg 2020    4901486
#> 9               Reg 2024    4462776
#> 10              Reg 2015   12877253
#> 11              Reg 2020   13484462
#> 12              Reg 2024   14001751
#> 13              Reg 2015    1722006
#> 14              Reg 2020    1797660
#> 15              Reg 2024    1808985
#> 16              Reg 2015    2596709
#> 17              Reg 2020    2804788
#> 18              Reg 2024    2865196
#> 19              Reg 2015    2963360
#> 20              Reg 2020    3228558
#> 21              Reg 2024    3245446
#> 22              Reg 2024    4904944
#> 23              Reg 2015    3781387
#> 24              Reg 2020    4404288
#> 25              Reg 2024    4545486

Wide format — one row per area

Set wide = TRUE to get each census year as its own column, making it easy to compare figures side by side or feed into a table or chart:

region_pop_wide <- get_population(
  geographic_level = "Region",
  details          = TRUE,
  wide             = TRUE
)
region_pop_wide
#>    psgc_code                                               area_name
#> 1 1000000000                            Region X (Northern Mindanao)
#> 2 1100000000                                Region XI (Davao Region)
#> 3 1200000000                               Region XII (SOCCSKSARGEN)
#> 4 1300000000                           National Capital Region (NCR)
#> 5 1400000000                  Cordillera Administrative Region (CAR)
#> 6 1600000000                                    Region XIII (Caraga)
#> 7 1700000000                                         MIMAROPA Region
#> 8 1800000000                              Negros Island Region (NIR)
#> 9 1900000000 Bangsamoro Autonomous Region In Muslim Mindanao (BARMM)
#>   geographic_level population_2015 population_2020 population_2024
#> 1              Reg         4689302         5022768         5178326
#> 2              Reg         4893318         5243536         5389422
#> 3              Reg         4545276         4901486         4462776
#> 4              Reg        12877253        13484462        14001751
#> 5              Reg         1722006         1797660         1808985
#> 6              Reg         2596709         2804788         2865196
#> 7              Reg         2963360         3228558         3245446
#> 8              Reg              NA              NA         4904944
#> 9              Reg         3781387         4404288         4545486

Attach population data to the PSGC list

If you want population figures alongside the main PSGC table (rather than as a separate data frame), use include_population_data = TRUE in get_psgc(). This adds a population_data list-column — each cell is a small data frame with population and year:

regions_with_pop <- get_psgc(
  geographic_level       = "Region",
  include_population_data = TRUE
)

# Inspect the population data for the first region
regions_with_pop$population_data[[1]]
#> [1] population year      
#> <0 rows> (or 0-length row.names)

Tracking codes across releases

The PSA occasionally renumbers or abolishes areas between releases. map_psgc() traces a code forward to any later release so you can keep longitudinal datasets consistent.

map_psgc("0100000000")  # forward to the latest release
#>     old_code   new_code mapping_type from_release to_release
#> 1 0100000000 0100000000       direct      Q1_2023    Q2_2026
map_psgc("0100000000", to = "Q4_2023")
#>     old_code   new_code mapping_type from_release to_release
#> 1 0100000000 0100000000       direct      Q1_2023    Q4_2023

The mapping_type column tells you what happened to the code:

Type Meaning
direct Code is unchanged
renumbered Code was assigned a new number
split One area was divided into multiple areas
merged Multiple areas were merged into one
abolished Area no longer exists (new_code will be NA)

This is especially useful when joining PSGC-coded survey data from different years — use map_psgc() first to normalise all codes to a single release before merging.