R: R 数据类型:6 种基本类型与类型转换

最后更新:2026-08-26

上一课我们学会了赋值和输出,R 程序里的所有数据——数字、文本、真假——都有自己明确的"类型"。这一课我们要把 R 的 6 种基本类型吃透,并把"类型转换"这个数据科学 R 必备技能掌握。

R 是动态类型语言,但不代表类型不重要——90% 的 R 报错都和类型转换有关。

1. 你将学到



2. 一个"看似相等"的陷阱

在写代码前,先看一个让无数初学者困惑的案例:

R
# 这两个数字看起来一样,但 R 认为它们"不相等"
1 == 1L
# [1] FALSE

# 验证它们的类型
typeof(1)
# [1] "double"  (双精度浮点数)

typeof(1L)
# [1] "integer" (整数)

是不是很反直觉?R 里"1"和"1L"不是同一个东西。这节课就要解开 R 数据类型的所有秘密。



3. R 的 6 种基本数据类型

R 的一切数据都属于以下 6 种基本类型之一:

100%
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"
💡 提示:实际开发中最常用的就 4 种:numeric、character、logical、integer。complex 和 raw 极少用。

(2) 各类型详解

R
# 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 不能写成 trueTrue,会报 object 'true' not found 错误。

(3) 整数 vs 浮点:什么时候用哪个?

场景 推荐类型 原因
普通数学计算 numeric R 默认,无需关心
大规模数值数组(10 亿+ 元素) integer 节省一半内存
位运算、ID、计数 integer 语义明确
浮点比较、sqrt() 等结果 numeric 数学运算天然是浮点
R
# 性能对比(1 亿个整数 vs 1 亿个浮点)
# integer: ~400 MB
# numeric: ~800 MB

# 普通场景不需要 integer,numeric 就够用
💡 提示新手阶段完全不需要 integer 类型。除非做大规模计算(10 亿+ 元素),用 numeric 即可。



4. typeof() vs class():两个容易混淆的函数

R 有两个函数都能查"类型",但含义不同

(1) 一图看懂区别

100%
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) 实际对比

R
# 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

R
# 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) 转换失败的代价

R
# 字符串 → 数字(成功)
as.numeric("3.14")
# [1] 3.14

# 字符串 → 数字(失败)
as.numeric("Hello")
# Warning: NAs introduced by coercion
# [1] NA
⚠️ 注意:批量转换时一定检查 NA 个数

R
# 一个失败不会中断,但会有警告
as.numeric(c("1", "2", "abc", "4"))
# Warning: NAs introduced by coercion
# [1]  1  2 NA  4

(3) 实战场景:读 CSV 后类型不匹配

读 CSV 时数字列被读成 character 是最常见的坑:

R
# 假设读了一个 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
💡 提示:第 11 课我们学 readr::read_csv() 时,它会自动推断类型,比 read.csv() 智能得多,不会出这个问题。



7. 特殊值:NA / NaN / Inf / NULL

R 有 4 个特殊值,含义完全不同——初学者最大的坑

(1) 四个特殊值的关系

100%
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/0sqrt(-1) is.nan()
Inf double 正无穷 1/0exp(1000) is.infinite()
NULL NULL 空对象 未定义、函数无返回值 is.null()

(3) NA:最常见的"数据缺失"

R
# 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:数学上"无定义"

R
# 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:数学上"无穷大"

R
# 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:空对象(甚至不存在)

R
# 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
⚠️ 注意NANULL 的本质区别:NA 是"位置存在但值未知"NULL 是"这个位置压根不存在"。前者常用于数据缺失,后者常用于函数无返回值。



8. 完整示例:类型转换综合演练

下面是一个完整工作流示例,把本课所有知识点串起来。

▶ 示例:用户输入数据清洗

R
# ============================================
# 用户输入数据清洗
# 功能:把字符向量转换为数字,处理 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")
▶ 试一试

预期输出(节选):

TEXT 📖 仅展示
原始数据:
[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 标记和清洗后结果

❓ 常见问题

Q typeof()class() 该用哪个?
A 想知道 R 内部底层类型用 typeof()(6 种基本类型);想知道业务类型用 class()(data.frame/Date/factor)。新手阶段用 class() 更直观。
Q 为什么 is.numeric(1L) 返回 TRUE,但 is.integer(1L) 也返回 TRUE?
A 因为 is.numeric()is.integer() 的"父集"——integer 一定是 numeric,但反过来不成立。建议:想知道"是不是数字"用 is.numeric(),想知道"是不是严格整数"用 is.integer()
Q NULLNA 怎么选?
ANA 表示"数据缺失"(位置存在,值未知);用 NULL 表示"对象不存在"(连位置都没有)。绝大多数数据处理场景用 NA

📖 小节


📝 作业

  1. 基础题:定义 6 个变量分别代表 6 种基本类型(numeric、integer、character、logical、complex、raw),用 typeof() 查看每个变量的类型,把 6 个 typeof() 的输出截图保存。

  2. 基础题:用 as.numeric() 把字符向量 c("1", "2.5", "3.14", "abc", "5") 转换成数字,记录警告信息和转换结果,is.na() 找出哪些元素变成了 NA。截图保存控制台输出。

  3. 基础题:在 RStudio 控制台计算 0/01/0-1/0sqrt(-1),记录每个结果,is.na()is.nan()is.infinite() 验证它们分别属于哪种特殊值

  4. 进阶题:定义一个向量 scores <- c(85, 92, NA, 78, NA, 95, 88),要求:① 计算总分(跳过 NA);② 计算平均分(跳过 NA,保留 2 位小数);③ 用 !is.na() 过滤出非 NA 元素;④ 统计 NA 的数量。把每一步的输出截图保存。

  5. 挑战题:写一个 R 脚本模拟"读取 CSV 后类型不匹配":① 手动构造一个 data.frame,所有列都是 character;② 用 as.numeric() 批量转换其中一列为数字;③ 用 sum(is.na(df$col)) 统计转换失败的元素数量;④ 用 paste() 拼成一段警告信息输出。运行后截图保存控制台全部输出。

Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