PROJECT

Author

G + D

Our report

First, we imported the Adult Census Income data from Kaggle.

#| include: false 

remove(list=ls())

library(tidyverse)
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.2.1     ✔ readr     2.2.0
✔ forcats   1.0.1     ✔ stringr   1.6.0
✔ ggplot2   4.0.3     ✔ tibble    3.3.1
✔ lubridate 1.9.5     ✔ tidyr     1.3.2
✔ purrr     1.2.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
library(reshape2)

Attaching package: 'reshape2'

The following object is masked from 'package:tidyr':

    smiths
library(ggplot2)

original <- adult <- read.csv("~/Desktop/adult.csv")

We split our data into qualitative and quantitative data frames

qualitative variables includes, workclass, education, marital.status, occupation, relationship, race, sex, native country, and income

quantitative variables includes: age, fnlwgt, education.num, capital.gain, capital.loss, hours.per.week

Then we distributed the qualitative variables.

# Reshape categorical data to long format 
df_qual_long <- melt(df_qual, measure.vars = colnames(df_qual))

# Remove ? values 
df_qual_long <- na.omit(df_qual_long)

# Faceted Bar chart for categorical features 
qual_vars_dist <- 
  ggplot(df_qual_long, aes(x = value, fill = variable)) + 
  facet_wrap(~ variable, scales = "free", ncol = 3) + 
  theme_classic() + 
  labs(
    title = "Adult Income Presentation"
  ) + 
  theme(axis.text.x = element_text(angle = 45, hjust = 1))
qual_vars_dist

# Reshape quantitative data 
library(ggplot2)
df_quant_long <- melt(df_quant, measure.vars = colnames(df_quant))

# Faceted Histogram Grid 
quant_vars_dist <- 
  ggplot(df_quant_long, aes(x = value, fill = variable)) + 
  facet_wrap(~variable, scales = "free", ncol = 3) + 
  theme_classic() + 
  labs(
    title = "Quantitative Variable Distributions", 
    x = "Value",
    y = "Count"
  ) + 
  
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1) # Rotates x-axis labels 45°
  )
quant_vars_dist

Cleaning data

library(tidyverse)

df_plot <- adult %>%
  mutate(
    education_clean = case_when(
      education %in% c("Preschool", "1st-4th", "5th-6th", "7th-8th", 
                       "9th", "10th", "11th", "12th") ~ "Less than HS",
      education == "HS-grad"                            ~ "HS Diploma",
      education %in% c("Some-college", "Assoc-voc", 
                       "Assoc-acdm")                   ~ "Some College / Associate",
      education == "Bachelors"                          ~ "Bachelor's Degree",
      education %in% c("Masters", "Prof-school", 
                       "Doctorate")                    ~ "Graduate / Advanced",
      TRUE                                              ~ education
    ),
    # Set explicitly ordered factor levels for the graph
    education_clean = factor(
      education_clean,
      levels = c(
        "Less than HS", 
        "HS Diploma", 
        "Some College / Associate", 
        "Bachelor's Degree", 
        "Graduate / Advanced"
      )
    )
  )

# Plot grouped education variable
ggplot(df_plot, aes(x = education_clean, fill = income)) +
  geom_bar(position = "fill") + # Proportional stacked bar graph
  scale_y_continuous(labels = scales::percent) +
  labs(
    title = "Income Level by Education Category",
    x = "Education Level",
    y = "Percentage",
    fill = "Income Group"
  ) +
  theme_classic() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

library(tidyverse)

# Read data
adult <- read_csv("adult.csv", na = c("", "NA", "?"))
Rows: 32561 Columns: 15
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (9): workclass, education, marital.status, occupation, relationship, rac...
dbl (6): age, fnlwgt, education.num, capital.gain, capital.loss, hours.per.week

ℹ 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.
df_workclass_grouped <- adult %>%
  mutate(
    # Group workclass into 5 presentation-ready categories
    workclass_clean = case_when(
      workclass == "Private" ~ "Private Sector",
      workclass %in% c("Local-gov", "State-gov", "Federal-gov") ~ "Government",
      workclass %in% c("Self-emp-not-inc", "Self-emp-inc") ~ "Self-Employed",
      workclass %in% c("Without-pay", "Never-worked") ~ "Other / Unemployed",
      is.na(workclass) | workclass == "?" ~ "Unknown",
      TRUE ~ workclass
    ),
    # Sort categories by frequency
    workclass_clean = fct_infreq(workclass_clean)
  )

