Chapter 2 R Objects

R is an object-oriented language, which means that everything you work with—numbers, text, datasets, even functions—is stored as an object. Understanding how objects work is fundamental to programming in R. This chapter covers the basic object types you’ll use constantly in economic data analysis.

2.1 What is an Object?

An object is simply a named container that holds data. When you write:

gdp <- 21000

You create an object called gdp that stores the value 21000. The <- symbol is the assignment operator—it takes whatever is on the right and stores it in the name on the left. You can think of it as an arrow pointing to where the data should go.

You can see all objects currently in your R session by looking at the Environment panel in RStudio, or by typing:

ls()
## [1] "gdp"    "macro"  "p1"     "p2"     "states"

2.2 Scalars

A scalar is the simplest type of object: a single value. R has three main types of scalar values.

2.2.1 Numeric

Numeric values are numbers, either integers or decimals:

inflation_rate <- 0.032
population <- 331000000
unemployment <- 3.7

You can perform arithmetic with numeric objects:

real_rate <- 0.05 - inflation_rate
real_rate
## [1] 0.018

2.2.2 Character

Character values are text, always enclosed in quotes:

country <- "United States"
currency <- "USD"

Note that numbers in quotes are treated as text, not as numbers you can do math with:

year_text <- "2024"
class(year_text)
## [1] "character"

2.2.3 Logical

Logical values are either TRUE or FALSE. They often result from comparisons:

is_recession <- FALSE
inflation_rate > 0.02
## [1] TRUE
unemployment < 5
## [1] TRUE

Logical values are essential for filtering data, which we’ll cover in later chapters.

2.3 Vectors

A vector is an ordered collection of values of the same type. Vectors are the workhorse of R—even a single number is technically a vector of length one.

2.3.1 Creating Vectors

Use the c() function (short for “combine”) to create vectors:

# GDP growth rates for five quarters
growth_rates <- c(2.1, 1.8, -0.5, 3.2, 2.7)
growth_rates
## [1]  2.1  1.8 -0.5  3.2  2.7
# Country names
countries <- c("USA", "Canada", "Mexico")
countries
## [1] "USA"    "Canada" "Mexico"
# Boolean indicators for recession
in_recession <- c(FALSE, FALSE, TRUE, FALSE, FALSE)
in_recession
## [1] FALSE FALSE  TRUE FALSE FALSE

2.3.2 Sequences

For numeric sequences, R provides shortcuts:

# Years from 2000 to 2010
years <- 2000:2010
years
##  [1] 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010
# Sequence with specific increment
rates <- seq(from = 0, to = 1, by = 0.1)
rates
##  [1] 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0
# Repeat a value
baseline <- rep(0, times = 5)
baseline
## [1] 0 0 0 0 0

2.3.3 Accessing Vector Elements

Use square brackets to access specific elements. R uses 1-based indexing, meaning the first element is at position 1:

growth_rates[1]       # First element
## [1] 2.1
growth_rates[3]       # Third element
## [1] -0.5
growth_rates[c(1, 3)] # First and third elements
## [1]  2.1 -0.5
growth_rates[2:4]     # Elements 2 through 4
## [1]  1.8 -0.5  3.2

You can also use negative indices to exclude elements:

growth_rates[-1]      # Everything except the first element
## [1]  1.8 -0.5  3.2  2.7
growth_rates[-c(1,2)] # Everything except first two elements
## [1] -0.5  3.2  2.7

2.3.4 Vector Operations

Operations on vectors apply to each element:

# Convert growth rates from percent to decimal
growth_decimal <- growth_rates / 100
growth_decimal
## [1]  0.021  0.018 -0.005  0.032  0.027
# Calculate squared deviations from mean
mean_growth <- mean(growth_rates)
deviations <- (growth_rates - mean_growth)^2
deviations
## [1] 0.0576 0.0036 5.5696 1.7956 0.7056

2.3.5 Naming Vector Elements

You can give names to vector elements for easier access:

quarterly_gdp <- c(Q1 = 5200, Q2 = 5350, Q3 = 5280, Q4 = 5400)
quarterly_gdp
##   Q1   Q2   Q3   Q4 
## 5200 5350 5280 5400
quarterly_gdp["Q2"]
##   Q2 
## 5350
quarterly_gdp[c("Q1", "Q4")]
##   Q1   Q4 
## 5200 5400

2.4 Lists

Unlike vectors, lists can contain elements of different types. A list can hold numbers, text, vectors, and even other lists.

2.4.1 Creating Lists

country_data <- list(
  name = "Germany",
  gdp = 4200,
  growth_rates = c(1.1, 0.8, 1.5, 2.0),
  in_eu = TRUE
)
country_data
## $name
## [1] "Germany"
## 
## $gdp
## [1] 4200
## 
## $growth_rates
## [1] 1.1 0.8 1.5 2.0
## 
## $in_eu
## [1] TRUE

