Skip to content

R - CSV Files

R is exceptionally powerful for data analysis, and a common first step is to import data from external files. Comma-Separated Values (CSV) files are one of the most common formats for storing tabular data. This chapter will guide you through the modern, efficient, and reproducible way of reading and writing CSV files in R using the Tidyverse.

Best Practice: Reproducible Workflows with RStudio Projects

Section titled “Best Practice: Reproducible Workflows with RStudio Projects”

Before we read any files, it’s crucial to set up our project for success. A common but problematic practice for beginners is using setwd() to change the working directory. This makes your code fragile and hard for others to run.

The modern, best-practice approach is to use RStudio Projects. An RStudio Project (.Rproj file) anchors your work to a specific directory. When you open a project, the working directory is automatically set to the project’s root folder. This ensures that file paths like "data/input.csv" always work, no matter where the project folder is located on your computer.

How to start:

  1. In RStudio, go to File > New Project... > New Directory > New Project.
  2. Give your project a name (e.g., r-data-analysis).
  3. Create a subfolder inside your project named data and save your CSV files there.

First, let’s ensure you have the necessary tools. We’ll be using packages from the tidyverse, a collection of R packages designed for data science. If you haven’t installed it yet, run this in your R console:

install.packages("tidyverse")

Next, create a CSV file named input.csv in your project’s data subfolder with the following content. You can use a plain text editor or a spreadsheet program.

id,name,salary,start_date,dept
1,Rick,623.3,2012-01-01,IT
2,Dan,515.2,2013-09-23,Operations
3,Michelle,611,2014-11-15,IT
4,Ryan,729,2014-05-11,HR
,Gary,843.25,2015-03-27,Finance
6,Nina,578,2013-05-21,IT
7,Simon,632.8,2013-07-30,Operations
8,Guru,722.5,2014-06-17,Finance

The readr package (part of the tidyverse) provides read_csv(), a fast and modern function for reading CSV files. It’s generally preferred over the base R read.csv() because it’s faster, provides more informative output, and creates tibbles instead of standard data frames.

# Load the tidyverse library, which includes readr and dplyr
library(tidyverse)
# Define the file path relative to the project root
file_path <- "data/input.csv"
# Read the CSV file into a tibble
employee_data <- read_csv(file_path)
# Print the tibble to see its contents and structure
print(employee_data)

When you run this code, read_csv() will print a summary of the column specifications, which is extremely helpful for debugging.

Rows: 8 Columns: 5
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
dbl (2): id, salary
chr (2): name, dept
dte (1): start_date
# A tibble: 8 × 5
id name salary start_date dept
<dbl> <chr> <dbl> <date> <chr>
1 1 Rick 623. 2012-01-01 IT
2 2 Dan 515. 2013-09-23 Operations
3 3 Michelle 611 2014-11-15 IT
4 4 Ryan 729 2014-05-11 HR
5 NA Gary 843. 2015-03-27 Finance
6 6 Nina 578 2013-05-21 IT
7 7 Simon 633. 2013-07-30 Operations
8 8 Guru 722. 2014-06-17 Finance

Once your data is loaded into a tibble, you can use the dplyr package (also part of the tidyverse) to manipulate and analyze it. dplyr uses a set of intuitive ‘verbs’ and the pipe operator %>% to create highly readable data analysis pipelines.

We use summarize() to calculate summary statistics. It’s good practice to handle potential missing values (NA) using na.rm = TRUE.

# Find the maximum salary, ignoring any NA values
max_salary <- employee_data %>%
summarize(max_sal = max(salary, na.rm = TRUE))
print(max_salary)

Result:

# A tibble: 1 × 1
max_sal
<dbl>
1 843.

Get the details of the employee(s) with the maximum salary

Section titled “Get the details of the employee(s) with the maximum salary”

We use filter() to subset rows based on a condition.

# Filter the data to find the employee with the highest salary
top_earner <- employee_data %>%
filter(salary == max(salary, na.rm = TRUE))
print(top_earner)

Result:

# A tibble: 1 × 5
id name salary start_date dept
<dbl> <chr> <dbl> <date> <chr>
1 NA Gary 843. 2015-03-27 Finance
# Filter for employees in the 'IT' department
it_employees <- employee_data %>%
filter(dept == "IT")
print(it_employees)

Result:

# A tibble: 3 × 5
id name salary start_date dept
<dbl> <chr> <dbl> <date> <chr>
1 1 Rick 623. 2012-01-01 IT
2 3 Michelle 611 2014-11-15 IT
3 6 Nina 578 2013-05-21 IT

Get IT employees with a salary greater than 620

Section titled “Get IT employees with a salary greater than 620”

You can combine multiple conditions within a single filter() call.

# Combine multiple filter conditions (comma implies AND)
info <- employee_data %>%
filter(dept == "IT", salary > 620)
print(info)

Result:

# A tibble: 1 × 5
id name salary start_date dept
<dbl> <chr> <dbl> <date> <chr>
1 1 Rick 623. 2012-01-01 IT

Get employees who joined on or after January 1, 2014

Section titled “Get employees who joined on or after January 1, 2014”

Because read_csv correctly identified the start_date column as a date, we can filter it directly.

# Filter based on the date column
recent_hires <- employee_data %>%
filter(start_date >= as.Date("2014-01-01"))
print(recent_hires)

Result:

# A tibble: 4 × 5
id name salary start_date dept
<dbl> <chr> <dbl> <date> <chr>
1 3 Michelle 611 2014-11-15 IT
2 4 Ryan 729 2014-05-11 HR
3 NA Gary 843. 2015-03-27 Finance
4 8 Guru 722. 2014-06-17 Finance

After filtering or transforming your data, you’ll often want to save the result. readr::write_csv() is the perfect counterpart to read_csv(). It efficiently writes a data frame or tibble to a CSV file.

A key advantage of write_csv() is that it does not write row names by default, which prevents the common issue of an extra, unnamed column appearing in your output file.

# Using the 'recent_hires' tibble from the previous step...
# Define the output file path
output_path <- "data/output.csv"
# Write the filtered data to a new CSV file
write_csv(recent_hires, output_path)
# To verify, you can read the new file back in and print it
new_data <- read_csv(output_path)
print(new_data)

The resulting output.csv file will be clean and correctly formatted, containing only the data you intended to save.

# A tibble: 4 × 5
id name salary start_date dept
<dbl> <chr> <dbl> <date> <chr>
1 3 Michelle 611 2014-11-15 IT
2 4 Ryan 729 2014-05-11 HR
3 NA Gary 843. 2015-03-27 Finance
4 8 Guru 722. 2014-06-17 Finance