Data 607 Project 2: Data Transformation

Author

Renee Watson

Published

October 12, 2026

Approach

For this project, I selected three datasets to practice transforming data from wide to tidy format using R. The datasets include simulated monthly patient visits for 15 community health clinics, fictional housing prices across the five New York City boroughs, and life expectancy data from the World Bank. These datasets provide an opportunity to work with different types of data and explore trends in healthcare utilization, housing, and public health. My plan is to import each dataset into R and examine its structure. I will use functions from tidyr and dplyr, to reshape the dataset into tidy format. I will also check for missing values, duplicate records, and inconsistencies in variable types. One challenge I anticipate is handling differences in how the datasets are organized. I will need to identify the appropriate columns to transform and ensure that the resulting variables have the correct data types. After cleaning and transforming the datasets, I plan to perform exploratory data analysis using descriptive statistics and visualizations. I will examine monthly patient visit trends, compare housing values across NYC boroughs, and explore changes in life expectancy across selected countries from 2015 to 2024.

Data Sources: Dataset 1: Community Health Clinic Visits - Simulated monthly patient visit data for 15 community health clinics during 2025 Dataset 2: NYC Housing Prices by Borough - Fictional housing data for the five NYC boroughs from 2024 to 2025, from dicussion board Dataset 3: World Bank Life Expectancy at birth, total(years) - https://data.worldbank.org/indicator/SP.DYN.LE00.IN?name_desc=false

Code
library(tidyr)
library(dplyr)
library(ggplot2)
library(readr)
library(stringr)

Dataset 1: Community health clinic visits

This dataset contains simulated monthly patient visit counts for community health clinics during 2025. The purpose of this analysis is to examine how patient visits vary across clinics and months. The original dataset is in wide format, with each month represented by a separate column.

Data Import and Tidying

Code
clinic_wide <- read_csv("data/community_clinic_visits_wide.csv", show_col_types = FALSE)
dim(clinic_wide)
[1] 15 14
Code
names(clinic_wide)
 [1] "Clinic_ID"   "Clinic_Name" "Jan"         "Feb"         "Mar"        
 [6] "Apr"         "May"         "Jun"         "Jul"         "Aug"        
[11] "Sep"         "Oct"         "Nov"         "Dec"        
Code
head(clinic_wide)
# A tibble: 6 × 14
  Clinic_ID Clinic_Name      Jan   Feb   Mar   Apr   May   Jun   Jul   Aug   Sep
  <chr>     <chr>          <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 C001      Harbor Commun…   245   231   260   278   290   301   315   309   287
2 C002      Riverside Fam…   190   205   198   220   235   241   250   263   255
3 C003      Central Commu…   310   298   325   340   355   348   370   365   380
4 C004      Eastside Fami…   155   162   170   168   180   195   201   210   205
5 C005      Westview Comm…   270   265   280   295   310   320   318   330   342
6 C006      Northside Hea…   225   218   240   251   260   272   280   275   290
# ℹ 3 more variables: Oct <dbl>, Nov <dbl>, Dec <dbl>

The original dataset contains 15 rows and 14 columns. Each row represents one community health clinic, while the columns include clinic ID, clinic name, and monthly patient visit counts from January through December 2025.

Transformation

Code
clinic_tidy <- clinic_wide %>%
  pivot_longer(
    cols = Jan:Dec,
    names_to = "month",
    values_to = "patient_visits"
  ) %>%
  rename(clinic_id = Clinic_ID, clinic_name = Clinic_Name) %>%
  mutate(
    month = factor(month, levels = month.abb, ordered = TRUE),
    patient_visits = as.numeric(patient_visits)
  )

head(clinic_tidy)
# A tibble: 6 × 4
  clinic_id clinic_name                    month patient_visits
  <chr>     <chr>                          <ord>          <dbl>
1 C001      Harbor Community Health Center Jan              245
2 C001      Harbor Community Health Center Feb              231
3 C001      Harbor Community Health Center Mar              260
4 C001      Harbor Community Health Center Apr              278
5 C001      Harbor Community Health Center May              290
6 C001      Harbor Community Health Center Jun              301
Code
dim(clinic_tidy)
[1] 180   4

