Reading Data (CSV)

Reviewed & published by Brayan K

Reading data is how you get real datasets into R — read.csv() turns a comma-separated file into a data frame you can explore, clean, and analyse.

Part of the free R course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.

By the end of this lesson you'll load CSV files (and inline CSV text) into data frames, check the result with str(), control the separator and missing-value handling, and work with NA values safely.

What You'll Learn in This Lesson

1️⃣ Reading a CSV File

read.csv("file.csv") reads the file into a data frame, using the first row as column names. The path is relative to your working directory. Always follow up with str() to confirm the types.

# read.csv() loads a CSV file into a data frame. Here sales.csv contains:
#   product,units,price
#   pen,120,2.5
#   pad,80,5.0
#   ink,45,9.0

# Write the file first so this block runs anywhere, then read it back:
writeLines(c("product,units,price", "pen,120,2.5", "pad,80,5.0", "ink,45,9.0"), "sales.csv")
sales <- read.csv("sales.csv")
sales
#   product units price
# 1     pen   120   2.5
# 2     pad    80   5.0
# 3     ink    45   9.0

str(sales)           # check the column types after loading

2️⃣ Reading Inline CSV Text

For quick tests (and for this course), you can pass CSV text directly with text =. It behaves exactly like reading a file, so it's perfect for experimenting without a file on disk.

# You can also read CSV text directly with text=, which is great for testing
# without needing a file on disk.

csv_text <- "name,age,city
Ada,36,London
Bob,28,Paris
Cara,41,Berlin"

people <- read.csv(text = csv_text)
nrow(people)         # -> [1] 3
people$age           # -> [1] 36 28 41
mean(people$age)     # -> [1] 35

3️⃣ Separators and Missing Values

Real files aren't always clean. Use sep for non-comma separators and na.strings to mark placeholders as missing. Once data has NA, statistics need na.rm = TRUE to skip them.

# Useful read.csv() options for messy real-world files:
#   header     - is the first row column names? (default TRUE)
#   sep        - the separator (use ";" or "\t" for other formats)
#   na.strings - which text counts as missing
#   stringsAsFactors - keep text as character (FALSE, the modern default)

raw <- "id;score
1;88
2;NA
3;95"

df <- read.csv(text = raw, sep = ";", na.strings = "NA")
df$score                       # -> [1] 88 NA 95
mean(df$score)                 # -> [1] NA   (NA spreads)
mean(df$score, na.rm = TRUE)   # -> [1] 91.5 (skip missing)

Your turn. Fill in the ___ blank, run it, and compare with the expected output.

# 🎯 YOUR TURN — replace each ___ then run it.

csv_text <- "fruit,kg
apple,3
banana,5
cherry,2"

# 1) Read the CSV text into a data frame
fruit <- ___(text = csv_text)   # 👉 replace ___ with read.csv

# 2) Print the total kilograms with sum()
cat("Total kg:", sum(fruit$kg), "\n")

# 3) Print how many rows there are
cat("Rows:", nrow(fruit), "\n")

# ✅ Expected output:
# Total kg: 10
# Rows: 3

Mini-Challenge: Missing Temperatures

Write it from the outline, run it, and check it against the example output. Handling that one NA correctly is the whole point.

# 🎯 MINI-CHALLENGE: analyse a temperatures CSV.
#
# Use this inline CSV text:
#   day,temp
#   Mon,18
#   Tue,21
#   Wed,NA
#   Thu,17
#
# 1. Read it with read.csv(text = ...).
# 2. Print the average temp, skipping NA (mean(..., na.rm = TRUE)).
# 3. Print how many days are missing a reading
#    (hint: sum(is.na(df$temp))).
#
# ✅ Example output:
#    Average temp: 18.7
#    Missing days: 1

# your code here

Common Errors (and the fix)

Pro Tips

📋 Quick Reference — Reading Data

