Read CSV in R
It is usual to find datasets in CSV (comma separated values) format. This type of data storage is a lightweight solution for the most use cases. In this tutorial you will learn how to read a CSV in R to work with.
Quick answer
To read a CSV file in R use read.csv("file.csv") and assign the result to a variable. If the file uses semicolons as separator and commas as decimal mark, use read.csv2 instead.
name,age,city,score
Ana,28,Madrid,7.5
Bob,35,London,8.1
Carla,41,Paris,6.9
David,23,Berlin,9.2
df <- read.csv("my_file.csv") # Comma separated, dot as decimal mark
# df <- read.csv2("my_file.csv") # Semicolon separated, comma as decimal mark
head(df)
name age city score
1 Ana 28 Madrid 7.5
2 Bob 35 London 8.1
3 Carla 41 Paris 6.9
4 David 23 Berlin 9.2
The file must be in your working directory or you must write its full path. For big files, readr::read_csv and data.table::fread are much faster.
How to read a CSV file in R?
In this section you will learn how to import a CSV file in R with the read.csv and read.csv2 functions. You can see the basic syntax of the functions with the most common arguments in the following code block. For additional details remember to type ?read.csv or ?read.csv2.
# Comma as separator and dot as decimal point by default
read.csv(file, # File name or full path of the file
header = TRUE, # Whether to read the header or not
sep = ",", # Separator of the values
quote = "\"", # Quoting character
dec = ".", # Decimal point
fill = TRUE, # Whether to fill blanks or not
comment.char = "", # Character of the comments or empty string
encoding = "unknown", # Encoding of the file
...) # Additional arguments
# Semicolon as separator and comma as decimal point by default
read.csv2(file, header = TRUE, sep = ";", quote = "\"", dec = ",",
fill = TRUE, comment.char = "", encoding = "unknown", ...)
You may have noticed that the only differences between the functions are the separator of the values and the decimal separator, because in some countries they use commas as decimal separator.
In the second case, in order to create CSV files the semicolon is needed if some numbers are decimals. As you may find datasets with both characteristics, you can use the corresponding function instead of changing the parameters of the arguments.
The following table summarizes the three main default arguments:
| Function | Header | Sep | Dec |
|---|---|---|---|
| read.csv | TRUE | “,” | “.” |
| read.csv2 | TRUE | “;” | “,” |
In order to load a CSV file in R with the default arguments, you can pass the file as string to the corresponding function. The output will be of class data.frame.
read.csv("my_file.csv")
If you just execute the previous code you will print the data frame but it will not be stored in memory, since you have not assigned it to any variable. If you save it in a variable called my_file, you will be able to access the variables or the data you want.
my_file <- read.csv("my_file.csv")
The file must be on your working directory. If not, you will need to specify the full path of the file in the file argument.
CSV file header
By default, the functions read the header of the files. In case you want to read the CSV without header you will need to set to FALSE the header argument.
read.csv("my_file.csv", header = FALSE)
CSV encoding
A common issue arises with bad encoding of the files. In case you are reading a file with rare characters you maybe need to specify the encoding. Setting the encoding to UTF-8 tends to solve the most of these problems.
read.csv("my_file.csv", encoding = "UTF-8")
The encoding argument only marks the strings as UTF-8. If accents or special characters still look wrong, use fileEncoding instead, which re-encodes the file while reading it. Files with accents saved on Windows are often encoded as "latin1".
read.csv("my_file.csv", fileEncoding = "UTF-8")
read.csv("my_file.csv", fileEncoding = "latin1")
Note that this argument and the following are inherited from the read.table function.
The na.strings argument
Sometimes the files contain some character string that represents missing or omitted values. You will find more information about how missing values are handled in the source of the data set you are working with. In order to solve this issue you can convert them to NA values with the na.strings argument, specifying the character string that represents the missing value.
Consider, for instance, that in your CSV file the -9999 values represent missing data. In this scenario you could type:
read.csv("my_file.csv", na.strings = "-9999")
Moreover, in case the file contains multiple na.strings you can specify all inside a vector.
read.csv("my_file.csv", na.strings = c("-9999" , "Na" ))
However, if you need to remove NA values or the value specified as it after importing you will need to use the corresponding function depending on your data. The most common function to remove missing values is na.omit.
The stringsAsFactors argument
The stringsAsFactors argument of the function will transform the string (character) columns of the dataset into factors. Since R 4.0.0 its default value is FALSE, so text columns are read as character unless you set it to TRUE.
df <- read.csv("my_file.csv", stringsAsFactors = TRUE)
str(df)
'data.frame': 4 obs. of 4 variables:
$ name : Factor w/ 4 levels "Ana","Bob","Carla",..: 1 2 3 4
$ age : int 28 35 41 23
$ city : Factor w/ 4 levels "Berlin","London",..: 3 2 4 1
$ score: num 7.5 8.1 6.9 9.2
Read only some rows or columns: nrows, skip and colClasses
You don’t need to load the whole file if you only need a part of it. The nrows argument sets the maximum number of rows to read, which is useful to take a quick look at a big file:
read.csv("my_file.csv", nrows = 2)
name age city score
1 Ana 28 Madrid 7.5
2 Bob 35 London 8.1
The skip argument skips the first lines of the file, for instance notes written before the data. Note that the header is a line too, so if you skip it you will need to set header = FALSE (and optionally pass the names with col.names):
read.csv("my_file.csv", skip = 2, header = FALSE)
V1 V2 V3 V4
1 Bob 35 London 8.1
2 Carla 41 Paris 6.9
3 David 23 Berlin 9.2
Finally, colClasses lets you set the class of each column. Use "NULL" to drop a column while reading, which saves memory with large files:
read.csv("my_file.csv",
colClasses = c("character", "integer", "NULL", "numeric"))
name age score
1 Ana 28 7.5
2 Bob 35 8.1
3 Carla 41 6.9
4 David 23 9.2
If you prefer to select the columns by name, fread has the select argument and read_csv the col_select argument, as you will see below.
Numbers read as character: decimal commas and thousands separators
A very common issue is a numeric column that R reads as character. This happens when the format of the numbers doesn’t match the sep and dec arguments. Consider the following file, which uses semicolons as separator and commas as decimal mark:
product;price;units
A;12,50;3
B;980,75;12
C;7,00;7
If you read it with read.csv all the data ends in a single column, because there are no commas separating the values. Use read.csv2 or set sep = ";" and dec = ",":
df <- read.csv2("european.csv")
# Equivalent to:
# df <- read.csv("european.csv", sep = ";", dec = ",")
str(df)
'data.frame': 3 obs. of 3 variables:
$ product: chr "A" "B" "C"
$ price : num 12.5 980.8 7
$ units : int 3 12 7
Thousands separators are another source of problems, as read.csv has no argument for them. If the file contains values such as "1,200", the column will be read as character:
id,amount
1,"1,200"
2,"15,000"
3,"850"
df <- read.csv("thousands.csv")
str(df)
'data.frame': 3 obs. of 2 variables:
$ id : int 1 2 3
$ amount: chr "1,200" "15,000" "850"
The solution is to remove the separator with gsub and convert the column to numeric:
df$amount <- as.numeric(gsub(",", "", df$amount))
str(df)
'data.frame': 3 obs. of 2 variables:
$ id : int 1 2 3
$ amount: num 1200 15000 850
The read_csv function of readr handles this case automatically, and you can set any combination of marks with its locale argument, for instance locale = locale(decimal_mark = ",", grouping_mark = ".").
Choose the CSV file interactively with file.choose
If you don’t want to type the path, you can use file.choose() inside read.csv. It will open a window where you can browse and select the file:
df <- read.csv(file.choose())
This is handy for quick analyses, but avoid it in scripts that you will run again, as you will need to select the file every time and your code won’t be reproducible.
Read a CSV from a URL
The file argument also accepts a URL, so you can import a CSV file from the internet directly, without downloading it first:
url <- "https://raw.githubusercontent.com/tidyverse/readr/main/inst/extdata/mtcars.csv"
df <- read.csv(url)
head(df, 3)
mpg cyl disp hp drat wt qsec vs am gear carb
1 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
2 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
3 22.8 4 108 93 3.85 2.320 18.61 1 1 4 4
read_csv and fread can read URLs in the same way. If you use GitHub, remember to use the “raw” link of the file and not the link of the web page.
read.csv vs read_csv (readr) vs fread (data.table)
Base R read.csv is enough for small and medium files, but there are two popular alternatives: read_csv from the readr package (part of the tidyverse) and fread from data.table. You will need to install the packages first.
The read_csv function returns a tibble and prints a summary of the type it guessed for each column:
# install.packages("readr")
library(readr)
df <- read_csv("my_file.csv")
df
Rows: 4 Columns: 4
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (2): name, city
dbl (2): age, score
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# A tibble: 4 × 4
name age city score
<chr> <dbl> <chr> <dbl>
1 Ana 28 Madrid 7.5
2 Bob 35 London 8.1
3 Carla 41 Paris 6.9
4 David 23 Berlin 9.2
The fread function returns a data.table and detects the separator automatically, so the same call works for comma, semicolon or tab separated files:
# install.packages("data.table")
library(data.table)
df <- fread("my_file.csv")
df
name age city score
<char> <int> <char> <num>
1: Ana 28 Madrid 7.5
2: Bob 35 London 8.1
3: Carla 41 Paris 6.9
4: David 23 Berlin 9.2
Both functions can read only some columns by name:
read_csv("my_file.csv", col_select = c(name, score))
fread("my_file.csv", select = c("name", "score"))
The main differences are summarized in the following table:
| read.csv | readr::read_csv | data.table::fread | |
|---|---|---|---|
| Output class | data.frame | tibble | data.table |
| Speed | Slow | Fast | Fastest |
| Separator | “,” (sep) | “,” (read_csv2 or read_delim for others) | Detected automatically |
| Text columns | character (factor with stringsAsFactors = TRUE) | character | character |
| Column names | Made syntactic (“first name” → “first.name”) | Kept as they are | Kept as they are |
| Encoding | System default (fileEncoding) | UTF-8 (locale) | encoding argument |
| Select columns | colClasses = “NULL” | col_select | select |
To give you an idea of the speed difference, this is the time (in seconds) that each function took to read a CSV file with one million rows and four columns on our computer:
system.time(read.csv("big.csv"))
system.time(read_csv("big.csv", show_col_types = FALSE))
system.time(fread("big.csv"))
user system elapsed
3.49 0.22 3.79
user system elapsed
1.14 0.76 0.23
user system elapsed
0.13 0.08 0.03
The exact times will depend on your computer, but fread and read_csv are usually more than ten times faster than read.csv with large files.
If you work with base R data frames, you can convert the output of read_csv or fread with as.data.frame(). Both tibbles and data.tables are also data frames, so most functions will work with them directly.
Read multiple CSV files in R
It is worth mentioning that it is possible to import multiple CSV files at the same time instead of loading them into R one by one. For that purpose you can use the list.files function in order to look for all CSV files and then read them applying the read.csv (or read.csv2) function with the sapply function.
files <- list.files(pattern = "*.csv")
multiple_csv <- sapply(files, read.csv)
If all the files have the same columns, you can read them with lapply and stack them into a single data frame with rbind:
files <- list.files(pattern = "\\.csv$")
all_data <- do.call(rbind, lapply(files, read.csv))
Common errors when reading a CSV in R
cannot open file ‘x.csv’: No such file or directory
This is the most common error. It means that R can’t find the file in the path you wrote:
read.csv("data.csv")
Error in file(file, "rt") : cannot open the connection
In addition: Warning message:
In file(file, "rt") :
cannot open file 'data.csv': No such file or directory
To fix it, check the following:
- The file is in your working directory. You can see it with
getwd()and the files on it withlist.files(). - The name and the extension are correct. Windows hides extensions by default, so a file called
data.csvmay bedata.csv.txtin reality.file.exists("data.csv")must returnTRUE. - If you write the full path on Windows, use forward slashes (
"C:/Users/me/data.csv") or double backslashes ("C:\\Users\\me\\data.csv"), never single backslashes.
more columns than column names
This error appears when some rows have more values than the header:
name,age
Ana,28,Madrid,7.5
Bob,35,London,8.1
read.csv("bad.csv")
Error in read.table(file = file, header = header, sep = sep, quote = quote, :
more columns than column names
It is usually caused by an incomplete header, by a wrong separator or by text values with commas that are not quoted. If the header is wrong, skip it and set the names yourself:
read.csv("bad.csv", header = FALSE, skip = 1,
col.names = c("name", "age", "city", "score"))
name age city score
1 Ana 28 Madrid 7.5
2 Bob 35 London 8.1
incomplete final line found by readTableHeader
This warning means that the last line of the file doesn’t end with a line break:
df <- read.csv("noeol.csv")
Warning message:
In read.table(file = file, header = header, sep = sep, quote = quote, :
incomplete final line found by readTableHeader on 'noeol.csv'
It is just a warning and the data is read correctly. You can ignore it or remove it by opening the file in a text editor and pressing Enter at the end of the last line.
duplicate ‘row.names’ are not allowed
Error in read.table(file = file, header = header, sep = sep, quote = quote, :
duplicate 'row.names' are not allowed
R uses the first column as row names in two cases: when you set row.names = 1 and when the data rows have one value more than the header, which typically happens when every line ends with a comma:
name,age,city
Ana,28,Madrid,
Ana,35,London,
As row names must be unique, the repeated "Ana" causes the error. If you used row.names = 1, just remove it. In the case of the trailing commas, set row.names = NULL and shift the column names:
df <- read.csv("trailing_comma.csv", row.names = NULL)
colnames(df) <- c(colnames(df)[-1], "empty")
df$empty <- NULL
df
name age city
1 Ana 28 Madrid
2 Ana 35 London