The original dataset contained 15 clinics with monthly patient visits stored in 12 separate columns. I used pivot_longer() to convert these columns into two variables: month and patient visits. I then renamed the clinic identifier variables using lowercase names for consistency and converted the month variable into an ordered factor to preserve chronological order. The resulting dataset contains 180 observations and four variables, with each row representing one clinic in one month.

Code
colSums(is.na(clinic_tidy))
     clinic_id    clinic_name          month patient_visits 
             0              0              0              0 
Code
clinic_tidy %>%
  filter(is.na(patient_visits))
# A tibble: 0 × 4
# ℹ 4 variables: clinic_id <chr>, clinic_name <chr>, month <ord>,
#   patient_visits <dbl>
Code
clinic_tidy %>%
  count(clinic_id, month) %>%
  filter(n >1)
# A tibble: 0 × 3
# ℹ 3 variables: clinic_id <chr>, month <ord>, n <int>
Code
clinic_tidy %>% 
  filter(patient_visits < 0)
# A tibble: 0 × 4
# ℹ 4 variables: clinic_id <chr>, clinic_name <chr>, month <ord>,
#   patient_visits <dbl>

I checked the dataset for missing values using is.na(). No missing patient visit counts were identified, so no observations needed to be removed or imputed. I also checked for duplicate clinic month records and negative patient visit counts. No duplicate records or invalid negative values were identified. Therefore, all observations were retained for analysis.

Analysis

The analysis used descriptive statistics to examine monthly patient visit trends across the 15 community health clinics. Total and average monthly visits were calculated for each clinic to compare patient visit volumes. Monthly totals were also calculated to examine changes throughout 2025. Finally, the difference between January and December visits was calculated for each clinic to identify which clinics experienced the largest and smallest increases in patient visits.

Patient Visits by Clinic

Code
clinic_summary <- clinic_tidy %>%
  group_by(clinic_name) %>%
  summarise(total_visits = sum(patient_visits, na.rm = TRUE),
            average_monthly_visits = mean(patient_visits, na.rm = TRUE),
            .groups = "drop") %>%
  arrange(desc(total_visits))
clinic_summary
# A tibble: 15 × 3
   clinic_name                      total_visits average_monthly_visits
   <chr>                                   <dbl>                  <dbl>
 1 Metro Family Health Clinic               4507                   376.
 2 Central Community Health Center          4299                   358.
 3 Lakeside Community Clinic                4054                   338.
 4 Oakwood Community Health Center          3942                   328.
 5 Westview Community Health Center         3815                   318.
 6 Maplewood Family Health Center           3567                   297.
 7 Harbor Community Health Center           3446                   287.
 8 Northside Health Clinic                  3229                   269.
 9 Parkview Health Center                   2984                   249.
10 Riverside Family Health Clinic           2875                   240.
11 Sunrise Community Health Clinic          2851                   238.
12 Greenwood Family Health Center           2667                   222.
13 Valley Community Health Center           2633                   219.
14 Hillcrest Community Clinic               2498                   208.
15 Eastside Family Clinic                   2319                   193.

This calculates the total number of patient visits and the average monthly visits for each clinic. The clinics are sorted from highest to lowest total visits.

Change in Patient Visits from January to December

Code
clinic_changes <- clinic_tidy %>%
  group_by(clinic_name) %>%
  summarise(
    january_visits = patient_visits[month == "Jan"],
    december_visits = patient_visits[month == "Dec"],
    change_in_visits = december_visits - january_visits, 
    .groups = "drop"
  ) %>%
  arrange(desc(change_in_visits))

clinic_changes
# A tibble: 15 × 4
   clinic_name                   january_visits december_visits change_in_visits
   <chr>                                  <dbl>           <dbl>            <dbl>
 1 Metro Family Health Clinic               320             440              120
 2 Central Community Health Cen…            310             415              105
 3 Lakeside Community Clinic                290             395              105
 4 Oakwood Community Health Cen…            280             385              105
 5 Westview Community Health Ce…            270             375              105
 6 Maplewood Family Health Cent…            250             350              100
 7 Northside Health Clinic                  225             315               90
 8 Riverside Family Health Clin…            190             280               90
 9 Sunrise Community Health Cli…            195             285               90