TaskR Syntax
Read a CSV fileread.csv("f.csv")
Read CSV textread.csv(text = s)
Other separatorread.csv(f, sep = ";")
Mark missingna.strings = "N/A"
Count missingsum(is.na(x))
Stats ignoring NAmean(x, na.rm = TRUE)

🎉 Lesson Complete!

Practice quiz

Which function reads a CSV file into a data frame?

  • read.table.only()
  • read.csv()
  • load.csv()
  • open.csv()

Answer: read.csv(). read.csv() loads a comma-separated file into a data frame.

How do you read CSV from a text string instead of a file?

  • read.csv(file = s)
  • read.csv(string = s)
  • read.csv(text = s)
  • read.csv(s, inline = TRUE)

Answer: read.csv(text = s). Passing text = supplies CSV content directly, no file needed.

What does the header argument default to in read.csv()?

  • FALSE
  • TRUE
  • NULL
  • "auto"

Answer: TRUE. header defaults to TRUE, treating the first row as column names.

Which argument changes the field separator to a semicolon?

  • delim = ";"
  • split = ";"
  • field = ";"
  • sep = ";"

Answer: sep = ";". sep = ";" tells read.csv() to split on semicolons.

What does NA represent in R?

  • A missing (not available) value
  • The number zero
  • An empty string
  • A syntax error

Answer: A missing (not available) value. NA marks a missing value; calculations on it return NA by default.

What does mean(x) return when x contains an NA?

  • The mean of non-NA values
  • Zero
  • NA
  • An error

Answer: NA. By design NA spreads, so mean() returns NA unless told otherwise.

How do you compute the mean while skipping missing values?

  • mean(x, skip = TRUE)
  • mean(x, ignore = NA)
  • mean(na.omit)
  • mean(x, na.rm = TRUE)

Answer: mean(x, na.rm = TRUE). na.rm = TRUE removes NA values before computing.

Which argument marks specific text as missing while reading?

  • na.strings
  • missing
  • fill
  • blank.lines

Answer: na.strings. na.strings lists the tokens that should be read as NA.

How do you count the missing values in a vector x?

  • count.na(x)
  • length(NA)
  • sum(is.na(x))
  • nrow(x)

Answer: sum(is.na(x)). is.na(x) gives a logical vector; sum() counts the TRUEs.

Why run str() right after reading a CSV?

  • To delete the file
  • To confirm the columns came in with the expected types
  • To plot the data
  • To rename the file

Answer: To confirm the columns came in with the expected types. str() reveals each column's type so you catch numbers read as text early.

Continue this course

Frequently asked questions

How do I read a CSV file into R?

Use read.csv("path/to/file.csv"), which returns a data frame with one column per CSV column. The path is relative to your working directory, so if R can't find the file, check getwd() and make sure the file is there (or give a full path). After reading, always run str() to confirm the columns came in with the types you expect — a number accidentally read as text is a common surprise.

Why are my numbers showing up as text?

Usually because the column contains something non-numeric — a stray currency symbol, a thousands comma like '1,000', or a placeholder such as 'N/A'. R sees the mixed content and reads the whole column as character to be safe. Fix it by cleaning the source, using the na.strings argument to mark placeholders as missing, or converting afterwards with as.numeric() once the offending characters are removed.

What is NA and how do I handle missing values?

NA means 'not available' — a missing value. By design, calculations involving NA return NA, so mean(x) on data with a gap gives NA rather than silently ignoring it. That's a safety feature. To compute anyway, pass na.rm = TRUE (e.g. mean(x, na.rm = TRUE)). Use is.na(x) to find missing values and sum(is.na(x)) to count them. Deciding how to handle missing data is a real part of analysis, not just a technicality.

What if my file uses semicolons or tabs instead of commas?

read.csv() assumes commas, but you can set the separator with sep. Use read.csv(file, sep = ";") for semicolon-separated files (common in some European locales) or sep = " " for tab-separated. There's also read.delim() for tabs and the general read.table() for full control. For very large files, the readr package's read_csv() and data.table's fread() are faster, but base read.csv() is perfect for learning.