</>
Skip to content
R lessons (13/41)

R — Data Frames

What is a data frame?

A data frame is a table where each column can be a different type, but every column must have the same length:

students <- data.frame(
  name = c("Alice", "Bob", "Charlie"),
  age = c(20, 22, 19),
  grade = c("A", "B", "A"),
  passed = c(TRUE, TRUE, TRUE)
)

print(students)
#     name age grade passed
# 1  Alice  20     A   TRUE
# 2    Bob  22     B   TRUE
# 3 Charlie  19     A   TRUE

Data frames are R's equivalent of spreadsheets, SQL tables, or Python DataFrames.

Creating data frames

# From vectors
df <- data.frame(
  x = 1:5,
  y = c("a", "b", "c", "d", "e"),
  z = rnorm(5)
)

# From existing data
df <- as.data.frame(matrix(1:12, nrow = 3))

# Empty data frame
df <- data.frame()

Accessing data

students <- data.frame(
  name = c("Alice", "Bob", "Charlie"),
  age = c(20, 22, 19),
  grade = c("A", "B", "A")
)

# By column name
students$name        # "Alice" "Bob" "Charlie"
students[["age"]]    # 20 22 19

# By position
students[, 1]        # first column
students[1, ]        # first row
students[1, 2]       # row 1, column 2 (20)

# Multiple columns
students[, c("name", "grade")]

# Subset rows by condition
students[students$age > 20, ]
students[students$grade == "A", ]

Adding and removing columns

students <- data.frame(
  name = c("Alice", "Bob"),
  age = c(20, 22)
)

# Add column
students$gpa <- c(3.8, 3.5)
students["city"] <- c("NYC", "LA")

# Remove column
students$gpa <- NULL

# Add row
students <- rbind(students, data.frame(name = "Charlie", age = 19))

Data frame functions

# Structure
str(students)

# Summary statistics
summary(students)

# Dimensions
dim(students)    # rows columns
nrow(students)   # number of rows
ncol(students)   # number of columns

# Names
names(students)  # column names
colnames(students)  # same thing

# Head and tail
head(students, 2)  # first 2 rows
tail(students, 2)  # last 2 rows

The dplyr package

dplyr is the modern way to work with data frames:

library(dplyr)

# Filter rows
students %>% filter(age > 20)

# Select columns
students %>% select(name, grade)

# Mutate — add/modify columns
students %>% mutate(gpa = round(gpa, 1))

# Arrange — sort
students %>% arrange(desc(age))

# Summarize — aggregate
students %>% summarize(
  avg_age = mean(age),
  count = n()
)

# Group by
students %>%
  group_by(grade) %>%
  summarize(avg_age = mean(age))

The pipe operator with dplyr

library(dplyr)

# Chain operations
result <- mtcars %>%
  filter(cyl == 6) %>%
  select(mpg, hp, wt) %>%
  arrange(desc(mpg)) %>%
  head(5)

print(result)

The pipe %>% passes the result of each step to the next. Code reads like a pipeline of transformations.

Row operations

df <- data.frame(x = c(1, 2, 3), y = c(4, 5, 6))

# Add rows
df <- rbind(df, data.frame(x = 7, y = 8))

# Remove rows
df <- df[-1, ]       # remove first row
df <- df[df$x > 1, ] # keep rows where x > 1

# Order rows
df[order(df$x), ]

Column operations

df <- data.frame(a = 1:5, b = 6:10, c = 11:15)

# Rename columns
names(df) <- c("first", "second", "third")

# Select columns
df[, c("first", "third")]

# Reorder columns
df[, c("third", "first", "second")]

# Column arithmetic
df$sum <- df$first + df$second

Handling missing values

df <- data.frame(
  x = c(1, 2, NA, 4, 5),
  y = c(NA, 2, 3, NA, 5)
)

# Check for NAs
is.na(df)           # logical matrix
colSums(is.na(df))  # NAs per column

# Remove rows with any NA
na.omit(df)
df[complete.cases(df), ]

# Replace NAs
df$x[is.na(df$x)] <- 0
df$y[is.na(df$y)] <- mean(df$y, na.rm = TRUE)

# tidyr approach
library(tidyr)
df %>% tidyr::drop_na()

Merging data frames

students <- data.frame(
  id = c(1, 2, 3),
  name = c("Alice", "Bob", "Charlie")
)

scores <- data.frame(
  id = c(1, 2, 3),
  score = c(95, 87, 92)
)

# Inner join — only matching rows
merged <- merge(students, scores, by = "id")

# dplyr join
library(dplyr)
merged <- inner_join(students, scores, by = "id")

Reading and writing data

# CSV
df <- read.csv("data.csv")
write.csv(df, "output.csv", row.names = FALSE)

# Excel (requires readxl)
library(readxl)
df <- read_excel("data.xlsx")

# R data format
save(df, file = "data.RData")
load("data.RData")

# JSON (requires jsonlite)
library(jsonlite)
df <- fromJSON("data.json")
toJSON(df)

tibbles — modern data frames

tibbles are tidyverse's enhanced data frames:

library(tibble)

df <- tibble(
  name = c("Alice", "Bob"),
  age = c(20, 22)
)

# Features
print(df)         # shows first 10 rows
df$name           # works (like data.frame)
df[["name"]]      # also works

tibbles are stricter — they don't convert strings to factors, don't do partial matching, and display more nicely.

Mini Practice

  1. Create a data frame of five students with name, age, and grade columns
  2. Filter students with grade "A" using both base R and dplyr
  3. Add a new column that calculates age in months
  4. Use summary() to get statistics for each column
  5. Merge two data frames by a common ID column

Next: functions — reusable code →

Related Topics

Frequently Asked Questions about Data Frames

What is Data Frames in R?

Data Frames is a fundamental concept in R. This lesson explains it step by step with clear examples, making it easy for beginners to understand.

How do I learn Data Frames?

Start by reading the explanation above, then try the code examples. Practice by modifying the examples and experimenting with different values. Hands-on practice is the best way to learn Data Frames.

Why is Data Frames important in R?

Data Frames is essential for R development. Understanding this concept will help you write better code and solve real-world problems more effectively.