7  Dataframes in R

Learning Objectives: After this chapter you will be able to:

  • Create a data frame from equal-length vectors.
  • Inspect one with str(), dim(), names(), and nrow()/ncol().
  • Select columns with [, [[, and $.
  • Select rows by position and by condition.
  • Subset rows and columns independently.
  • Explain why stringsAsFactors defaults to FALSE in R 4.0.0 and later.

7.1 Introduction

Data frames are lists of equal-length vectors, so they can hold columns of different types.

7.2 Create dataframes

Use data.frame to create dataframes. Below is the function syntax:

args(data.frame)
function (..., row.names = NULL, check.rows = FALSE, check.names = TRUE, 
    fix.empty.names = TRUE, stringsAsFactors = FALSE) 
NULL

Data frames are basically lists with elements of equal length and as such, they are heterogeneous. Let us create a dataframe:

name <- c('John', 'Jack', 'Jill')
age <- c(29, 25, 27)
graduate <- c(TRUE, TRUE, FALSE)
students <- data.frame(name, age, graduate)
students
  name age graduate
1 John  29     TRUE
2 Jack  25     TRUE
3 Jill  27    FALSE

7.3 Basic Information

class(students)
## [1] "data.frame"
names(students)
## [1] "name"     "age"      "graduate"
colnames(students)
## [1] "name"     "age"      "graduate"
str(students)
## 'data.frame':    3 obs. of  3 variables:
##  $ name    : chr  "John" "Jack" "Jill"
##  $ age     : num  29 25 27
##  $ graduate: logi  TRUE TRUE FALSE
dim(students)
## [1] 3 3
nrow(students)
## [1] 3
ncol(students)
## [1] 3

7.4 Select Columns

7.4.1 Single Column

  • []
  • [[]]
  • $
# using [
students[1]
##   name
## 1 John
## 2 Jack
## 3 Jill

# using [[
students[[1]]
## [1] "John" "Jack" "Jill"

# using $
students$name
## [1] "John" "Jack" "Jill"

7.4.2 Multiple Columns

students[, 1:3]
##   name age graduate
## 1 John  29     TRUE
## 2 Jack  25     TRUE
## 3 Jill  27    FALSE

students[, c(1, 3)]
##   name graduate
## 1 John     TRUE
## 2 Jack     TRUE
## 3 Jill    FALSE

7.5 Select Rows

# single row
students[1, ]
##   name age graduate
## 1 John  29     TRUE

# multiple row
students[c(1, 3), ]
##   name age graduate
## 1 John  29     TRUE
## 3 Jill  27    FALSE

Try it in your browser

Edit the code below and press Run. It executes entirely in your browser via WebR β€” no R installation needed. The runtime downloads once, on this page only.

Starting with R 4.0.0 (April 2020), the default value of stringsAsFactors in data.frame() is FALSE, meaning character columns remain as character type. In older versions of R (< 4.0.0), the default was TRUE, which automatically converted character vectors to factors.

Common Mistake: Assuming data.frame() still converts strings to factors. That was the default before R 4.0.0 and was a frequent source of confusion. On R >= 4.0.0 the default is FALSE.

students <- data.frame(name, age, graduate, stringsAsFactors = FALSE)

7.6 Practice Check

Knowledge Check: One column, three operators What do students[1], students[[1]], and students$name each return?

Click to reveal answer

Answer: A one-column data frame; a vector; and the same vector.

Explanation: [ always returns a data frame, even for a single column, so downstream code that expects a vector breaks. [[ and $ both extract the column itself as a vector. Reach for [[ or $ whenever you want the values.

Knowledge Check: Rows and columns are indexed separately What does students[1, ] return, and how does that differ from students[, 1]?

Click to reveal answer

Answer: students[1, ] returns the first row; students[, 1] returns the first column. The comma is what separates the two.

Explanation: Inside [ the first position selects rows and the second selects columns. Leaving one side empty means β€œall of them”. So students[1, ] is row 1, students[, 1] is column 1, and students[1, 1] is the single cell where they cross.

Knowledge Check: Filtering rows by a condition How do you return only the students older than 26?

Click to reveal answer

Answer: students[students$age > 26, ], which gives John (29) and Jill (27).

Explanation: The condition builds a logical vector with one value per row. Using it as the row index keeps the rows where the condition is TRUE and drops the rest. Because the condition has the same length as the data frame, the column is left out of the result.

Knowledge Check: How many rows and columns? The data frame has three columns and three rows. Which two functions report those counts directly?

Click to reveal answer

Answer: nrow(students) gives 3 and ncol(students) gives 3. Both are also available together as dim(students), which returns c(3, 3).

Explanation: dim() returns rows first, then columns, so dim(students)[1] is the row count. str() gives you a structural overview while nrow() and ncol() answer the two specific questions directly.

Knowledge Check: stringsAsFactors changed in R 4.0.0 In R 4.0.0 and later, what does data.frame(name, age, graduate) do with the character column name?

Click to reveal answer

Answer: It keeps it as character. Before R 4.0.0 the default was TRUE, which silently converted character columns to factors.

Explanation: The old default caused endless confusion, because strings became categories and levels were alphabetised behind your back. Passing stringsAsFactors = FALSE is now redundant on R >= 4.0.0, but it keeps code readable and portable to older R.