# Plot grouped workclass vs income level
ggplot(df_workclass_grouped, aes(x = workclass_clean, fill = income)) +
  geom_bar(position = "dodge") +
  scale_fill_manual(values = c("<=50K" = "#56B4E9", ">50K" = "#D55E00")) +
  labs(
    title = "Income Distribution by Work Class",
    x = "Work Class",
    y = "Count",
    fill = "Income Group"
  ) +
  theme_classic() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

library(tidyverse)

# 1. Load data (treating "?" as missing NA values)
adult <- read_csv("adult.csv", na = c("", "NA", "?"))
Rows: 32561 Columns: 15
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (9): workclass, education, marital.status, occupation, relationship, rac...
dbl (6): age, fnlwgt, education.num, capital.gain, capital.loss, hours.per.week

ℹ 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.
df_marital.status_grouped <- adult %>%
  mutate(
    # Group marital.status into 4 presentation-ready categories 
    marital.status_clean = case_when(
      marital.status %in% c("Married-civ-spouse", "Married-spouse-absent", "Married-AF-spouse") ~ "Married", 
      marital.status %in% c("Divorced", "Separated") ~ "Divorced", 
      marital.status == "Widowed" ~ "Spouse Dead",  
      marital.status == "Never-married" ~ "Single",
      TRUE ~ marital.status
    ),
    # Sort categories by frequency 
    marital.status_clean = fct_infreq(marital.status_clean)
  )


# 2. Bar Graph
ggplot(df_marital.status_grouped, aes(x = marital.status_clean, fill = income)) +
  geom_bar(position = "dodge") +
  scale_fill_manual(values = c("<=50k" = "#56B4E9", ">50K" = "#D55E00")) +
  labs(
    title = "Income by Marital Status",
    x = "Status", 
    y= "Count"
  ) + 
  theme_classic() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

library(tidyverse)

# 1. Read dataset
adult <- read_csv("adult.csv", na = c("", "NA", "?"))
Rows: 32561 Columns: 15
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (9): workclass, education, marital.status, occupation, relationship, rac...
dbl (6): age, fnlwgt, education.num, capital.gain, capital.loss, hours.per.week

ℹ 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.
# 2. Group occupations into 6 major industry sectors
df_occ_grouped <- adult %>%
  mutate(
    occupation_sector = case_when(
      occupation %in% c("Prof-specialty", "Exec-managerial", "Tech-support") ~ "Manage. & Professional",
      occupation %in% c("Adm-clerical", "Sales")                              ~ "Sales & Office",
      occupation %in% c("Craft-repair", "Machine-op-inspct", 
                        "Transport-moving", "Handlers-cleaners")              ~ "Blue Collar & Trades",
      occupation %in% c("Other-service", "Protective-serv", 
                        "Priv-house-serv")                                    ~ "Services & Security",
      occupation == "Farming-fishing"                                         ~ "Farming & Agriculture",
      occupation == "Armed-Forces"                                            ~ "Military",
      is.na(occupation) | occupation == "?"                                   ~ "Unknown",
      TRUE                                                                    ~ occupation
    ),
    # Sort bars by frequency
    occupation_sector = fct_infreq(occupation_sector)
  )

# 3. Proportional Stacked Bar Graph (Shows % of high earners in each sector)
ggplot(df_occ_grouped, aes(x = occupation_sector, fill = income)) +
  geom_bar(position = "fill") +
  scale_y_continuous(labels = scales::percent) +
  scale_fill_manual(values = c("<=50K" = "#56B4E9", ">50K" = "#D55E00")) +
  labs(
    title = "High Earners (>50K) Across Occupational Sectors",
    x = "Occupational Sector",
    y = "Percentage",
    fill = "Income Group"
  ) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 30, hjust = 1))

library(tidyverse)