10 Valley Community Health Cent…            175             265               90
11 Parkview Health Center                   205             292               87
12 Greenwood Family Health Cent…            180             265               85
13 Hillcrest Community Clinic               165             250               85
14 Harbor Community Health Cent…            245             325               80
15 Eastside Family Clinic                   155             230               75

Visualizations

Code
ggplot(
  monthly_summary, aes(x = month, y = total_visits, group = 1)) +
  geom_line(color = "blue", linewidth = 1) + 
  geom_point(color = "blue", size = 2) + 
  labs(title = "Monthly Patient Visits Across Community Health Clinics, 2025",
       x = "Month",
       y = "Total Patient Visits") +
  theme_minimal()

This line graph illustrates changes in total monthly patient visits across 15 community health clinics during 2025. Each point represents the combined number of visits across all clinics for a particular month. Total visits decreased slightly from 3,455 in January to 3,413 in February before increasing steadily throughout the remainder of the year. December had the highest number of visits at 4,867. Overall, the graph shows an upward trend in monthly patient visits throughout 2025.

Code
ggplot(
  clinic_tidy, aes(x = month, y = patient_visits, color = clinic_name, group = clinic_name)
  ) + 
  geom_line(linewidth = 1) + 
  geom_point(size = 1.5) + 
  labs(
    title = "Monthly Patient Visits by Clinic, 2025", 
    x = "Month",
    y = "Number of Patient Visits",
    color = "Clinic"
  ) + theme_minimal()

This line graph compares monthly patient visits across the 15 community health clinics in 2025. Although patient visit volumes varied between clinics, most showed an overall upward trend throughout 2025, with some monthly fluctuations. Metro Family Health Clinic consistently had the highest number of patient visits, increasing from 320 in January to 440 in December. Eastside Family Clinic had the lowest visit volume, increasing from 155 in January to 230 in December.

Conclusions

The analysis showed an overall increase in patient visits across the 15 community health clinics during 2025. Total monthly visits increased from 3,455 in January to 4,867 in December, with February having the lowest number of visits (3,413). Although there were some monthly fluctuations, patient visit volumes generally increased throughout the year. Metro Family Health Clinic had the highest number of visits (4,507), averaging approximately 376 visits per month. In contrast, Eastside Family Clinic had the lowest total (2,319) averaging approximately 193 visits per month. When comparing January and December, all 15 clinics experienced an increase in patient visits. Metro Family Health Clinic had the largest increase with 120 additional visits, while Eastside Family Clinic had the smallest increase, with 75 additional visits. Overall, the findings suggest a consistent upward trend in patient visit volume across the clinics, although the number of visits varied by location. Since this dataset contains simulated patient visit counts, these findings illustrate how data tidying and analysis can be used to examine healthcare utilization patterns rather than representing actual patient activity.

Dataset 2: New York housing by borough

This dataset was provided by my classmate and contains fictional average housing prices for the five New York City boroughs from January 2024 through December 2025. The purpose of this analysis is to compare average housing prices across boroughs, examine monthly and yearly trends, and identify which boroughs have the highest and lowest prices.

Data Import and Tidying

Code
housing_raw <- read_csv("data/nyc_housing_wide.csv", 
                        skip = 1,
                        show_col_types = FALSE,
                        col_types = cols(.default = col_character()))
nrow(housing_raw)
[1] 24
Code
names(housing_raw)
[1] "Year"          "Month"         "Bronx"         "Brooklyn"     
[5] "Manhattan"     "Queens"        "Staten Island"
Code
head(housing_raw)
# A tibble: 6 × 7
  Year  Month Bronx Brooklyn Manhattan Queens `Staten Island`
  <chr> <chr> <chr> <chr>    <chr>     <chr>  <chr>          
1 2024  Jan   565   948      1,108     650    675            
2 2024  Feb   568   952      1,112     654    678            
3 2024  Mar   572   958      1,118     660    683            
4 2024  Apr   575   965      1,122     663    688            
5 2024  May   579   972      1,128     668    693            
6 2024  Jun   582   978      1,132     671    697            

