Research Question: Which metro areas have the fastest growing populations, and which of those areas have the highest median household income?

According to the United States Census Bureau, the population of the United States has been increasingly concentrated in our metropolitan areas, instead of our rural and suburban communities. What might be motivating our residents to move to the cities? Many people across the country move in pursuit of better jobs and incomes–is there a relationship between the areas with increasing populations, and areas with high median household incomes? This dataset compiles information from metro areas across the United States. This data was compiled by the Maryland Department of Commerce. I will use the columns Population.Change..2000.2010…“,”Metro”, and “Median.Household.Income….Dollars”

Source: Erickson, Matt, and Lindsay Spell. “Population Gains in Metro Areas Driven Largely by Growth in the Exurbs This Decade — with Some Exceptions.” United States Census Bureau, www.census.gov/library/stories/2026/05/major-city-outer-edge-growth.html. Accessed 24 July 2026.

install.packages("tidyverse")
## Installing package into '/cloud/lib/x86_64-pc-linux-gnu-library/4.6'
## (as 'lib' is unspecified)
install.packages("dplyr")
## Installing package into '/cloud/lib/x86_64-pc-linux-gnu-library/4.6'
## (as 'lib' is unspecified)
install.packages("readr")
## Installing package into '/cloud/lib/x86_64-pc-linux-gnu-library/4.6'
## (as 'lib' is unspecified)
library(tidyr)
library(dplyr)
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(readr)
#Import the Dataset
metro <- read_csv("Project1Metro.csv")
## Rows: 54 Columns: 8
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (8): Metro, Total Population, 2018, Total Population, 2010, Total Popula...
## 
## ℹ 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.
metro <- data.frame(metro)

Data Cleaning

I am going to explore my dataset and prepare it for cleaning.

head(metro)
##              Metro Total.Population..2018 Total.Population..2010
## 1    Atlanta metro                5949951                5268860
## 2 Austin, TX metro                2168316                1716289
## 3  Baltimore metro                2802789                2710489
## 4 Birmingham metro                1151801                1128047
## 5     Boston metro                4875390                4552402
## 6    Buffalo metro                1130152                1135509
##   Total.Population..2000 Population.Change..2000.2010....
## 1                4247981                               24
## 2                1249763                             37.3
## 3                2552994                              6.2
## 4                1052238                              7.2
## 5                4391344                              3.7
## 6                1170111                               -3
##   Per.Capita.Personal.Income....Dollars. Median.Household.Income....Dollars.
## 1                                  52473                               69464
## 2                                  58773                               76925
## 3                                  62402                               80469
## 4                                  50979                               56409
## 5                                  78694                               88711
## 6                                  50414                               56195
##   Total.Personal.Income....Millions.
## 1                           312213.5
## 2                           127439.2
## 3                           174900.9
## 4                            55469.3
## 5                           383664.5
## 6                              56976
str(metro)
## 'data.frame':    54 obs. of  8 variables:
##  $ Metro                                 : chr  "Atlanta metro" "Austin, TX metro" "Baltimore metro" "Birmingham metro" ...
##  $ Total.Population..2018                : chr  "5949951" "2168316" "2802789" "1151801" ...
##  $ Total.Population..2010                : chr  "5268860" "1716289" "2710489" "1128047" ...
##  $ Total.Population..2000                : chr  "4247981" "1249763" "2552994" "1052238" ...
##  $ Population.Change..2000.2010....      : chr  "24" "37.3" "6.2" "7.2" ...
##  $ Per.Capita.Personal.Income....Dollars.: chr  "52473" "58773" "62402" "50979" ...
##  $ Median.Household.Income....Dollars.   : chr  "69464" "76925" "80469" "56409" ...
##  $ Total.Personal.Income....Millions.    : chr  "312213.5" "127439.2" "174900.9" "55469.3" ...

I can see using (str) that these are saved as character data instead of integer or dbl, so we’re going to re-class these categories. The names of the columns are also rather long so I’m going to shorten them. I’m also going to subset the data so I’m only working with what I need to.