# 1. Load dataset
adult <- read_csv("adult.csv")
Rows: 32561 Columns: 15
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (9): workclass, education, marital.status, occupation, relationship, rac...
dbl (6): age, fnlwgt, education.num, capital.gain, capital.loss, hours.per.week

ℹ 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.
# 2. Relabel hyphenated values and sort by frequency
df_rel_sorted <- adult %>%
  mutate(
    relationship_clean = fct_recode(
      relationship,
      "Not in Family"  = "Not-in-family",
      "Own Child"      = "Own-child",
      "Other Relative" = "Other-relative"
    ),
    # Order levels by size (most frequent to least frequent)
    relationship_clean = fct_infreq(relationship_clean)
  )

# 3. Horizontal Bar Graph
ggplot(df_rel_sorted, aes(x = fct_rev(relationship_clean), fill = income)) +
  geom_bar(position = "dodge") +
  scale_fill_manual(values = c("<=50K" = "#56B4E9", ">50K" = "#D55E00")) +
  labs(
    title = "Household Relationship vs Income",
    x = "Relationship",
    y = "Count",
    fill = "Income Group"
  ) +
  theme_classic()

library(tidyverse)

# 1. Load data
adult <- read_csv("adult.csv")
Rows: 32561 Columns: 15
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (9): workclass, education, marital.status, occupation, relationship, rac...
dbl (6): age, fnlwgt, education.num, capital.gain, capital.loss, hours.per.week

ℹ 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.
# 2. Simplify into 4 primary presentation categories
df_race_grouped <- adult %>%
  mutate(
    race_grouped = case_when(
      race == "White"              ~ "White",
      race == "Black"              ~ "Black",
      race == "Asian-Pac-Islander" ~ "Asian / Pacific Islander",
      race %in% c("Amer-Indian-Eskimo", "Other") ~ "Other / Indigenous",
      TRUE                         ~ race
    ),
    # Sort categories by frequency
    race_grouped = fct_infreq(race_grouped)
  )

# 3. Proportional Stacked Bar Chart (100% Filled)
ggplot(df_race_grouped, aes(x = race_grouped, fill = income)) +
  geom_bar(position = "fill") +
  scale_y_continuous(labels = scales::percent) +
  scale_fill_manual(values = c("<=50K" = "#56B4E9", ">50K" = "#D55E00")) +
  labs(
    title = "Proportion of Income Levels by Race",
    x = "Racial Group",
    y = "Percentage",
    fill = "Income Group"
  ) +
  theme_classic() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

# 1. Load data
adult <- read_csv("adult.csv")
Rows: 32561 Columns: 15
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (9): workclass, education, marital.status, occupation, relationship, rac...
dbl (6): age, fnlwgt, education.num, capital.gain, capital.loss, hours.per.week

ℹ 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.
# 2. Clean/Factor the sex variable
df_sex <- adult %>%
  mutate(
    sex = factor(sex, levels = c("Male", "Female"))
  )

# 3. Side-by-Side Bar Graph
ggplot(df_sex, aes(x = sex, fill = income)) +
  geom_bar(position = "dodge") +
  scale_fill_manual(values = c("<=50K" = "#56B4E9", ">50K" = "#D55E00")) +
  labs(
    title = "Income Level Distribution by Sex",
    x = "Sex",
    y = "Count",
    fill = "Income Group"
  ) +
  theme_classic()

# Map with United States separated
df_continent_split <- adult %>%
  mutate(
    continent = case_when(
      native.country == "United-States" ~ "United States",
      native.country %in% c("Canada", "Mexico") ~ "Rest of North America",
      native.country %in% c("Puerto-Rico", "El-Salvador", "Cuba", "Jamaica", 
                            "Dominican-Republic", "Guatemala", "Haiti", 
                            "Nicaragua", "Trinadad&Tobago", "Honduras", 
                            "Columbia", "Ecuador", "Peru", 
                            "Outlying-US(Guam-USVI-etc)") ~ "Central / South America & Caribbean",
      native.country %in% c("Germany", "England", "Italy", "Poland", "Portugal", 
                            "Greece", "Yugoslavia", "Ireland", "Hungary", 
                            "Scotland", "Holand-Netherlands") ~ "Europe",
      native.country %in% c("Philippines", "India", "China", "Japan", "Vietnam", 
                            "Taiwan", "Iran", "Asian-Pac-Islander", "Thailand", 
                            "Cambodia", "Laos", "Hong") ~ "Asia",
      is.na(native.country) ~ "Unknown",
      TRUE ~ "Other"
    ),
    continent = fct_infreq(continent)
  )