Transformation

Code
housing_tidy <- housing_raw %>%
  pivot_longer(cols = c(Bronx, Brooklyn, Manhattan, Queens, `Staten Island`),
               names_to = "borough", values_to = "housing_value") %>%
  mutate(
    year = as.integer(Year),
    month = factor(Month, levels = month.abb, ordered = TRUE),
    housing_value = parse_number(housing_value)
  ) %>%
  select(year, month, borough, housing_value)

head(housing_tidy)
# A tibble: 6 × 4
   year month borough       housing_value
  <int> <ord> <chr>                 <dbl>
1  2024 Jan   Bronx                   565
2  2024 Jan   Brooklyn                948
3  2024 Jan   Manhattan              1108
4  2024 Jan   Queens                  650
5  2024 Jan   Staten Island           675
6  2024 Feb   Bronx                   568
Code
dim(housing_tidy)
[1] 120   4

The original dataset contains 24 rows and seven columns, with each row representing a month from 2024 through 2025. I used pivot_longer() to transform the borough columns into two variables: borough and housing value. I also used parse_number() to convert values containing commas into numeric format and converted the year and month variables into appropriate data types. The resulting tidy dataset contains 120 observations and four variables, with each row representing one borough during a particular month and year.

Code
colSums(is.na(housing_tidy))
         year         month       borough housing_value 
            0             0             0             0 
Code
housing_tidy %>%
  count(year, month, borough) %>%
  filter(n > 1)
# A tibble: 0 × 4
# ℹ 4 variables: year <int>, month <ord>, borough <chr>, n <int>
Code
housing_tidy %>%
  filter(housing_value < 0)
# A tibble: 0 × 4
# ℹ 4 variables: year <int>, month <ord>, borough <chr>, housing_value <dbl>

I checked the tidy dataset for missing values, duplicate year-month borough records, and negative housing values. No missing values, duplicate records, or negative values were identified. Therefore, all 120 observations were retained for analysis.

Analysis

The analysis used descriptive statistics to examine housing price patterns across the five NYC boroughs during 2024 and 2025. Average, minimum, and maximum housing prices were calculated for each borough to compare price difference. Average prices were also calculated by year and month to examine changes over time. Finally, the lowest-priced months were identified for each borough to explore when housing prices were relatively lower.

Average Housing Prices by borough

Code
housing_summary <- housing_tidy %>%
  group_by(borough) %>%
  summarise(average_price = mean(housing_value, na.rm = TRUE),
            minimum_price = min(housing_value, na.rm = TRUE),
            maximum_price = max(housing_value, na.rm = TRUE),
            .groups = "drop") %>%
  arrange(desc(average_price))
housing_summary
# A tibble: 5 × 4
  borough       average_price minimum_price maximum_price
  <chr>                 <dbl>         <dbl>         <dbl>
1 Manhattan             1153.          1108          1192
2 Brooklyn              1000.           948          1045
3 Staten Island          714.           675           750
4 Queens                 687.           650           718
5 Bronx                  595.           565           620

I calculated the average, minimum, and maximum housing prices for each borough to compare housing costs across New York City. The boroughs were arranged from highest to lowest average price to identify which areas were the most and least expensive. The results show differences in average housing prices across the five NYC boroughs. Manhattan had the highest average housing price at $1,152.63, followed by Brooklyn at $1,000.08. The Bronx had the lowest average price at $594.63, followed by Queens at $686.83 and Staten Island at $714.50. Manhattan also had the highest maximum price at $1,192, while the Bronx had the lowest minimum price at $565. These findings suggest Manhattan was the most expensive borough and the Bronx was the least expensive during the period examined.

Average Housing Prices by Year and Borough

Code
housing_yearly <- housing_tidy %>%
  group_by(year, borough) %>%
  summarise(
    average_price = mean(housing_value, na.rm = TRUE), 
    .groups = "drop"
  ) %>%
  arrange(borough, year)

