R: R Data Types
Last updated: 2026-08-26
In the previous lesson, we learned about assignment and output. All data in R programs—numbers, text, and booleans—have their own distinct "types." In this lesson, we’ll thoroughly explore R’s six basic data types and master "type conversion," an essential skill for data science in R.
R is a dynamically typed language, but that doesn’t mean types aren’t important—90% of R errors are related to type conversions.
1. What You'll Learn
- The 6 basic data types in R (numeric, integer, character, logical, complex, raw)
- The difference between
typeof()andclass() is.*Family of type-checking functionsas.*Family of Type Conversion Functions- The Differences Between the 4 Special Values (NA, NaN, Inf, NULL)
- Common Type Conversion Scenarios in Real-World Applications
2. The "Seemingly Equal" Trap
Before writing any code, let’s look at an example that confuses countless beginners:
# These two numbers look the same, but R considers them "unequal"
1 == 1L
# [1] FALSE
# Verify their types
typeof(1)
# [1] "double" (Double-precision floating-point numbers)
typeof(1L)
# [1] "integer" (Integer)
Isn't that counterintuitive? In R, "1" and "1L" are not the same thing. In this lesson, we'll uncover all the secrets of R data types.
3. The 6 Basic Data Types in R
All data in R belongs to one of the following six basic types:
graph TB
A[R Data Types]
A --> B[numeric<br/>Double-precision floating-point numbers<br/>Default number]
A --> C[integer<br/>Integer<br/>Need to add L Suffix]
A --> D[character<br/>String<br/>Quotation marks must be used]
A --> E[logical<br/>Logical value<br/>TRUE/FALSE]
A --> F[complex<br/>Plural<br/>1+2i]
A --> G[raw<br/>Byte<br/>as.raw 0xff]
style A fill:#fff3cd
style B fill:#cce5ff
style C fill:#cce5ff
style D fill:#d4edda
style E fill:#f8d7da
style F fill:#e1d4ff
style G fill:#ffe1e1
(1) Overview Table of the 6 Types
| Type | Meaning | Example | what typeof() returns |
|---|---|---|---|
| numeric | Double-precision floating-point number (default) | 3.14, -2.5, 1e3 |
"double" |
| integer | Integer (must be suffixed with L) |
1L, 100L, -5L |
"integer" |
| character | String (must be quoted) | "Hello", 'R' |
"character" |
| logical | Logical value (Boolean) | TRUE, FALSE |
"logical" |
| complex | plural | 1+2i, 3-4i |
"complex" |
| raw | Byte type | as.raw(0xff) |
"raw" |
(2) Detailed Explanation of Each Type
# numeric —— Double-precision floating-point numbers(Default number)
x <- 3.14
typeof(x)
# [1] "double"
# integer -- Strict Integers (Add L Suffix)
x <- 10L
typeof(x)
# [1] "integer"
# character —— String
x <- "Hello R"
typeof(x)
# [1] "character"
# logical —— Logical value(Must be all uppercase)
x <- TRUE
typeof(x)
# [1] "logical"
# complex —— Plural
x <- 1 + 2i
typeof(x)
# [1] "complex"
TRUE cannot be written as true or True; doing so will result in a object 'true' not found error.
(3) Integers vs. Floating-Point Numbers: When to Use Which?
| Scenario | Recommended Type | Reason |
|---|---|---|
| General mathematical calculations | numeric | R default; no need to worry about this |
| Large numerical arrays (1 billion+ elements) | integer | Saves half the memory |
| Bitwise operations, IDs, counting | integer | Semantically unambiguous |
Results of floating-point comparisons, sqrt(), etc. |
numeric | Mathematical operations are inherently floating-point |
# Performance Comparison(1 A billion integers vs 1 A billion floating-point numbers)
# integer: ~400 MB
# numeric: ~800 MB
# Not required in normal situations integer,numeric That's enough
integer type at all during the beginner stage. Unless you’re performing large-scale computations (1 billion+ elements), numeric is sufficient.
4. typeof() vs class(): Two Functions That Are Easily Confused
R has two functions that can both check for "type," but they have different meanings.
(1) A Quick Visual Guide to the Differences
graph TB
A["R Object"] --> B["typeof()<br/>Bottom Layer C Type<br/>6 Basic Types"]
A --> C["class()<br/>Business OOP Class<br/>data.frame / Date / factor"]
B --> D["double / integer<br/>character / logical<br/>complex / raw"]
C --> E["Business Concepts<br/>(20+ kinds)"]
style A fill:#fff3cd
style B fill:#cce5ff
style C fill:#d4edda
(2) Actual Comparison
# 1. Ordinary Vectors:The two are consistent
x <- 1:10
typeof(x)
# [1] "integer"
class(x)
# [1] "integer"
# 2. Data Frame: The two are different!
y <- data.frame(a = 1:3, b = c("x", "y", "z"))
typeof(y)
# [1] "list" ← The bottom layer is list
class(y)
# [1] "data.frame" ← In business terms, it's a data frame.
(3) Selection Recommendations
| Scenario | Which one to use |
|---|---|
| Want to know "what this is inside R" | typeof() |
| Want to know "what this means for the business" | class() |
| Beginners | Recommended class() (more intuitive) |
5. Type Checking: The is.* Function Family
R provides the is.* function family for type checking, and all functions return TRUE or FALSE.
(1) Common Check Functions
| Check Function | Purpose | Sample Results |
|---|---|---|
is.numeric(x) |
Is numeric (numeric or integer) | is.numeric(1L) → TRUE |
is.integer(x) |
Is a strict integer (with an "L" suffix) | is.integer(1) → FALSE |
is.character(x) |
Is string | is.character("a") → TRUE |
is.logical(x) |
is a logical value | is.logical(TRUE) → TRUE |
is.na(x) |
Is a missing value NA | is.na(NA) → TRUE |
is.null(x) |
Is NULL (empty value) | is.null(NULL) → TRUE |
(2) Key Pitfall: is.numeric() does not distinguish between integers and doubles
# is.numeric() is the "superset" of is.integer()
is.numeric(1) # [1] TRUE
is.numeric(1L) # [1] TRUE
is.integer(1) # [1] FALSE
is.integer(1L) # [1] TRUE
is.numeric(); to check if it is a strict integer, use is.integer().
6. Type Conversion: The as.* Function Family
The as.* function family in R can coerce one type into another.
(1) Common Conversion Functions
| Conversion Function | Purpose | Failure Behavior |
|---|---|---|
as.numeric(x) |
→ Number | Return NA + Warning |
as.integer(x) |
→ Integer | Truncate Decimal |
as.character(x) |
→ String | Always successful |
as.logical(x) |
→ Logical value | 0 → FALSE, other numbers → TRUE |
(2) The Cost of a Failed Conversion
# String → Numbers(Success)
as.numeric("3.14")
# [1] 3.14
# String → Numbers(Failure)
as.numeric("Hello")
# Warning: NAs introduced by coercion
# [1] NA
NA:
# One failure won't stop me,But there will be a warning
as.numeric(c("1", "2", "abc", "4"))
# Warning: NAs introduced by coercion
# [1] 1 2 NA 4
(3) Real-world scenario: Type mismatch after reading a CSV file
One of the most common pitfalls when reading CSV files is that numeric columns are interpreted as characters:
# Suppose we read one CSV,All columns are character
df <- data.frame(
id = c("1", "2", "3"),
value = c("10.5", "20.3", "30.1")
)
# Before Conversion
str(df)
# 'data.frame': 3 obs. of 2 variables:
# $ id : chr "1" "2" "3"
# $ value: chr "10.5" "20.3" "30.1"
# After conversion
df$id <- as.numeric(df$id)
df$value <- as.numeric(df$value)
str(df)
# $ id : num 1 2 3
# $ value: num 10.5 20.3 30.1
readr::read_csv(), it will automatically infer the type—it’s much smarter than read.csv(), so this problem won’t occur.
- Special Values: NA / NaN / Inf / NULL
R has four special values with completely different meanings—the biggest pitfall for beginners.
(1) The Relationship Among the Four Special Values
graph TB
A["Missing values/Null value"]
A --> B[NA<br/>Missing values Not Available<br/>Missing Data,Not assigned,Conversion Failed]
A --> C[NaN<br/>Non-numeric Not a Number<br/>Not defined mathematically]
A --> D[Inf<br/>Infinity Infinity<br/>1/0,exp 1000]
A --> E[NULL<br/>Empty object<br/>Undefined,Functions with no return value]
B --> F[Includes NaN]
style A fill:#fff3cd
style B fill:#d4edda
style C fill:#f8d7da
style D fill:#cce5ff
style E fill:#e1d4ff
(2) Comparison Table of Four Special Values
| Special Value | typeof | Meaning | Usage Scenario | Check Function |
|---|---|---|---|---|
| NA | logical | Missing value | Missing data, unassigned, conversion failed | is.na() |
| Not a Number | double | non-numeric | 0/0,sqrt(-1) |
is.nan() |
| Inf | double | positive infinity | 1/0, exp(1000) |
is.infinite() |
| NULL | NULL | empty object | undefined, function returns no value | is.null() |
(3) NA: The most common type of "missing data"
# NA Participating in calculations is contagious(NA It won't disappear)
x <- c(1, 2, NA, 4)
sum(x)
# [1] NA <- The entire result turned out NA
# Must use na.rm = TRUE Skip NA
sum(x, na.rm = TRUE)
# [1] 7
# Inspection NA Location
is.na(x)
# [1] FALSE FALSE TRUE FALSE
(4) NaN: "Not defined" in mathematics
# 0 Divide by 0
0 / 0
# [1] NaN
# Taking the square root of a negative number
sqrt(-1)
# Warning: NaNs produced
# [1] NaN
# NaN It is special. NA(NA a subset of)
is.na(NaN)
# [1] TRUE ← NaN Me too NA
(5) Info: "Infinity" in mathematics
# 1 Divide by 0
1 / 0
# [1] Inf
# A negative number divided by 0
-1 / 0
# [1] -Inf
# Inspection Inf
is.infinite(c(1, Inf, -Inf, 2))
# [1] FALSE TRUE TRUE FALSE
(6) NULL: An empty object (or one that does not even exist)
# NULL Doesn't take up memory
x <- NULL
length(x)
# [1] 0
# NA occupies 1 position, NULL disappears entirely
length(c(1, 2, NA, 4)) # [1] 4
length(c(1, 2, NULL, 4)) # [1] 3 ← NULL Swallowed whole
# Default return value for functions with no return value NULL
my_void_func <- function() { }
result <- my_void_func()
is.null(result)
# [1] TRUE
NA and NULL: NA means "the position exists but the value is unknown," while NULL means "the position does not exist at all." The former is often used to indicate missing data, while the latter is often used when a function has no return value.
7. Complete Example: Comprehensive Practice in Type Conversion
Below is an example of a complete workflow that ties together all the concepts covered in this lesson.
▶ Example: Cleaning User-Input Data
# ============================================
# Cleaning User-Input Data
# Features:Convert a character vector to a number,Processing NA
# ============================================
# 1. Simulate from CSV Read"Dirty Data"(All of them character)
raw_data <- c("1", "2.5", "3.14", "abc", "5", "", "7.8")
cat("Raw Data:\n")
print(raw_data)
cat("Primitive Types:", typeof(raw_data), "\n\n")
# 2. Convert to a number ("abc" and "" will become NA)
nums <- as.numeric(raw_data)
cat("After conversion:\n")
print(nums)
# 3. See which ones are NA
na_positions <- is.na(nums)
cat("\nNA Location:")
print(na_positions)
# 4. Statistics NA Quantity
na_count <- sum(na_positions)
cat("\nNA Quantity:", na_count, "\n")
# 5. Keep only non- NA the number
clean_nums <- nums[!na_positions]
cat("\nData After Cleaning:")
print(clean_nums)
# 6. Statistical Indicators
cat("\n=== Statistical Indicators ===\n")
cat("Total Number of Elements:", length(raw_data), "\n")
cat("Valid Data:", length(clean_nums), "\n")
cat("Invalid data:", na_count, "\n")
cat("Total:", sum(clean_nums), "\n")
cat("Average:", round(mean(clean_nums), 2), "\n")
cat("Maximum value:", max(clean_nums), "\n")
cat("Minimum value:", min(clean_nums), "\n")
Expected Output (Excerpt):
Raw Data:
[1] "1" "2.5" "3.14" "abc" "5" "" "7.8"
Primitive Types: character
After conversion:
[1] 1.00 2.50 3.14 NA 5.00 NA 7.80
NA Location:
[1] FALSE FALSE FALSE TRUE FALSE TRUE FALSE
NA Quantity: 2
Data After Cleaning:
[1] 1.00 2.50 3.14 5.00 7.80
=== Statistical Indicators ===
Total Number of Elements: 7
Valid Data: 5
Invalid data: 2
Total: 19.44
Average: 3.89
Maximum value: 7.8
Minimum value: 1
(1) Procedure
| Step | Action | Description |
|---|---|---|
| 1 | Create RStudio Project r-types |
File → New Project |
| 2 | Create a new script data_cleaning.R |
Copy the code above |
| 3 | Select All → Ctrl+Enter |
Send to Console |
| 4 | Observe the output | See the "NA" label and the results after cleaning |
❓ FAQ
typeof() or class()?typeof() (6 basic types) if you want to know about R’s internal underlying types; use class() (data.frame/Date/factor) if you want to know about business types. For beginners, class() is more intuitive.is.numeric(1L) return TRUE, but is.integer(1L) also return TRUE?is.numeric() is the "parent set" of [YIJIAN3PH"—an integer is always a numeric, but the reverse is not true. Recommendation: Use is.numeric() to check if a value is a "number," and use is.integer() to check if it is a "strict integer."as.numeric("3.14") and as.numeric("Hello") return?NA and prints the warning NAs introduced by coercion. When performing batch conversions, be sure to check the number of is.na() entries; otherwise, all subsequent calculations will return NA.NA + 1 equal to?NA. NA is contagious; the result of any arithmetic operation involving NA is NA. To bypass NA, use the na.rm = TRUE parameter (e.g., sum(x, na.rm = TRUE)).NULL and NA?NA to indicate "missing data" (the location exists, but the value is unknown); use NULL to indicate "object does not exist" (not even a location exists). NA is used in the vast majority of data processing scenarios.📖 Summary
- R's 6 basic data types: numeric (default), integer (suffixed with
L), character (string), logical (Boolean), complex (complex numbers), raw (bytes) typeof()Covers low-level C data types (6 basic types);class()covers business-related data types (data.frame, Date, factor) — Beginners will findclass()more intuitiveis.*Function family checks the type (returns TRUE/FALSE),as.*Function family performs a type cast (returns NA and issues a warning if the cast fails)as.numeric()Matches both integers and doubles; strictly distinguishes between them usingas.integer()- The four special values have different meanings: NA (missing value—infectious), NaN (not a number), Inf (infinity), and NULL (empty object—does not exist)
- Standard methods for handling NA:
sum(x, na.rm = TRUE)Skip NA;!is.na(x)Filter out NA
📝 Exercises
-
Basic Exercise: Define 6 variables representing the 6 basic data types (numeric, integer, character, logical, complex, raw). Use
typeof()to check the type of each variable, and save screenshots of the output from the 6typeof()commands. -
Basic Problem: Use
as.numeric()to convert the character vectorc("1", "2.5", "3.14", "abc", "5")into numbers, log the warning messages and the conversion results, and useis.na()to identify which elements have become NA. Take a screenshot of the console output and save it. -
Basic Exercise: In the RStudio console, calculate
0/0,1/0,-1/0, andsqrt(-1), record each result, and useis.na(),is.nan(), andis.infinite()to verify which special value each one belongs to. -
Advanced Problem: Define a vector
scores <- c(85, 92, NA, 78, NA, 95, 88). Requirements: ① Calculate the total score (excluding NA); ② Calculate the average score (excluding NA, rounded to 2 decimal places); ③ Use!is.na()to filter out elements that are not NA; ④ Count the number of NA values. Save a screenshot of the output for each step. -
Challenge: Write an R script to simulate a "type mismatch after reading a CSV file": ① Manually construct a data.frame where all columns are of type
character; ② Useas.numeric()to batch-convert one of the columns to numeric; ③ Usesum(is.na(df$col))to count the number of elements that failed to convert; ④ Usepaste()to construct a warning message and output it. After running the script, take a screenshot and save the entire console output.