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
- How to read a CSV file with read.csv()
- How to read inline CSV text with text =
- Why you should str() right after loading
- How to set the separator with sep
- What NA is and how na.strings marks missing data
- How na.rm = TRUE handles missing values in stats
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 loading2️⃣ 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] 353️⃣ 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: 3Mini-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 hereCommon Errors (and the fix)
- "cannot open file ...: No such file or directory" — the path is wrong or the working directory isn't where the file lives. Check getwd().
- Numbers read as text — a stray symbol or comma in the column. Clean it or use na.strings, then convert with as.numeric().
- mean() returns NA — there are missing values. Add na.rm = TRUE to skip them.
- Everything in one column — the file uses a different separator. Set sep = ";" or sep = "\t".
Pro Tips
- 💡 Inspect immediately: str() and summary() right after loading catch most data problems.
- 💡 Read straight from a URL: read.csv("https://...") works for public CSV links.
- 💡 Faster for big files: readr::read_csv() and data.table::fread() handle large data quickly.
📋 Quick Reference — Reading Data
| Task | R Syntax |
|---|---|
| Read a CSV file | read.csv("f.csv") |
| Read CSV text | read.csv(text = s) |
| Other separator | read.csv(f, sep = ";") |
| Mark missing | na.strings = "N/A" |
| Count missing | sum(is.na(x)) |
| Stats ignoring NA | mean(x, na.rm = TRUE) |
🎉 Lesson Complete!
- ✅ read.csv() turns a CSV into a data frame
- ✅ text = reads inline CSV for quick tests
- ✅ Always str() after loading to check types
- ✅ sep and na.strings handle messy files
- ✅ na.rm = TRUE computes stats despite missing data
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
- Previous: Data Frames
- Next: The apply Family — Apply functions over rows, columns, and lists without loops
- Quick reference: R cheat sheet › I/O
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.