Chapter 11: R Data Types
R Data Types (also called data modes, atomic types, or basic object types).
This is super important because almost everything in R revolves around how data is stored and what you can do with it. If you mix types carelessly, R will silently coerce (change) them — sometimes causing bugs that are hard to spot later.
I’m going to explain like your offline teacher in a calm classroom near Gachibowli: slow, step-by-step, with lots of copy-paste examples, checks you can run right now, common mistakes, and 2026 best practices.
1. Two Big Worlds in R: Atomic vs Recursive Objects
R has two main families:
- Atomic vectors → the simple building blocks (all elements same type) → numeric, integer, logical, character, complex, raw → This is what most people mean when they say “data types” in R
- Recursive objects / containers → can hold different types inside → lists, data.frames, matrices, arrays, factors (special case), etc.
Today we focus on atomic data types — because everything else is built from them.
2. The 6 Main Atomic Data Types (What You Really Use Every Day)
| # | Type (what typeof() shows) | What it stores | Example creation | Common check functions | Notes / 2026 reality |
|---|---|---|---|---|---|
| 1 | double (aka numeric) | Real numbers (with decimals) | 3.14, c(1.5, 2, 10.7) | is.numeric(), is.double() | Default for most numbers |
| 2 | integer | Whole numbers only | 5L, 1:10, as.integer(7) | is.integer() | Must use L suffix |
| 3 | logical | TRUE / FALSE | TRUE, c(TRUE, FALSE, T, F) | is.logical() | T/F are shortcuts |
| 4 | character | Text / strings | “Hyderabad”, ‘2026’ | is.character() | Most flexible type |
| 5 | complex | Numbers with imaginary part | 2 + 3i, 1i | is.complex() | Math / signal processing |
| 6 | raw | Bytes (raw binary data) | charToRaw(“A”), as.raw(65) | is.raw() | Rare for beginners |
3. How to Check Data Type (Run These Right Now!)
R gives you several ways — they sometimes give different answers!
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
x <- 3.14 typeof(x) # "double" ← most accurate low-level type class(x) # "numeric" ← what most functions see mode(x) # "numeric" ← old-school name storage.mode(x) # "double" ← storage details y <- 42L typeof(y) # "integer" class(y) # "integer" z <- "Hyderabad 2026" typeof(z) # "character" class(z) # "character" |
Quick rule 2026:
- Use typeof() for precise internal type (what storage uses)
- Use class() for what behaves like (S3 object system)
- Use str() or glimpse() (from dplyr) for friendly overview
4. Hands-on Examples — Create & Play
Open RStudio → new script → run line by line (Ctrl+Enter)
Numeric (double) – Most common
|
0 1 2 3 4 5 6 7 8 9 10 |
pi_value <- 3.14159 temps_hyd <- c(28.5, 29.8, 30.2, 27.9) class(temps_hyd) # "numeric" typeof(temps_hyd) # "double" is.numeric(temps_hyd) # TRUE |
Integer – Whole numbers (save memory in big data)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 |
counts <- 1:5 # special shortcut → integers ages <- c(22L, 25L, 19L) class(ages) # "integer" typeof(ages) # "integer" # Without L → becomes double! wrong <- c(22, 25, 19) typeof(wrong) # "double" ← careful! |
Logical – For conditions, filtering
|
0 1 2 3 4 5 6 7 8 9 10 11 |
is_hot <- temps_hyd > 29 is_hot # FALSE TRUE TRUE FALSE sum(is_hot) # 2 (TRUE = 1, FALSE = 0) mean(is_hot) # 0.5 class(is_hot) # "logical" |
Character – Text (very forgiving)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 |
city <- "Hyderabad" foods <- c("Biryani", "Haleem", "Irani Chai") class(foods) # "character" # Mix numbers + text → everything becomes character! mixed <- c(2026, "Feb", TRUE) mixed # "2026" "Feb" "TRUE" typeof(mixed) # "character" ← coercion happened! |
Complex – Rare but useful in math/engineering
|
0 1 2 3 4 5 6 7 8 |
z <- 1 + 2i z^2 # -3 + 4i class(z) # "complex" |
Raw – Almost never for beginners (binary data)
|
0 1 2 3 4 5 6 7 8 |
bytes <- charToRaw("A") # 41 (hex for ASCII A) bytes # [41] rawToChar(bytes) # "A" |
5. Coercion Rules – The Silent Danger
R tries to be helpful by automatically converting types when mixing in a vector — but follows a strict hierarchy:
logical < integer < double < complex < character < raw
Lowest to highest (character wins almost always)
|
0 1 2 3 4 5 6 7 8 9 |
c(TRUE, 5L) # TRUE → 1L → integer vector c(3L, 4.2) # 3L → 3 → double c(1, "hello") # everything → character c(TRUE, "yes") # logical → character |
Very common bug:
|
0 1 2 3 4 5 6 7 |
scores <- c(85, 92, "absent", 78) # Oops! "absent" makes whole vector character mean(scores) # Error! Cannot mean characters |
Fix: Clean data before calculations or use lists/data.frames for mixed types.
6. Special Values You Will See Often
- NA → missing value (any type)
- NaN → Not a Number (e.g. 0/0)
- Inf / -Inf → infinity (e.g. 1/0)
- NULL → empty / nothing (not the same as NA!)
|
0 1 2 3 4 5 6 7 8 |
is.na(NA) # TRUE is.nan(NaN) # TRUE is.infinite(Inf) # TRUE |
7. Quick Summary Cheat-Sheet (2026 Style)
- Most numbers → double (numeric)
- Whole counts → integer (use L)
- Yes/No flags → logical
- Text → character
- Mix types in vector → R coerces upward (usually to character)
- Check: typeof() (precise), class(), str()
- Avoid surprises: check types early with str() or glimpse()
Your Mini Practice Right Now
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# Create different types a <- 3.14 # double b <- 42L # integer c <- TRUE # logical d <- "Hyderabad" # character e <- 1 + 3i # complex # Check them data.frame( name = c("a","b","c","d","e"), value = c(a,b,c,d,e), typeof = sapply(list(a,b,c,d,e), typeof), class = sapply(list(a,b,c,d,e), class) ) |
What do you see? All different types!
Want to continue?
- Dive deeper into factors (special character type for categories)?
- How coercion works in data frames?
- Or next topic: vectors in full detail?
Just say the word — I’m right here with the whiteboard! ☕🚀