housing_yearly
# A tibble: 10 × 3
    year borough       average_price
   <int> <chr>                 <dbl>
 1  2024 Bronx                  581.
 2  2025 Bronx                  609.
 3  2024 Brooklyn               975 
 4  2025 Brooklyn              1025.
 5  2024 Manhattan             1130.
 6  2025 Manhattan             1175.
 7  2024 Queens                 670.
 8  2025 Queens                 704 
 9  2024 Staten Island          696.
10  2025 Staten Island          733.

The yearly analysis compares average housing prices across the five NYC boroughs in 2024 and 2025. The results indicate that average housing prices were higher in 2025 than in 2024 across the boroughs.

Visualizations

Code
ggplot(
  housing_monthly, aes(x = month, 
                       y = average_price, 
                       color = factor(year),
                       group = factor(year)) 
) + 
  geom_line(linewidth = 1) +
  geom_point(size = 2) + 
  labs(
    title = "Monthly Average Housing Price in NYC, 2024 - 2025",
    x = "Month",
    y = "Average Housing Price", 
    color = "Year"
  ) + theme_minimal()

The line graph compares monthly average housing prices across the five NYC boroughs in 2024 and 2025. Average housing prices were consistently higher in 2025 than in 2024. Both years showed an overall upward trend, with slight decreases during certain months. January had the lowest average price in both years at $789.20 in 2024 and $830.20 in 2025. December had the highest average price in both years at $827 in 2024 and $865 in 2025.

Code
ggplot(housing_summary, aes(x = reorder(borough, average_price), y = average_price)) + 
  geom_col(fill = "blue") + 
  coord_flip() + 
  labs(
    title = "Average Housing Prices by NYC Borough, 2024-2025", 
    x = "Borough",
    y = "Average Housing Price"
  ) + theme_minimal()

The bar chart compares average housing prices across the five NYC boroughs during 2024 and 2025. Manhattan had the highest average housing price at $1,152.63, followed by Brooklyn at $1,000.08. The Bronx had the lowest average price at $594.63, followed by Queens at $686.83 and Staten Island at $714.50.

Conclusions

The analysis showed differences in average housing prices across the five NYC boroughs during 2024 and 2025. Manhattan had the highest average housing price at $1,152.63, followed by Brooklyn at $1,000.08, while the Bronx had the lowest average price at $594.63. Average housing prices were consistently higher in 2025 than in 2024. The monthly analysis also showed that January had the lowest average housing prices in both years. Further examination confirmed that January was the lowest-priced month for all five boroughs in 2024 and 2025. These findings indicate that January had the lowest housing values across all five boroughs in the fictional dataset.

Dataset 3: World Bank Life Expectancy at Birth

This dataset was obtained from the World Bank’s World Development Indicators database and contains life expectancy at birth estimates for countries and regional groups from 1960 through 2024. Life expectancy is measured in years. The purpose of this analysis is to examine changes in life expectancy over time and compare patterns across selected countries.

Data Import and Tidying

Code
life_wide <- read_csv("data/API_SP.DYN.LE00.IN_DS2_en_csv_v2_1528.csv",
                      skip = 4, 
                      show_col_types = FALSE)

dim(life_wide)
[1] 266  71
Code
names(life_wide)
 [1] "Country Name"   "Country Code"   "Indicator Name" "Indicator Code"
 [5] "1960"           "1961"           "1962"           "1963"          
 [9] "1964"           "1965"           "1966"           "1967"          
[13] "1968"           "1969"           "1970"           "1971"          
[17] "1972"           "1973"           "1974"           "1975"          
[21] "1976"           "1977"           "1978"           "1979"          
[25] "1980"           "1981"           "1982"           "1983"          
[29] "1984"           "1985"           "1986"           "1987"          
[33] "1988"           "1989"           "1990"           "1991"          
[37] "1992"           "1993"           "1994"           "1995"          
[41] "1996"           "1997"           "1998"           "1999"          
[45] "2000"           "2001"           "2002"           "2003"          
[49] "2004"           "2005"           "2006"           "2007"          
[53] "2008"           "2009"           "2010"           "2011"          
[57] "2012"           "2013"           "2014"           "2015"          
[61] "2016"           "2017"           "2018"           "2019"          
[65] "2020"           "2021"           "2022"           "2023"          
[69] "2024"           "2025"           "...71"         
Code
head(life_wide)
# A tibble: 6 × 71
  `Country Name`  `Country Code` `Indicator Name` `Indicator Code` `1960` `1961`
  <chr>           <chr>          <chr>            <chr>             <dbl>  <dbl>
