R Basics: Vectors and Types
Vectors are the most fundamental data structure in R. Unlike many other programming languages, everything in R is a vector—even a single value is technically a vector of length one. Understanding vectors and their types is essential for writing effective R code.
This tutorial covers creating vectors, understanding atomic types, performing operations, and managing type coercion.
What Are Vectors?
A vector is an ordered collection of values of the same type. R stores vectors efficiently in memory and provides vectorized operations that work on entire vectors at once.
Creating Vectors with c()
The c() function (combine) creates vectors by joining values together:
# Numeric vector
numbers <- c(1, 2, 3, 4, 5)
numbers
# [1] 1 2 3 4 5
# Character vector
names <- c("Alice", "Bob", "Charlie")
names
# [1] "Alice" "Bob" "Charlie"
# Logical vector
flags <- c(TRUE, FALSE, TRUE)
flags
# [1] TRUE FALSE TRUE
Checking Vector Properties
R provides functions to inspect vectors:
# Length of a vector
length(numbers)
# [1] 5
# Check if it's a vector
is.vector(numbers)
# [1] TRUE
Atomic Types in R
R has six atomic vector types. The four most common are:
Numeric
The default type for numbers. R uses double-precision floating-point arithmetic:
# Numeric (double) is the default
x <- 3.14
typeof(x)
# [1] "double"
y <- c(1.5, 2.5, 3.5)
typeof(y)
# [1] "double"
Integer
Whole numbers, created with the L suffix:
# Create integer with L suffix
whole <- c(1L, 2L, 3L)
typeof(whole)
# [1] "integer"
# Also from sequences
seq_int <- 1:5
typeof(seq_int)
# [1] "integer"
Character
Text strings, always wrapped in quotes:
greeting <- "Hello, R!"
typeof(greeting)
# [1] "character"
words <- c("one", "two", "three")
typeof(words)
# [1] "character"
Logical
Boolean values TRUE and FALSE:
is_active <- c(TRUE, FALSE, TRUE, FALSE)
typeof(is_active)
# [1] "logical"
# Can also use T and F (not recommended)
Creating Vectors: Beyond c()
seq() for Sequences
Create sequences with regular intervals:
# Sequence from 1 to 10
1:10
# [1] 1 2 3 4 5 6 7 8 9 10
# Using seq()
seq(1, 10, by = 2)
# [1] 1 3 5 7 9
seq(0, 1, length.out = 5)
# [1] 0.00 0.25 0.50 0.75 1.00
rep() for Repeating Values
Repeat values to fill vectors:
# Repeat single value
rep(1, times = 5)
# [1] 1 1 1 1 1
# Repeat each element
rep(c(1, 2), each = 3)
# [1] 1 1 1 2 2 2
# Repeat entire vector
rep(c(1, 2), times = 3)
# [1] 1 2 1 2 1 2
Vector Operations
One of R’s strengths is vectorized operations:
# Arithmetic operations
c(1, 2, 3) + c(4, 5, 6)
# [1] 5 7 9
c(10, 20, 30) / c(2, 4, 5)
# [1] 5 5 6
# Recycling: shorter vectors are recycled
c(1, 2, 3, 4) + c(1, 2)
# [1] 2 4 4 6
# Warning: longer object length not a multiple of shorter
Recycling with Caution
R recycles shorter vectors but may produce unexpected results:
# What you might expect
c(1, 2, 3) + c(1, 2)
# [1] 2 4 4 (1+1, 2+2, 3+1)
# Always use vectors of equal length for clarity
Checking and Converting Types
Type Checking Functions
x <- c(1, 2, 3)
is.numeric(x)
# [1] TRUE
is.integer(x)
# [1] FALSE (defaults to double)
is.character(x)
# [1] FALSE
# To create integer
y <- c(1L, 2L, 3L)
is.integer(y)
# [1] TRUE
Type Conversion Functions
Convert between types with as.*() functions:
# Numeric to character
as.character(c(1, 2, 3))
# [1] "1" "2" "3"
# Character to numeric
as.numeric(c("1", "2", "3"))
# [1] 1 2 3
# Numeric to logical (0 = FALSE, non-zero = TRUE)
as.logical(c(0, 1, 2, -5))
# [1] FALSE TRUE TRUE TRUE
# Character to logical
as.logical(c("TRUE", "FALSE", "true"))
# [1] TRUE FALSE NA
Implicit Type Coercion
When mixing types, R automatically coerces to the “highest” type:
# Numeric + character = character
c(1, "two", 3)
# [1] "1" "two" "3"
# Logical + numeric = numeric
c(TRUE, 2, 3)
# [1] 1 2 3
# Order: logical → integer → double → character
Common Gotchas
Floating Point Comparison
# This might surprise you
0.1 + 0.2 == 0.3
# [1] FALSE
# Use near-equality
all.equal(0.1 + 0.2, 0.3)
# [1] TRUE
NA Values
NA represents missing values and has its own type:
# NA is typelogical by default
typeof(NA)
# [1] "logical"
# Check for NA
x <- c(1, 2, NA, 4)
is.na(x)
# [1] FALSE FALSE TRUE FALSE
# NA in operations propagates
sum(c(1, 2, NA, 4))
# [1] NA
# Use na.rm = TRUE
sum(c(1, 2, NA, 4), na.rm = TRUE)
# [1] 7
Working with Vectors in Practice
Subsetting Vectors
Access elements using square brackets:
x <- c("a", "b", "c", "d", "e")
# By position
x[1]
# [1] "a"
x[c(1, 3)]
# [1] "a" "c"
# Negative indices remove elements
x[-1]
# [1] "b" "c" "d" "e"
# With logical vector
x[c(TRUE, FALSE, TRUE, FALSE, TRUE)]
# [1] "a" "c" "e"
Naming Vector Elements
# Create named vector
scores <- c(Alice = 95, Bob = 87, Charlie = 92)
scores
# Alice Bob Charlie
# 95 87 92
# Access by name
scores["Alice"]
# Alice
# 95
names(scores)
# [1] "Alice" "Bob" "Charlie"
Summary
- Vectors are R’s fundamental data structure—collections of values of the same type
- The four main atomic types are: numeric, integer, character, and logical
- Use
c(),seq(), andrep()to create vectors - Vectorized operations work on entire vectors, making R efficient
- Type checking:
is.*()functions; conversion:as.*()functions - R coerces types implicitly when needed—understand the hierarchy
Next Steps
Now that you understand vectors, continue with the next tutorial in the r-fundamentals series: Data Frames and Tibbles, where you’ll learn how to work with rectangular data.
Practice what you learned:
# Try creating vectors of different types
numeric_vec <- c(1.5, 2.5, 3.5)
integer_vec <- c(1L, 2L, 3L)
char_vec <- c("apple", "banana", "cherry")
logical_vec <- c(TRUE, FALSE, TRUE)
# Check their types
sapply(list(numeric_vec, integer_vec, char_vec, logical_vec), typeof)