2.4.2 Accessing List Elements

Lists use double brackets [[]] or the $ operator to access elements:

# Using double brackets with position
country_data[[1]]
## [1] "Germany"
# Using double brackets with name
country_data[["gdp"]]
## [1] 4200
# Using $ operator (most common)
country_data$name
## [1] "Germany"
country_data$growth_rates
## [1] 1.1 0.8 1.5 2.0

The $ operator is the standard way to access named elements in R. You’ll use it constantly.

Single brackets return a sublist rather than the element itself:

country_data[1]        # Returns a list containing the first element
## $name
## [1] "Germany"
country_data[[1]]      # Returns the first element directly
## [1] "Germany"

2.5 Data Frames

A data frame is R’s structure for tabular data—rows and columns, like a spreadsheet. Each column is a vector, and all columns must have the same length. Data frames are what you’ll use most often for economic data.

2.5.1 Creating Data Frames

trade_data <- data.frame(
  country = c("China", "Canada", "Mexico", "Japan", "Germany"),
  exports = c(150.4, 310.2, 276.5, 75.3, 58.8),
  imports = c(538.8, 357.2, 371.9, 148.2, 131.8),
  year = c(2023, 2023, 2023, 2023, 2023)
)
trade_data
##   country exports imports year
## 1   China   150.4   538.8 2023
## 2  Canada   310.2   357.2 2023
## 3  Mexico   276.5   371.9 2023
## 4   Japan    75.3   148.2 2023
## 5 Germany    58.8   131.8 2023

2.5.2 Examining Data Frames

Several functions help you understand a data frame’s structure:

# Dimensions (rows, columns)
dim(trade_data)
## [1] 5 4
# Number of rows
nrow(trade_data)
## [1] 5
# Number of columns
ncol(trade_data)
## [1] 4
# Column names
names(trade_data)
## [1] "country" "exports" "imports" "year"
# Structure overview
str(trade_data)
## 'data.frame':    5 obs. of  4 variables:
##  $ country: chr  "China" "Canada" "Mexico" "Japan" ...
##  $ exports: num  150.4 310.2 276.5 75.3 58.8
##  $ imports: num  539 357 372 148 132
##  $ year   : num  2023 2023 2023 2023 2023
# First few rows
head(trade_data, 3)
##   country exports imports year
## 1   China   150.4   538.8 2023
## 2  Canada   310.2   357.2 2023
## 3  Mexico   276.5   371.9 2023

2.5.3 Accessing Data Frame Elements

Data frames combine vector and list access methods:

# Single column (returns a vector)
trade_data$exports
## [1] 150.4 310.2 276.5  75.3  58.8
trade_data[["exports"]]
## [1] 150.4 310.2 276.5  75.3  58.8
trade_data[, "exports"]
## [1] 150.4 310.2 276.5  75.3  58.8
# Single row
trade_data[1, ]
##   country exports imports year
## 1   China   150.4   538.8 2023
# Single cell
trade_data[1, "exports"]
## [1] 150.4
trade_data[1, 2]
## [1] 150.4
# Multiple columns
trade_data[, c("country", "exports")]
##   country exports
## 1   China   150.4
## 2  Canada   310.2
## 3  Mexico   276.5
## 4   Japan    75.3
## 5 Germany    58.8
# Multiple rows
trade_data[1:3, ]
##   country exports imports year
## 1   China   150.4   538.8 2023
## 2  Canada   310.2   357.2 2023
## 3  Mexico   276.5   371.9 2023

2.5.4 Adding and Modifying Columns

Create new columns using the $ operator:

# Calculate trade balance
trade_data$balance <- trade_data$exports - trade_data$imports
trade_data
##   country exports imports year balance
## 1   China   150.4   538.8 2023  -388.4
## 2  Canada   310.2   357.2 2023   -47.0
## 3  Mexico   276.5   371.9 2023   -95.4
## 4   Japan    75.3   148.2 2023   -72.9
## 5 Germany    58.8   131.8 2023   -73.0
# Calculate total trade
trade_data$total_trade <- trade_data$exports + trade_data$imports
trade_data
##   country exports imports year balance total_trade
## 1   China   150.4   538.8 2023  -388.4       689.2
## 2  Canada   310.2   357.2 2023   -47.0       667.4
## 3  Mexico   276.5   371.9 2023   -95.4       648.4
## 4   Japan    75.3   148.2 2023   -72.9       223.5
## 5 Germany    58.8   131.8 2023   -73.0       190.6

2.6 Managing Objects

2.6.1 Viewing Objects