metroclean <- metro %>% rename( Popchange = Population.Change..2000.2010....,
                                Medianincome = Median.Household.Income....Dollars.)

metroclean <- metroclean %>% select(Metro,Popchange,Medianincome)

metroclean$Popchange <- as.numeric(metroclean$Popchange)
## Warning: NAs introduced by coercion
metroclean$Medianincome <- as.numeric(metroclean$Medianincome)
## Warning: NAs introduced by coercion
class(metroclean$Popchange)
## [1] "numeric"
class(metroclean$Medianincome)
## [1] "numeric"
summary(metroclean)
##        Metro      Popchange       Medianincome   
##  Length   :54   Min.   :-11.30   Min.   : 50301  
##  N.unique :54   1st Qu.:  4.95   1st Qu.: 59842  
##  N.blank  : 0   Median : 11.00   Median : 65638  
##  Min.nchar: 4   Mean   : 13.22   Mean   : 69225  
##  Max.nchar:30   3rd Qu.: 19.75   3rd Qu.: 75490  
##                 Max.   : 41.80   Max.   :124696  
##                 NAs    :4        NAs    :4

There are some rows of data that are NA, so I’m going to remove the NA rows from the dataset. In the summary, I also see that theres a large range between the 3rd and 4th quartiles for my two variables. I’m interested to see if the metro area with the maximum population change also has the highest median income.

metroclean <- metroclean %>% filter(!is.na(Popchange))

Now I have a dataset with the columns in the classes I need, and the NAs are removed.

Data Analysis

metroclean <- metroclean %>% arrange(Popchange)
metroclean2 <- metroclean %>% filter(Popchange >= 20 )
metroclean2$Metro <- gsub("metro", "", metroclean2$Metro)

Of the 50 observations, 12 have a higher population growth of over 20%–we’re going to focus on areas with positive population growth so we’ll remove the rows with negative population growth so they don’t clutter our final visualization. We will also make the labels for the metro areas more brief by using gsub and removing the word “metro” in the observations.

summary(metroclean2)
##        Metro      Popchange      Medianincome  
##  Length   :12   Min.   :21.20   Min.   :57076  
##  N.unique :12   1st Qu.:24.90   1st Qu.:61204  
##  N.blank  : 0   Median :29.35   Median :65532  
##  Min.nchar: 7   Mean   :30.12   Mean   :65629  
##  Max.nchar:25   3rd Qu.:33.40   3rd Qu.:69450  
##                 Max.   :41.80   Max.   :76925

Looking through our latest subset, we use the summary function to get a snapshot of the top growing 12 metro areas. I notice that the max for the median income has changed by almost $40,000 from our previous summary, and the differences between quartiles is much less dramatic.

install.packages("ggplot2")
## Installing package into '/cloud/lib/x86_64-pc-linux-gnu-library/4.6'
## (as 'lib' is unspecified)
library(ggplot2)

metrograph <- metroclean2 %>% ggplot(aes(Medianincome,Popchange, labels = Metro))+
  geom_point(size = 0.5, color = "blue")+
  geom_text(size=3, hjust = -0.05 )+
  xlim(50000,90000)+
  xlab("Median Household Income ($)")+
  ylab("Population Change (Percent %)")+
  ggtitle("Which Metro Areas are Affluent and Growing?")+
  theme_minimal()

  
metrograph

### Conclusion We find that the fastest growing metro areas in the country are overwhelmingly in the South and Southwest. There is no Midwestern or New England metro areas included in our graph. Additionally, the fastest growing cities, Las Vegas and Raleigh have a large gap in median income, almost a $20,000 different. This raises questions for further research–how does cost of living impact the residents of these areas? Does lower income mean a poorer quality of living? Are there other factors, such as local infrastructure, the housing market, accessibility to nature, or certain industries the big draw to these areas? This analysis indicates that anyone who wants to live in a rapidly growing city with a high household income should consider Raleigh, or Austin as their new metro areas to live.