1 Aruba           ABW            Life expectancy… SP.DYN.LE00.IN     64.0   64.2
2 Africa Eastern… AFE            Life expectancy… SP.DYN.LE00.IN     44.2   44.5
3 Afghanistan     AFG            Life expectancy… SP.DYN.LE00.IN     32.8   33.3
4 Africa Western… AFW            Life expectancy… SP.DYN.LE00.IN     37.8   38.1
5 Angola          AGO            Life expectancy… SP.DYN.LE00.IN     37.9   36.9
6 Albania         ALB            Life expectancy… SP.DYN.LE00.IN     56.4   57.5
# ℹ 65 more variables: `1962` <dbl>, `1963` <dbl>, `1964` <dbl>, `1965` <dbl>,
#   `1966` <dbl>, `1967` <dbl>, `1968` <dbl>, `1969` <dbl>, `1970` <dbl>,
#   `1971` <dbl>, `1972` <dbl>, `1973` <dbl>, `1974` <dbl>, `1975` <dbl>,
#   `1976` <dbl>, `1977` <dbl>, `1978` <dbl>, `1979` <dbl>, `1980` <dbl>,
#   `1981` <dbl>, `1982` <dbl>, `1983` <dbl>, `1984` <dbl>, `1985` <dbl>,
#   `1986` <dbl>, `1987` <dbl>, `1988` <dbl>, `1989` <dbl>, `1990` <dbl>,
#   `1991` <dbl>, `1992` <dbl>, `1993` <dbl>, `1994` <dbl>, `1995` <dbl>, …

Transformation

Code
life_tidy <- life_wide %>%
  filter(`Country Name` %in% c(
    "United States",
    "Canada",
    "Ghana",
    "Japan"
  )) %>%
  pivot_longer(
    cols = `2015`:`2024`,
    names_to = "year",
    values_to = "life_expectancy"
  ) %>%
  rename(
    country = `Country Name`,
    country_code = `Country Code`
  ) %>%
  mutate(
    year = as.integer(year)
  ) %>%
  select(country, country_code, year, life_expectancy)

head(life_tidy)
# A tibble: 6 × 4
  country country_code  year life_expectancy
  <chr>   <chr>        <int>           <dbl>
1 Canada  CAN           2015            81.8
2 Canada  CAN           2016            81.9
3 Canada  CAN           2017            81.8
4 Canada  CAN           2018            81.8
5 Canada  CAN           2019            82.2
6 Canada  CAN           2020            81.5
Code
dim(life_tidy)
[1] 40  4

The original World Bank dataset contains 266 rows and 71 columns, with countries and regional groups represented in rows and individual years represented in separate columns. I selected four countries: the United States, Canada, Ghana, and Japan, and restricted the analysis to 2015 through 2024. I used pivot_longer() to transform the year columns into two variables: year and life expectancy. I also converted the year variable to an integer and renamed the country identifier variables for consistency. The resulting dataset contains 40 observations and four variables, with each row representing one country in a particular year.

Code
colSums(is.na(life_tidy))
        country    country_code            year life_expectancy 
              0               0               0               0 
Code
life_tidy %>%
  count(country, year) %>%
  filter(n >1)
# A tibble: 0 × 3
# ℹ 3 variables: country <chr>, year <int>, n <int>
Code
life_tidy %>%
  filter(life_expectancy <= 0 | life_expectancy > 120)
# A tibble: 0 × 4
# ℹ 4 variables: country <chr>, country_code <chr>, year <int>,
#   life_expectancy <dbl>

After transforming the dataset, I checked for missing values, duplicate country-year observations, and invalid life expectancy values. No issues were identified in the selected observations.

Analysis

I calculated descriptive statistics for each country and compared life expectancy in 2019 and 2024 to examine changes relative to the pre-pandemic period.