# Plot as horizontal bar counts
ggplot(df_continent_split, aes(y = fct_rev(continent), fill = income)) +
  geom_bar(position = "dodge") +
  scale_fill_manual(values = c("<=50K" = "#56B4E9", ">50K" = "#D55E00")) +
  labs(
    title = "Sample Count by Geographic Region of Origin",
    x = "Count",
    y = "Region",
    fill = "Income Group"
  ) +
  theme_minimal()

library(tidyverse)

# 1. Load dataset
adult <- read_csv("adult.csv")
Rows: 32561 Columns: 15
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (9): workclass, education, marital.status, occupation, relationship, rac...
dbl (6): age, fnlwgt, education.num, capital.gain, capital.loss, hours.per.week

ℹ 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.
# 2. Bin continuous age into decades
df_age_decades <- adult %>%
  mutate(
    age_decade = cut(
      age,
      breaks = c(10, 20, 30, 40, 50, 60, 70, Inf),
      labels = c("Teens (17-19)", "20s", "30s", "40s", "50s", "60s", "70s+"),
      right = FALSE # Includes lower bound, e.g., 20 to 29 is "20s"
    )
  )

# 3. Option A: Proportional Stacked Bar Graph (100% Filled - Recommended)
# Shows the percentage of high earners (>50K) in each decade
ggplot(df_age_decades, aes(x = age_decade, fill = income)) +
  geom_bar(position = "fill") +
  scale_y_continuous(labels = scales::percent) +
  scale_fill_manual(values = c("<=50K" = "#56B4E9", ">50K" = "#D55E00")) +
  labs(
    title = "Proportions of Income Levels across Age Decades",
    x = "Age Decade",
    y = "Percentage",
    fill = "Income Group"
  ) +
  theme_minimal()

library(tidyverse)

# 1. Load dataset
adult <- read_csv("adult.csv")
Rows: 32561 Columns: 15
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (9): workclass, education, marital.status, occupation, relationship, rac...
dbl (6): age, fnlwgt, education.num, capital.gain, capital.loss, hours.per.week

ℹ 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.
# 2. Bin fnlwgt into population representation brackets (in groups of 100,000)
df_fnlwgt_binned <- adult %>%
  mutate(
    weight_group = cut(
      fnlwgt,
      breaks = c(0, 100000, 200000, 300000, 400000, 500000, Inf),
      labels = c("<100k", "100k–200k", "200k–300k", "300k–400k", "400k–500k", "500k+"),
      right = FALSE
    )
  )

# 3. Bar Graph showing distribution of survey weights
ggplot(df_fnlwgt_binned, aes(x = weight_group, fill = income)) +
  geom_bar(position = "dodge") +
  scale_fill_manual(values = c("<=50K" = "#56B4E9", ">50K" = "#D55E00")) +
  labs(
    title = "Distribution of Census Sample Weights (fnlwgt)",
    x = "Population Weight Group (Represented Individuals)",
    y = "Survey Row Count",
    fill = "Income Group"
  ) +
  theme_minimal()

library(tidyverse)

# 1. Load dataset
adult <- read_csv("adult.csv")
Rows: 32561 Columns: 15
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (9): workclass, education, marital.status, occupation, relationship, rac...
dbl (6): age, fnlwgt, education.num, capital.gain, capital.loss, hours.per.week