To see what objects exist in your session:

ls()
##  [1] "baseline"       "countries"      "country"        "country_data"  
##  [5] "currency"       "deviations"     "gdp"            "growth_decimal"
##  [9] "growth_rates"   "in_recession"   "inflation_rate" "is_recession"  
## [13] "macro"          "mean_growth"    "p1"             "p2"            
## [17] "population"     "quarterly_gdp"  "rates"          "real_rate"     
## [21] "states"         "trade_data"     "unemployment"   "year_text"     
## [25] "years"

To check an object’s type:

class(growth_rates)
## [1] "numeric"
class(country_data)
## [1] "list"
class(trade_data)
## [1] "data.frame"

2.6.2 Removing Objects

Remove objects you no longer need with rm():

temp_value <- 999
ls()
##  [1] "baseline"       "countries"      "country"        "country_data"  
##  [5] "currency"       "deviations"     "gdp"            "growth_decimal"
##  [9] "growth_rates"   "in_recession"   "inflation_rate" "is_recession"  
## [13] "macro"          "mean_growth"    "p1"             "p2"            
## [17] "population"     "quarterly_gdp"  "rates"          "real_rate"     
## [21] "states"         "temp_value"     "trade_data"     "unemployment"  
## [25] "year_text"      "years"
rm(temp_value)
ls()
##  [1] "baseline"       "countries"      "country"        "country_data"  
##  [5] "currency"       "deviations"     "gdp"            "growth_decimal"
##  [9] "growth_rates"   "in_recession"   "inflation_rate" "is_recession"  
## [13] "macro"          "mean_growth"    "p1"             "p2"            
## [17] "population"     "quarterly_gdp"  "rates"          "real_rate"     
## [21] "states"         "trade_data"     "unemployment"   "year_text"     
## [25] "years"

To remove all objects (use with caution):

rm(list = ls())

2.6.3 Checking Object Properties

# Length of vectors and lists
length(growth_rates)
## [1] 5
length(country_data)
## [1] 4
# Check if an object exists
exists("trade_data")
## [1] TRUE
exists("nonexistent_object")
## [1] FALSE
# Check object type
is.vector(growth_rates)
## [1] TRUE
is.list(country_data)
## [1] TRUE
is.data.frame(trade_data)
## [1] TRUE

2.7 Combining Objects

2.7.1 Combining Vectors

Use c() to combine vectors:

first_half <- c(1.2, 1.5, 1.8)
second_half <- c(2.1, 1.9, 2.3)
full_year <- c(first_half, second_half)
full_year
## [1] 1.2 1.5 1.8 2.1 1.9 2.3

2.7.2 Combining Data Frames

Stack data frames vertically with rbind() (row bind):

asia_trade <- data.frame(
  country = c("South Korea", "Vietnam"),
  exports = c(65.2, 114.5),
  imports = c(115.7, 137.2)
)

americas_trade <- data.frame(
  country = c("Brazil", "Chile"),
  exports = c(40.1, 18.2),
  imports = c(36.5, 12.8)
)

combined_trade <- rbind(asia_trade, americas_trade)
combined_trade
##       country exports imports
## 1 South Korea    65.2   115.7
## 2     Vietnam   114.5   137.2
## 3      Brazil    40.1    36.5
## 4       Chile    18.2    12.8

Combine data frames horizontally with cbind() (column bind):

indicators <- data.frame(
  gdp_growth = c(2.1, 5.5, 3.2, -1.0),
  inflation = c(3.2, 3.8, 7.5, 4.1)
)

regions <- data.frame(
  region = c("Asia", "Asia", "Americas", "Americas")
)

full_data <- cbind(combined_trade, indicators, regions)
full_data
##       country exports imports gdp_growth inflation   region
## 1 South Korea    65.2   115.7        2.1       3.2     Asia
## 2     Vietnam   114.5   137.2        5.5       3.8     Asia
## 3      Brazil    40.1    36.5        3.2       7.5 Americas
## 4       Chile    18.2    12.8       -1.0       4.1 Americas

2.8 Exercises

  1. Create a vector called monthly_cpi containing these Consumer Price Index values: 299.2, 300.1, 301.5, 302.8, 303.0, 302.5. Calculate the mean and standard deviation using mean() and sd().

  2. Create a data frame called state_unemployment with three columns: state (character), unemployment_rate (numeric), and above_national (logical). Include at least four states with made-up values.

  3. Create a list called fed_data that contains: a character value for the Fed chair’s name, a numeric value for the current federal funds rate, and a vector of the last four rate decisions (as numeric values like 0.25, 0, -0.25).

  4. Using the trade_data data frame from this chapter, extract only the rows where imports exceed 200 billion. (Hint: use a logical condition inside the brackets.)