R: R 数据类型:6 种基本类型与类型转换
最后更新:2026-08-26
上一课我们学会了赋值和输出,R 程序里的所有数据——数字、文本、真假——都有自己明确的"类型"。这一课我们要把 R 的 6 种基本类型吃透,并把"类型转换"这个数据科学 R 必备技能掌握。
R 是动态类型语言,但不代表类型不重要——90% 的 R 报错都和类型转换有关。
1. 你将学到
- R 的 6 种基本数据类型(numeric、integer、character、logical、complex、raw)
typeof()和class()的区别is.*类型检查函数族as.*类型转换函数族- 4 个特殊值(NA、NaN、Inf、NULL)的区别
- 实战中常见的类型转换场景
2. 一个"看似相等"的陷阱
在写代码前,先看一个让无数初学者困惑的案例:
# 这两个数字看起来一样,但 R 认为它们"不相等"
1 == 1L
# [1] FALSE
# 验证它们的类型
typeof(1)
# [1] "double" (双精度浮点数)
typeof(1L)
# [1] "integer" (整数)
是不是很反直觉?R 里"1"和"1L"不是同一个东西。这节课就要解开 R 数据类型的所有秘密。
3. R 的 6 种基本数据类型
R 的一切数据都属于以下 6 种基本类型之一:
graph TB
A[R 数据类型]
A --> B[numeric<br/>双精度浮点数<br/>默认数字]
A --> C[integer<br/>整数<br/>需加 L 后缀]
A --> D[character<br/>字符串<br/>必须用引号]
A --> E[logical<br/>逻辑值<br/>TRUE/FALSE]
A --> F[complex<br/>复数<br/>1+2i]
A --> G[raw<br/>字节<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) 6 种类型总览表
| 类型 | 含义 | 示例 | typeof() 返回 |
|---|---|---|---|
| numeric | 双精度浮点数(默认数字) | 3.14, -2.5, 1e3 |
"double" |
| integer | 整数(需加 L 后缀) |
1L, 100L, -5L |
"integer" |
| character | 字符串(必须用引号) | "Hello", 'R' |
"character" |
| logical | 逻辑值(布尔型) | TRUE, FALSE |
"logical" |
| complex | 复数 | 1+2i, 3-4i |
"complex" |
| raw | 字节类型 | as.raw(0xff) |
"raw" |
(2) 各类型详解
# numeric —— 双精度浮点数(默认数字)
x <- 3.14
typeof(x)
# [1] "double"
# integer —— 严格整数(加 L 后缀)
x <- 10L
typeof(x)
# [1] "integer"
# character —— 字符串
x <- "Hello R"
typeof(x)
# [1] "character"
# logical —— 逻辑值(必须全大写)
x <- TRUE
typeof(x)
# [1] "logical"
# complex —— 复数
x <- 1 + 2i
typeof(x)
# [1] "complex"
TRUE 不能写成 true 或 True,会报 object 'true' not found 错误。
(3) 整数 vs 浮点:什么时候用哪个?
| 场景 | 推荐类型 | 原因 |
|---|---|---|
| 普通数学计算 | numeric | R 默认,无需关心 |
| 大规模数值数组(10 亿+ 元素) | integer | 节省一半内存 |
| 位运算、ID、计数 | integer | 语义明确 |
浮点比较、sqrt() 等结果 |
numeric | 数学运算天然是浮点 |
# 性能对比(1 亿个整数 vs 1 亿个浮点)
# integer: ~400 MB
# numeric: ~800 MB
# 普通场景不需要 integer,numeric 就够用
integer 类型。除非做大规模计算(10 亿+ 元素),用 numeric 即可。
4. typeof() vs class():两个容易混淆的函数
R 有两个函数都能查"类型",但含义不同。
(1) 一图看懂区别
graph TB
A["R 对象"] --> B["typeof()<br/>底层 C 类型<br/>6 种基本类型"]
A --> C["class()<br/>业务 OOP 类<br/>data.frame / Date / factor"]
B --> D["double / integer<br/>character / logical<br/>complex / raw"]
C --> E["业务含义类<br/>(20+ 种)"]
style A fill:#fff3cd
style B fill:#cce5ff
style C fill:#d4edda
(2) 实际对比
# 1. 普通向量:两者一致
x <- 1:10
typeof(x)
# [1] "integer"
class(x)
# [1] "integer"
# 2. 数据框:两者不同!
y <- data.frame(a = 1:3, b = c("x", "y", "z"))
typeof(y)
# [1] "list" ← 底层是 list
class(y)
# [1] "data.frame" ← 业务上是数据框
(3) 选用建议
| 场景 | 用哪个 |
|---|---|
| 想知道"这在 R 内部是什么" | typeof() |
| 想知道"这在业务上是什么" | class() |
| 新手 | 推荐 class()(更直观) |
5. 类型检查:is.* 函数族
R 提供 is.* 函数族检查类型,全部返回 TRUE/FALSE。
(1) 常用检查函数
| 检查函数 | 用途 | 示例结果 |
|---|---|---|
is.numeric(x) |
是数字(numeric 或 integer) | is.numeric(1L) → TRUE |
is.integer(x) |
是严格整数(带 L 后缀) | is.integer(1) → FALSE |
is.character(x) |
是字符串 | is.character("a") → TRUE |
is.logical(x) |
是逻辑值 | is.logical(TRUE) → TRUE |
is.na(x) |
是缺失值 NA | is.na(NA) → TRUE |
is.null(x) |
是 NULL(空值) | is.null(NULL) → TRUE |
(2) 关键陷阱:is.numeric() 不区分 integer 和 double
# is.numeric() 是 is.integer() 的"父集"
is.numeric(1) # [1] TRUE
is.numeric(1L) # [1] TRUE
is.integer(1) # [1] FALSE
is.integer(1L) # [1] TRUE
is.numeric(),想知道"是不是严格整数"用 is.integer()。
6. 类型转换:as.* 函数族
R 的 as.* 函数族可以把一种类型强制转换为另一种。
(1) 常用转换函数
| 转换函数 | 用途 | 失败行为 |
|---|---|---|
as.numeric(x) |
→ 数字 | 返回 NA + 警告 |
as.integer(x) |
→ 整数 | 截断小数 |
as.character(x) |
→ 字符串 | 总是成功 |
as.logical(x) |
→ 逻辑值 | 0 → FALSE,其他数字 → TRUE |
(2) 转换失败的代价
# 字符串 → 数字(成功)
as.numeric("3.14")
# [1] 3.14
# 字符串 → 数字(失败)
as.numeric("Hello")
# Warning: NAs introduced by coercion
# [1] NA
NA 个数:
# 一个失败不会中断,但会有警告
as.numeric(c("1", "2", "abc", "4"))
# Warning: NAs introduced by coercion
# [1] 1 2 NA 4
(3) 实战场景:读 CSV 后类型不匹配
读 CSV 时数字列被读成 character 是最常见的坑:
# 假设读了一个 CSV,所有列都是 character
df <- data.frame(
id = c("1", "2", "3"),
value = c("10.5", "20.3", "30.1")
)
# 转换前
str(df)
# 'data.frame': 3 obs. of 2 variables:
# $ id : chr "1" "2" "3"
# $ value: chr "10.5" "20.3" "30.1"
# 转换后
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() 时,它会自动推断类型,比 read.csv() 智能得多,不会出这个问题。
7. 特殊值:NA / NaN / Inf / NULL
R 有 4 个特殊值,含义完全不同——初学者最大的坑。
(1) 四个特殊值的关系
graph TB
A["缺失值/空值"]
A --> B[NA<br/>缺失值 Not Available<br/>数据缺失、未赋值、转换失败]
A --> C[NaN<br/>非数字 Not a Number<br/>数学上无定义]
A --> D[Inf<br/>无穷大 Infinity<br/>1/0、exp 1000]
A --> E[NULL<br/>空对象<br/>未定义、函数无返回值]
B --> F[包含 NaN]
style A fill:#fff3cd
style B fill:#d4edda
style C fill:#f8d7da
style D fill:#cce5ff
style E fill:#e1d4ff
(2) 四个特殊值对比表
| 特殊值 | typeof | 含义 | 产生场景 | 检查函数 |
|---|---|---|---|---|
| NA | logical | 缺失值 | 数据缺失、未赋值、转换失败 | is.na() |
| NaN | double | 非数字 | 0/0、sqrt(-1) |
is.nan() |
| Inf | double | 正无穷 | 1/0、exp(1000) |
is.infinite() |
| NULL | NULL | 空对象 | 未定义、函数无返回值 | is.null() |
(3) NA:最常见的"数据缺失"
# NA 参与运算会传染(NA 不会消失)
x <- c(1, 2, NA, 4)
sum(x)
# [1] NA ← 整个结果都成 NA 了
# 必须用 na.rm = TRUE 跳过 NA
sum(x, na.rm = TRUE)
# [1] 7
# 检查 NA 位置
is.na(x)
# [1] FALSE FALSE TRUE FALSE
(4) NaN:数学上"无定义"
# 0 除以 0
0 / 0
# [1] NaN
# 负数开方
sqrt(-1)
# Warning: NaNs produced
# [1] NaN
# NaN 是特殊的 NA(NA 的子集)
is.na(NaN)
# [1] TRUE ← NaN 也是 NA
(5) Inf:数学上"无穷大"
# 1 除以 0
1 / 0
# [1] Inf
# 负数除以 0
-1 / 0
# [1] -Inf
# 检查 Inf
is.infinite(c(1, Inf, -Inf, 2))
# [1] FALSE TRUE TRUE FALSE
(6) NULL:空对象(甚至不存在)
# NULL 不占内存
x <- NULL
length(x)
# [1] 0
# NA 占 1 个位置,NULL 直接被吞掉
length(c(1, 2, NA, 4)) # [1] 4
length(c(1, 2, NULL, 4)) # [1] 3 ← NULL 直接被吞掉
# 函数无返回值时默认返回 NULL
my_void_func <- function() { }
result <- my_void_func()
is.null(result)
# [1] TRUE
NA 和 NULL 的本质区别:NA 是"位置存在但值未知",NULL 是"这个位置压根不存在"。前者常用于数据缺失,后者常用于函数无返回值。
8. 完整示例:类型转换综合演练
下面是一个完整工作流示例,把本课所有知识点串起来。
▶ 示例:用户输入数据清洗
# ============================================
# 用户输入数据清洗
# 功能:把字符向量转换为数字,处理 NA
# ============================================
# 1. 模拟从 CSV 读到的"脏数据"(全是 character)
raw_data <- c("1", "2.5", "3.14", "abc", "5", "", "7.8")
cat("原始数据:\n")
print(raw_data)
cat("原始类型:", typeof(raw_data), "\n\n")
# 2. 转成数字("abc" 和 "" 会变 NA)
nums <- as.numeric(raw_data)
cat("转换后:\n")
print(nums)
# 3. 查看哪些是 NA
na_positions <- is.na(nums)
cat("\nNA 位置:")
print(na_positions)
# 4. 统计 NA 数量
na_count <- sum(na_positions)
cat("\nNA 数量:", na_count, "\n")
# 5. 只保留非 NA 的数字
clean_nums <- nums[!na_positions]
cat("\n清洗后数据:")
print(clean_nums)
# 6. 统计指标
cat("\n=== 统计指标 ===\n")
cat("元素总数:", length(raw_data), "\n")
cat("有效数据:", length(clean_nums), "\n")
cat("无效数据:", na_count, "\n")
cat("总和:", sum(clean_nums), "\n")
cat("平均:", round(mean(clean_nums), 2), "\n")
cat("最大值:", max(clean_nums), "\n")
cat("最小值:", min(clean_nums), "\n")
预期输出(节选):
原始数据:
[1] "1" "2.5" "3.14" "abc" "5" "" "7.8"
原始类型: character
转换后:
[1] 1.00 2.50 3.14 NA 5.00 NA 7.80
NA 位置:
[1] FALSE FALSE FALSE TRUE FALSE TRUE FALSE
NA 数量: 2
清洗后数据:
[1] 1.00 2.50 3.14 5.00 7.80
=== 统计指标 ===
元素总数: 7
有效数据: 5
无效数据: 2
总和: 19.44
平均: 3.89
最大值: 7.8
最小值: 1
(1) 操作步骤
| 步骤 | 操作 | 说明 |
|---|---|---|
| 1 | 新建 RStudio Project r-types |
File → New Project |
| 2 | 新建脚本 data_cleaning.R |
复制上面代码 |
| 3 | 选中全部 → Ctrl+Enter |
发送到控制台 |
| 4 | 观察输出 | 看到 NA 标记和清洗后结果 |
❓ 常见问题
typeof() 和 class() 该用哪个?typeof()(6 种基本类型);想知道业务类型用 class()(data.frame/Date/factor)。新手阶段用 class() 更直观。is.numeric(1L) 返回 TRUE,但 is.integer(1L) 也返回 TRUE?is.numeric() 是 is.integer() 的"父集"——integer 一定是 numeric,但反过来不成立。建议:想知道"是不是数字"用 is.numeric(),想知道"是不是严格整数"用 is.integer()。NULL 和 NA 怎么选?NA 表示"数据缺失"(位置存在,值未知);用 NULL 表示"对象不存在"(连位置都没有)。绝大多数数据处理场景用 NA。📖 小节
- R 6 种基本类型:numeric(默认数字)、integer(
L后缀)、character(字符串)、logical(布尔)、complex(复数)、raw(字节) typeof()看底层 C 类型(6 种基本类型),class()看业务类(data.frame/Date/factor)—— 新手用class()更直观is.*函数族检查类型(返回 TRUE/FALSE),as.*函数族强制类型转换(失败返回 NA + 警告)as.numeric()同时匹配 integer 和 double;严格区分用as.integer()- 4 个特殊值含义不同:NA 缺失值(传染性)、NaN 非数字、Inf 无穷大、NULL 空对象(不存在)
- 处理 NA 的标准模式:
sum(x, na.rm = TRUE)跳过 NA;!is.na(x)过滤 NA
📝 作业
-
基础题:定义 6 个变量分别代表 6 种基本类型(numeric、integer、character、logical、complex、raw),用
typeof()查看每个变量的类型,把 6 个typeof()的输出截图保存。 -
基础题:用
as.numeric()把字符向量c("1", "2.5", "3.14", "abc", "5")转换成数字,记录警告信息和转换结果,用is.na()找出哪些元素变成了 NA。截图保存控制台输出。 -
基础题:在 RStudio 控制台计算
0/0、1/0、-1/0、sqrt(-1),记录每个结果,用is.na()、is.nan()、is.infinite()验证它们分别属于哪种特殊值。 -
进阶题:定义一个向量
scores <- c(85, 92, NA, 78, NA, 95, 88),要求:① 计算总分(跳过 NA);② 计算平均分(跳过 NA,保留 2 位小数);③ 用!is.na()过滤出非 NA 元素;④ 统计 NA 的数量。把每一步的输出截图保存。 -
挑战题:写一个 R 脚本模拟"读取 CSV 后类型不匹配":① 手动构造一个 data.frame,所有列都是 character;② 用
as.numeric()批量转换其中一列为数字;③ 用sum(is.na(df$col))统计转换失败的元素数量;④ 用paste()拼成一段警告信息输出。运行后截图保存控制台全部输出。