CTCaliberTek
Course: R Programming Path: From Beginner to Reproducible Reports · Lesson 3 of 8Log in to track your progress and earn a certificate when you finish the course.
Programming

R Data Frames: Importing, Inspecting, Subsetting, and Summarizing Data

Published November 9, 2026·Updated November 9, 2026·10 min read

Edited by , Senior Data Analyst. How we make our content

Like SaveLog in to like, save, and track progress.

Introduction

A data frame is R's table: each column is a vector, columns can have different types, and every column has the same length. Nearly every analysis starts by reading a file into a data frame and learning its structure. This lesson uses base R, which works everywhere without extra packages and which you will still see in older code, before the next lesson introduces dplyr for more readable data wrangling.

Prerequisites

  • The previous lesson on vectors, types, and indexing
  • An RStudio Project with a data folder

Step-by-Step Guide

Step 1: Build a data frame by hand

The data.frame function combines vectors of equal length into columns. Building a small table yourself is a good way to understand the structure before you load a large file. Each column keeps its own type, so a character column of names can sit beside a numeric column of salaries. Use the dollar sign to pull out a single column as a vector, and nrow and ncol to get the dimensions.

employees <- data.frame(
  name   = c("Asha", "Ben", "Chen", "Dina", "Eli"),
  dept   = c("Eng", "Eng", "Sales", "Sales", "HR"),
  salary = c(85000, 95000, 60000, 65000, 55000)
)
nrow(employees)        # 5
ncol(employees)        # 3
employees$salary       # the salary column as a vector

Step 2: Import a CSV file

Real data usually comes from a file. The read.csv function reads a comma-separated file into a data frame, using the first line as column names. Pass a relative path inside your project so the code works on any computer. Check the result immediately, because encoding, delimiters, and stray header lines are common problems. If your file uses semicolons, as is common in some European locales, use read.csv2 or the sep argument. You can write results back out with write.csv, and row.names = FALSE keeps R from adding a useless index column.

sales <- read.csv("data/sales.csv")
write.csv(employees, "output/employees.csv", row.names = FALSE)

Step 3: Inspect before you analyze

Always look at a dataset before computing anything. The head function shows the first rows, str shows each column's type and a preview of its values, and summary gives quick statistics, counting values for text and factor columns and reporting quartiles for numeric ones. A numeric column that str reports as character usually has a stray non-numeric value. Checking for missing values with colSums and is.na at this stage tells you how much cleaning the file needs.

head(employees, 3)
str(employees)
summary(employees$salary)
colSums(is.na(employees))   # missing values per column

Step 4: Select rows and columns

A data frame is indexed with two positions inside square brackets, rows first and columns second. Leaving one side empty means all of them. Logical tests on columns produce row filters, and you can combine tests with & for and, and | for or. Note the trailing comma in the filter example, which says to keep all columns. Forgetting it is a classic mistake that produces a confusing error or the wrong shape.

employees[2, ]                          # second row, all columns
employees[ , c("name", "salary")]       # all rows, two columns
employees[employees$salary > 60000, ]   # Asha, Ben, Dina
employees[employees$dept == "Eng" & employees$salary > 90000, ]   # Ben

Step 5: Add columns and sort rows

Assigning to a new column name with the dollar sign creates the column, calculated from existing columns for every row at once. To sort, use order, which returns the row positions that would put a column in order, and use those positions to reindex the data frame. Add decreasing = TRUE for descending order. Because assignment changes the data frame in your session only, nothing happens to the original file, which keeps raw data safe.

employees$bonus <- employees$salary * 0.10
employees$senior <- employees$salary >= 80000
employees[order(employees$salary, decreasing = TRUE), ]

Step 6: Summarize by group

Analysis constantly asks for a statistic per category, such as average salary per department. The aggregate function takes a formula, with the value on the left of the tilde and the grouping column on the right, plus the data frame and the function to apply. The result is a new, smaller data frame. The tapply function does a similar job and returns a named vector. For several statistics at once, or for more readable code, the dplyr package in the next lesson is usually easier.

aggregate(salary ~ dept, data = employees, FUN = mean)
#    dept salary
# 1   Eng  90000
# 2    HR  55000
# 3 Sales  62500

tapply(employees$salary, employees$dept, mean)

FAQs

What is the difference between a data frame and a matrix?
A matrix holds a single type across the whole table, while a data frame lets each column have its own type. Use a data frame for mixed data such as names, dates, and numbers, and a matrix for purely numeric calculations.
What is a tibble?
A tibble is the tidyverse version of a data frame. It prints more compactly, never changes column names or types behind your back, and works with all data frame code. You create one with tibble or read one with readr's read_csv.
Why does my filter return NA rows?
When the test column contains NA, the comparison gives NA, and base R indexing returns a row of NAs for it. Add !is.na(column) to the condition, or use dplyr's filter, which drops those rows automatically.

Summary

You can now create and import data frames, inspect them with head, str, and summary, select rows and columns with square brackets, derive new columns, sort with order, and summarize by group with aggregate. These base R skills remain useful everywhere. Next you will learn to write your own functions and use R's apply family, which let you reuse logic instead of copying code.

Related tutorials

Comments

Log in or create a free account to join the discussion.

  • No comments yet. Be the first to comment.