ℹ 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.
# 2. Bin capital gains into intuitive tiers
df_cap_gain_tiered <- adult %>%
  mutate(
    cap_gain_group = case_when(
      capital.gain == 0 ~ "None ($0)",
      capital.gain > 0 & capital.gain < 5000 ~ "Low ($1–$4,999)",
      capital.gain >= 5000 & capital.gain < 15000 ~ "Medium ($5,000–$14,999)",
      capital.gain >= 15000 & capital.gain < 99999 ~ "High ($15,000–$99,998)",
      capital.gain == 99999 ~ "Maximum ($99,999)",
      TRUE ~ "Other"
    ),
    # Set explicit ordering for the plot
    cap_gain_group = factor(
      cap_gain_group,
      levels = c("None ($0)", "Low ($1–$4,999)", "Medium ($5,000–$14,999)", "High ($15,000–$99,998)", "Maximum ($99,999)")
    )
  )

# 3. Bar Graph
ggplot(df_cap_gain_tiered, aes(x = cap_gain_group, fill = income)) +
  geom_bar(position = "dodge") +
  scale_fill_manual(values = c("<=50K" = "#56B4E9", ">50K" = "#D55E00")) +
  labs(
    title = "Income Level across Capital Gain Brackets",
    x = "Capital Gain Tier",
    y = "Count",
    fill = "Income Group"
  ) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 20, hjust = 1))

library(tidyverse)

# 1. Load dataset
adult <- read_csv("adult.csv")
Rows: 32561 Columns: 15
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (9): workclass, education, marital.status, occupation, relationship, rac...
dbl (6): age, fnlwgt, education.num, capital.gain, capital.loss, hours.per.week

ℹ 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.
# 2. Bin capital loss into structured tiers
df_cap_loss_tiered <- adult %>%
  mutate(
    cap_loss_group = case_when(
      capital.loss == 0 ~ "None ($0)",
      capital.loss > 0 & capital.loss < 1600 ~ "Low ($1–$1,599)",
      capital.loss >= 1600 & capital.loss <= 2000 ~ "Medium ($1,600–$2,000)",
      capital.loss > 2000 ~ "High ($2,001+)",
      TRUE ~ "Other"
    ),
    # Set explicit factor ordering
    cap_loss_group = factor(
      cap_loss_group,
      levels = c("None ($0)", "Low ($1–$1,599)", "Medium ($1,600–$2,000)", "High ($2,001+)")
    )
  )

# 3. Bar Graph
ggplot(df_cap_loss_tiered, aes(x = cap_loss_group, fill = income)) +
  geom_bar(position = "dodge") +
  scale_fill_manual(values = c("<=50K" = "#56B4E9", ">50K" = "#D55E00")) +
  labs(
    title = "Income Distribution across Capital Loss Tiers",
    x = "Capital Loss Bracket",
    y = "Count",
    fill = "Income Group"
  ) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 15, hjust = 1))

library(tidyverse)

# 1. Load dataset
adult <- read_csv("adult.csv")
Rows: 32561 Columns: 15
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (9): workclass, education, marital.status, occupation, relationship, rac...
dbl (6): age, fnlwgt, education.num, capital.gain, capital.loss, hours.per.week

ℹ 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.
# 2. Bin hours.per.week into labor categories
df_hours_grouped <- adult %>%
  mutate(
    work_schedule = case_when(
      hours.per.week < 35 ~ "Part-Time (<35 hrs)",
      hours.per.week >= 35 & hours.per.week <= 40 ~ "Full-Time Standard (35–40 hrs)",
      hours.per.week > 40 & hours.per.week <= 50 ~ "Overtime (41–50 hrs)",
      hours.per.week > 50 ~ "Extended Overtime (50+ hrs)",
      TRUE ~ "Other"
    ),
    # Set explicit factor level order
    work_schedule = factor(
      work_schedule,
      levels = c("Part-Time (<35 hrs)", "Full-Time Standard (35–40 hrs)", "Overtime (41–50 hrs)", "Extended Overtime (50+ hrs)")
    )
  )

# 3. 100% Proportional Stacked Bar Graph
ggplot(df_hours_grouped, aes(x = work_schedule, fill = income)) +
  geom_bar(position = "fill") +
  scale_y_continuous(labels = scales::percent) +
  scale_fill_manual(values = c("<=50K" = "#56B4E9", ">50K" = "#D55E00")) +
  labs(
    title = "Proportion of High Earners (>50K) by Work Schedule",
    x = "Work Schedule Category",
    y = "Percentage",
    fill = "Income Group"
  ) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 15, hjust = 1))