Code
life_summary <- life_tidy %>%
  group_by(country) %>%
  summarise(
    mean_life = mean(life_expectancy),
    min_life = min(life_expectancy),
    max_life = max(life_expectancy),
    .groups = "drop"
  ) %>%
  arrange(desc(mean_life))

life_summary
# A tibble: 4 × 4
  country       mean_life min_life max_life
  <chr>             <dbl>    <dbl>    <dbl>
1 Japan              84.2     83.8     84.6
2 Canada             81.7     81.1     82.2
3 United States      78.1     76.3     78.9
4 Ghana              64.4     63.2     65.7

The descriptive analysis revealed differences in life expectancy across the four selected countries from 2015 to 2024. Japan had the highest average life expectancy at 84.15 years, followed by Canada at 81.73 years and the United States at 78.12 years. Ghana had the lowest average life expectancy at 64.42 years.

Code
life_changes <- life_tidy %>%
  filter(year %in% c(2019, 2024)) %>%
  group_by(country) %>%
  summarise(
    life_2019 = life_expectancy[year == 2019],
    life_2024 = life_expectancy[year == 2024],
    change = life_2024 - life_2019,
    .groups = "drop"
  ) %>%
  arrange(desc(change))

life_changes
# A tibble: 4 × 4
  country       life_2019 life_2024  change
  <chr>             <dbl>     <dbl>   <dbl>
1 Ghana              64.5      65.7  1.24  
2 United States      78.8      78.9  0.102 
3 Canada             82.2      82.1 -0.0505
4 Japan              84.4      84.0 -0.320 

Comparing 2019 and 2024, Ghana experienced the largest increase in life expectancy, rising by 1.24 years from 64.46 to 65.70 years. The United States experienced a smaller increase of 0.10 years, from 78.79 to 78.89 years. In contrast, life expectancy declined slightly in Canada by 0.05 years and in Japan by 0.32 years.

Visualization

I created a line graph to visualize life expectancy trends across the four countries from 2015 through 2024.

Code
ggplot(life_tidy, aes(x = year, y = life_expectancy, color = country)) +
  geom_line(linewidth = 1) +
  geom_point(size = 2) + 
  scale_x_continuous(breaks = 2015:2024) +
  labs(
    title = "Life Expectancy Trends by Country, 2015-2024",
    x = "Year",
    y = "Life Expectancy at Birth (Years)",
    color = "Country"
  ) + theme_minimal()

The line graph shows differences in life expectancy trends across the four countries from 2015 to 2024. Japan maintained the highest life expectancy throughout the study period, while Ghana had the lowest. The United States experienced a noticeable decline in life expectancy during 2020 and 2021, followed by a gradual recovery through 2024. Canada experienced smaller fluctuations, while Ghana showed an overall increasing trend.

Code
ggplot(
  life_summary, aes(x = reorder(country, mean_life),
                    y = mean_life,
                    fill = country)) +
  geom_col() +
  coord_flip() +
  labs(
    title = "Average Life Expectancy by Country 2015-2024",
    x = "Country",
    y = "Average Life Expectancy (Years)"
  ) + theme_minimal() + theme(legend.position = "none")

The bar chart compares average life expectancy across the four countries. Japan had the highest average at 84.15 years, followed by Canada at 81.73 years and the United States at 78.12 years. Ghana had the lowest average at 64.42 years.

Conclusion

This analysis examined life expectancy trends across the United States, Canada, Ghana, and Japan from 2015 to 2024. The results showed that Japan had the highest average life expectancy at 84.15 years, while Ghana had the lowest at 64.42 years. However, Ghana experienced the largest increase in life expectancy between 2019 and 2024, gaining 1.24 years. The United States experienced a noticeable decline during 2020 and 2021 but recovered by 2024.

Data source: https://data.worldbank.org/indicator/SP.DYN.LE00.IN?name_desc=false

Project Conclusion

This project demonstrated how three datasets in wide format could be transformed into tidy format using R. Through pivot_longer(), data cleaning, descriptive statistics, and visualization, I was able to organize the datasets and examine patterns in clinic visits, housing values, and life expectancy. Although the datasets covered different topics, the same data-tidying techniques made them easier to analyze and interpret.