跳至主要内容

适用于各个水平的40道 R 编程面试题与答案

掌握40道基础 R 编程面试题及其答案,覆盖所有资历层级:入门、进阶与高级问题。
Elena Kosourova
Elena Kosourova

创建您的免费账户

实践并学习路径你的进步。

使用 Google 继续继续即表示您接受我们的 使用条款,我们的 隐私政策 ,并且您的数据存储在美国。

为了提高您在 R 面试中成功的机会,无论您是在找工作还是负责招聘,提前了解可能会被问到的问题(或可以问候选人的问题)总是有益的。

本文汇总了40道基础的 R 编程面试题及其参考答案,涵盖从入门到高级的各个资历水平,并包含若干通用面试问题。为便于阅读,所有技术问题分为三类:入门、进阶和高级问题。

作为准备 R 编程面试的补充资源,您可以参考以下博客和课程:

R 编程通用面试问题

在 R 面试的开场阶段,面试官可能会就候选人整体的 R 使用经验提出一些非技术性问题,例如:

  • 您使用 R 多久了?
  • 您在 R 中通常完成哪些类型的任务?
  • 您如何评估自己在 R 方面的熟练程度?

如果您是求职者,应当提前思考这些及类似问题并准备答案。即便您尚无实际的 R 工作经验也不必担心:描述您在 R 编程方面的实习,或您在校期间完成的个人或团队R 项目,同样有效。

此外,如果您应聘的是入门级岗位,面试官并不一定期望您具备丰富(甚至任何)的 R 工作经验。请记住,既然您已收到面试邀请,说明公司已对您的简历表示认可。

入门级 R 编程面试问题

让我们从一些基础的技术性 R 面试题开始,这些问题常见于潜在雇主的考察中。它们要求您掌握基础知识,并具有一定的 R 实操经验。

1. 什么是 R?它有哪些主要特性?

R 是一种广泛用于解决数据科学问题的编程语言与环境,特别为统计计算与数据可视化而设计。其主要特性包括:

  • 开源
  • 解释型(即同时支持函数式与面向对象编程)
  • 凭借庞大的数据科学包生态而具有高度可扩展性
  • 函数化且灵活(用户可自定义函数,并可调节现有函数的多种参数)
  • 兼容多种操作系统
  • 易于与其他编程语言和框架集成
  • 支持强大的统计计算
  • 提供多样的数据可视化工具,可创建出版级图表
  • 配备命令行界面
  • 拥有强大的在线社区支持

2. 使用 R 有哪些劣势?

  • 语法不直观,学习曲线较陡,尤其对编程初学者
  • 相对较慢
  • 内存使用效率不高
  • 部分包的文档不一致且常较难阅读
  • 一些包质量不高或维护不佳
  • 由于开源属性,可能存在安全性隐患

3. 列举并定义 R 中的一些基本数据类型。

R 中有若干数据类型,包括: 

  1. Numeric(数值)—十进制数。
  2. Integer(整数)—整型数。
  3. Character(字符)—字母、数字或符号,或它们的任意组合,用双引号或单引号括起。
  4. Factor(因子)—来自预定义可能值集合的类别,通常具有内在顺序。
  5. Logical(逻辑)—布尔值 TRUE 和 FALSE,在底层分别用 1 和 0 表示。

4. 列举并定义 R 中的一些基本数据结构。

  1. Vector(向量)—一维数据结构,用于存储同一数据类型的值。
  2. List(列表)—多维数据结构,可存储任意数据类型和值以及其他数据结构。
  3. Matrix(矩阵)—二维数据结构,用于存储同一数据类型的值。
  4. Data frame(数据框)—二维数据结构,可存储任意数据类型的值,但每列必须是相同的数据类型。

5. 如何在 R 中导入数据?

基础 R 提供了导入数据的核心函数:

  • read.table()—基础 R 中最通用的导入函数,读取以任意分隔符(包括自定义如 |)分隔的表格数据。

  • read.csv()—读取以逗号分隔(CSV)的文件,小数点分隔符为 .。

  • read.csv2()—读取以分号分隔的文件,小数点分隔符为 ,。

  • read.delim()—读取以制表符分隔(TSV)的文件,小数点分隔符为 .。

  • read.delim2()—读取以制表符分隔(TSV)的文件,小数点分隔符为 ,。

实际中,这些函数都可用于导入具有任意字段与小数点分隔符的表格数据:按约定与默认设置用于指定格式而已。例如,第一个函数的语法为:read.table(file, header = FALSE, sep = "", dec = ".")。其余函数拥有相同参数,但默认值不同,且总可显式覆盖。

tidyverse 的 readr 和 readxl 包提供了用于特定文件格式的其他函数。每个函数都可通过设置可选参数进行进一步微调。

readr

  • read_tsv()—读取 TSV 文件。

  • read_fwf()—读取定宽文件。

  • read_log()—读取 Web 日志文件。

  • read_table()、read_csv()、read_csv2() 和 read_delim()—与基础 R 的同名函数等效。

readxl

  • read_excel()—读取 Excel 文件。

  • read_csv()—等效于基础 R 的同名函数。

要更深入了解 R 中的数据加载,请查看教程 如何将数据导入 R。

6. R 中的包是什么?如何安装和加载包?

R 包是函数、代码、数据和文档的集合,是对 R 编程语言的扩展,用于解决特定类型的任务。R 自带若干预装包,其他包可由用户从仓库安装。最受欢迎的集中式仓库是 CRAN(Comprehensive R Archive Network,综合 R 存档网络)。

要直接从 CRAN 安装 R 包,需要将包名用引号括起并传给 install.packages() 函数,如:install.packages("package_name")。要一次安装多个包,需使用包含包名的字符向量,如:install.packages(c("package_name_1", "package_name_2")。若要手动安装 R 包,需先将包下载为本地 zip 文件,然后运行 install.packages() 函数:

install.packages("path_to_the_locally_stored_zipped_package_file", repos=NULL, type="source")

要在当前 R 工作环境中加载已安装的包,可使用 library() 或 require()。两者都接收不带引号的包名并加载包,例如 library(caret)。不同之处在于找不到包时的行为:library() 会抛出错误并停止程序执行,而 require() 会给出警告并继续执行。

7. 如何在 R 中创建数据框?

1. 由一个或多个向量(长度相同)—使用 data.frame() 函数:

df <- data.frame(vector_1, vector_2)

2. 由矩阵—使用 data.frame() 函数:

df <- data.frame(my_matrix)

3. 由向量列表(长度相同)—使用 data.frame() 函数:

df <- data.frame(list_of_vectors)

4. 由其他数据框:

  • 将数据框横向合并(仅当数据框行数相同,且记录相同且顺序一致)—使用 cbind() 函数:

df <- cbind(df1, df2)
  • 将数据框纵向合并(仅当它们具有数量相等、名称一致、数据类型相同且顺序一致的列)—使用 rbind() 函数:

df <- rbind(df1, df2)

8. 如何在 R 的数据框中添加新列?

  1. 使用 $ 符号:
df <- data.frame(col_1=10:13, col_2=c("a", "b", "c", "d"))
print(df)
​
df$col_3 <- c(5, 1, 18, 16)
print(df)

输出:

  col_1 col_2
1    10     a
2    11     b
3    12     c
4    13     d
  col_1 col_2 col_3
1    10     a     5
2    11     b     1
3    12     c    18
4    13     d    16
  1. 使用方括号:
df <- data.frame(col_1=10:13, col_2=c("a", "b", "c", "d"))
print(df)
​
df["col_3"] <- c(5, 1, 18, 16)
print(df)

输出:

  col_1 col_2
1    10     a
2    11     b
3    12     c
4    13     d
  col_1 col_2 col_3
1    10     a     5
2    11     b     1
3    12     c    18
4    13     d    16
  1. 使用 cbind() 函数:

df <- data.frame(col_1=10:13, col_2=c("a", "b", "c", "d"))
print(df)
​
df <- cbind(df, col_3=c(5, 1, 18, 16))
print(df)

输出:

 col_1 col_2
1    10     a
2    11     b
3    12     c
4    13     d
  col_1 col_2 col_3
1    10     a     5
2    11     b     1
3    12     c    18
4    13     d    16

在上述三种方法中,既可以赋单个值,也可以赋向量,或基于该数据框或其他数据框的现有列计算新列。

9. 如何在 R 的数据框中删除列?

1. 使用 tidyverse 集合中 dplyr 包的 select() 函数。每个要删除的列名前加负号:

df <- select(df, -col_1, -col_3)

如果待删除的列太多,更合理的方式是只保留其余列而不是删除目标列。此时语法类似,但保留的列名不加负号:

df <- select(df, col_2, col_4)

2. 使用基础 R 的内置 subset() 函数。若只需删除一列,将带负号的列名赋给函数的 select 参数。要删除多列,则将带负号的列名构成向量赋给该参数:

df <- subset(df, select=-col_1)
df <- subset(df, select=-c(col_1, col_3))

如果待删除的列太多,更合理的方式是只保留其余列。此时语法类似,但不加负号:

df <- subset(df, select=col_2)
df <- subset(df, select=c(col_2, col_4))

10. R 中的因子(factor)是什么?

因子是 R 中的一种特定数据类型,接受来自预定义可能值集合的类别(也称水平)。这些类别看起来像字符,但底层以整数存储。此类类别通常具有内在顺序。例如,数据框中用于表达观点的李克特量表选项("strongly agree"、"agree"、"somewhat agree"、"neither agree nor disagree"、"somewhat disagree"、"disagree"、"strongly disagree")应设为因子类型,以捕捉这种内在顺序,并在各类图表中得到恰当反映。

11. 什么是 RStudio?

RStudio 是一个开源 IDE(集成开发环境),自 3.0.1 版本起被广泛用作 R 的图形化前端。它拥有诸多实用功能,因此备受 R 用户青睐:

  • 用户友好
  • 灵活
  • 多功能
  • 支持创建可复用脚本
  • 记录操作历史
  • 代码自动补全
  • 为任意对象提供详细完整的帮助
  • 便捷访问所有导入数据与构建对象
  • 便于在终端与控制台间切换
  • 支持绘图预览
  • 支持高效的项目创建与共享
  • 可与其他编程语言(Python、SQL 等)配合使用

欲了解 RStudio 是什么、如何安装并开始使用,请参阅RStudio 教程。

12. 什么是 R Markdown?

R Markdown 是一个免费开源的 R 包,为构建数据科学项目提供创作框架。使用它,我们可以编写一个同时包含叙述、代码和图形的 .rmd 文件,并将其渲染为所选输出格式。其主要特点包括:

  • 结果文档可分享、完全可复现且具备出版质量。
  • 支持广泛的静态和动态输出及格式,如 HTML、PDF、Microsoft Word、交互式文档、仪表板、报告、文章、书籍、演示、应用、网站、可复用模板等。
  • 便于版本控制。
  • 支持多种编程语言,包括 R、Python 和 SQL。

13. 如何在 R 中创建自定义函数?

在 R 中创建自定义函数,需要使用关键字 function,语法如下:

function_name <- function(parameters){
    function body 
}
  1. 函数名—定义后用于调用该函数的对象名。
  2. 函数参数—放在圆括号中、以逗号分隔的变量,每次调用函数时会被设置为实际实参。
  3. 函数体—位于花括号中的代码块,按预定义顺序对输入参数执行操作。通常包含 return()(返回函数输出)或 print()(打印输出)。

一个简单的 R 自定义函数示例:

my_function <- function(x, y){
    return(x + y)
}

14. 列举一些 R 中常用的数据可视化包。

  • ggplot2—最流行的 R 可视化包,可创建多种图表。
  • Lattice—以平铺面板(trellis)方式展示多元数据。
  • Plotly—创建交互式、出版级图表。
  • highcharter—便于动态绘图,提供众多灵活特性、插件与主题;可用一个函数绘制不同 R 对象。
  • Leaflet—创建交互式地图。
  • ggvis—创建可交互且高度可定制的图表,可借助 Shiny 基础设施在任意浏览器中访问。
  • patchwork—将多个(通常类型各异的)图表组合于同一画面。

进阶 R 编程面试问题

对于更有经验的从业者,面试官很可能会提出需要更深入 R 知识的问题。以下是一些需要准备的内容:

15. 如何在 R 中给变量赋值?

  1. 使用赋值运算符 <-,如 my_var <- 1—R 中最常见的赋值方式。

  2. 使用等号运算符 =,如 my_var = 1—多用于函数定义内为参数赋值。

  3. 使用右向赋值运算符 ->,如 my_var -> 1—可用于管道中。

  4. 使用全局赋值运算符,左向(<<-)或右向(->>),如 my_var <<- 1—用于在函数定义内创建全局变量。

16. R 中变量命名有哪些要求?

  • 变量名可由字母、数字、点与下划线组合而成。不能包含其他符号,包括空格。

  • 变量名必须以字母或点开头。

  • 若以点开头,点后不能紧跟数字。

  • R 中的保留字(如 TRUE、for、NULL 等)不能作为变量名。

  • 变量名区分大小写。

在课程 高效 R 代码编写 中,您将学习更多 R 代码编写的最佳实践。

17. R 中有哪些类型的循环?各自语法是什么?

1. for 循环—对序列进行迭代,次数等于其长度(除非使用 break 和/或 next 语句),对序列的每个元素执行相同操作。这是最常见的循环类型。语法如下:

for (variable in sequence) {
    operations
}

2. while 循环—在满足预先定义的逻辑条件(可为多个)之前,反复执行相同操作(除非使用 break 和/或 next 语句)。与 for 不同,while 在执行前并不知晓迭代次数。运行 while 前需先赋初值,并在循环体内每次迭代更新。语法如下:

variable assignment

while (logical condition) {
    operations
    variable update
}

3. repeat 循环—重复执行相同操作,直至满足预定义的中断条件(可为多个)。为引入中断条件,repeat 循环需包含 if 语句代码块,且其中必须含有 break。与 while 相似,repeat 的迭代次数也无法事先知晓。语法如下:

repeat { 
    operations 
    if(break condition) {
        break
    }
}

您可在教程 R 中的循环 中了解更多。

18. 如何在 R 中聚合数据?

在 R 中使用 aggregate() 函数聚合数据。该函数的关键参数依次为:

  • x—要聚合的数据框。

  • by—按哪些因子分组的列表。

  • FUN—对每组计算汇总统计的聚合函数(如 mean、max、min、count、sum)。

19. 如何在 R 中合并数据?

1. 使用 cbind() 函数—仅当数据框行数一致且记录相同且顺序一致:

df <- cbind(df1, df2)

2. 使用 rbind() 函数将数据框纵向合并—仅当它们具有数量相等、名称一致、数据类型相同且顺序一致的列:

df <- rbind(df1, df2)

3. 使用 merge() 函数按共有列(通常是 ID 列)合并数据框:

  • 内连接:
df <- merge(df1, df2, by="ID")
  • 左连接:
df <- merge(df1, df2, by="ID", all.x=TRUE)
  • 右连接:
df <- merge(df1, df2, by="ID", all.y=TRUE)
  • 外连接:
df <- merge(df1, df2, by="ID", all=TRUE)

4. 使用 dplyr 包的 join() 函数按共有列(通常为 ID)合并数据框:

df <- join(df1, df2, by="ID", type="type_of_join")

type 参数可取:inner、left、right 或 full。

20. 如何在 R 中拼接字符串?

可使用 paste() 或 cat() 函数拼接两个或更多字符串。前者更常用。两者均可接收任意数量的待拼接字符串,并可接收可选参数 sep(以及其他可选参数)—用于指定结果字符串中各部分的分隔符(默认空格)。

21. 如何在 R 中转置二维数据?

我们可以对数据框或矩阵进行转置,使列变为行、行变为列。可使用基础 R 的 t() 函数,例如:

df <- data.frame(col_1=c(10, 20, 30), col_2=c(11, 22, 33))
print(df)
​
transposed_df <- t(df)
print(transposed_df)

输出:

 col_1 col_2
1    10    11
2    20    22
3    30    33
      [,1] [,2] [,3]
col_1   10   20   30
col_2   11   22   33

22. 如何在 R 中将多个操作串联起来?

可使用 tidyverse 提供的管道运算符(%>%)将多个操作串联。使用该运算符可以构建函数流水线:第一个函数的输出作为第二个函数的输入,依此类推,直至流水线结束。这样无需创建额外变量,并显著提升代码可读性。

在数据框上使用管道运算符的示例:

df <- data.frame(a=1:4, b=11:14, c=21:24)
print(df)
​
df_new <- df %>% select(a, b) %>% filter(a > 2)
print(df_new)

输出:

 a  b  c
1 1 11 21
2 2 12 22
3 3 13 23
4 4 14 24
  a  b
1 3 12
2 4 13

23. 在 R 中可以创建哪些类型的图表?

数据可视化是 R 语言的一大强项,几乎所有类型的图表都能用 R 创建:

  • 常见图表类型:
    • 条形图(Bar plot)—展示分类数据的数值。
    • 折线图(Line plot)—展示变量的变化过程,通常随时间。
    • 散点图(Scatter plot)—展示两个变量之间的关系。
    • 面积图(Area plot)—基于折线图,对曲线下方区域进行填充。
    • 饼图(Pie chart)—以整体中的占比展示每个类别。
    • 箱线图(Box plot)—展示数据的一组描述性统计。
  • 高级图表类型:
    • 小提琴图(Violin plot)—同时展示数据的描述性统计与分布形状。
    • 热图(Heatmap)—展示数据集中每个数值点的大小。
    • 矩形树图(Treemap)—展示分类数据的数值,常用于整体-部分关系。
    • 树状图(Dendrogram)—展示数据的层级结构与聚类。
    • 气泡图(Bubble plot)—展示三个变量之间的关系。
    • 六边形箱图(Hexbin plot)—在相对较大的数据集中展示两个数值变量的关系。
    • 词云(Word cloud)—展示文本中词语的频率。
    • 分级着色地图(Choropleth map)—展示地理数据的聚合主题统计。
    • 圆形打包图(Circular packing chart)—展示数据的层级结构及数据点数值
    • 等等。

技能路径 使用 R 进行数据可视化 将助您拓展 R 图形的视野。若您希望在更广的语境下学习 R 的数据可视化,请探索全面且对初学者友好的职业路径 R 数据科学家。

24. 什么是 R 中的向量回收(vector recycling)?

当我们尝试对两个长度不同的 R 向量进行运算时,R 解释器会在底层识别较短的向量,按相同顺序循环重复其元素,直到与较长向量长度匹配,然后再执行运算。在开始回收前,解释器会就向量长度不匹配给出警告。

例如,若尝试执行如下加法:

c(1, 2, 3, 4, 5) + c(1, 2, 3)

由于向量回收,第二个向量会被转换为 c(1, 2, 3, 1, 2)。因此,最终结果为 c(2, 4, 6, 5, 7)。

虽然有时向量回收很有用(如当我们期望值呈周期性时),但更多情况下并不合适且易误导。因此,在对向量执行运算前,应留意它们的长度。

25. R 中的 next 和 break 语句有什么作用?

next 语句用于在满足某条件时跳过某次迭代,进入下一次。break 语句用于在满足某条件时停止并退出循环。若用于嵌套循环中的内层循环,它只会退出该内层循环。

在 R 的任意循环类型(for、while、repeat)中都可使用 next 与 break。它们也可在同一循环中同时使用,例如:

for(i in 1:10) {
    if(i < 5)
        next
    if(i == 8)
        break
    print(i)}

输出:

[1] 5
[1] 6
[1] 7

26. R 中 str() 与 summary() 函数有何区别?

str() 返回 R 对象的结构及总体信息,具体内容取决于对象的数据结构。例如,对向量,它会返回其元素类型、索引范围和元素值(若过长则显示前若干个);对数据框,它会返回其类(data.frame)、观测数与变量数、列名、各列的数据类型以及每列的前若干个值。

summary() 返回 R 对象的汇总统计。它多用于数据框和矩阵:对数值列返回最小值、最大值、均值、中位数以及第 1、3 四分位数;对因子列返回各水平的计数。

27. R 中 subset() 和 sample() 函数有何不同?

subset() 用于基于特定条件从数据框或矩阵中抽取行列,或从向量中抽取元素,例如:subset(my_vector, my_vector > 10)。

而 sample() 只能用于向量。它从向量元素中抽取预定义大小的随机样本,可放回或不放回。例如:sample(my_vector, size=5, replace=TRUE)

高级 R 编程面试问题

28. 如何基于其他列在 R 的数据框中创建新列?

1. 使用基础 R 的 transform() 与 ifelse():

df <- data.frame(col_1 = c(1, 3, 5, 7),  col_2 = c(8, 6, 4, 2))
print(df)
​
# 向数据框 df 添加列 col_3
df <- transform(df, col_3 = ifelse(col_1 < col_2, col_1 + col_2, col_1 * col_2))
print(df)

输出:

  col_1 col_2
1     1     8
2     3     6
3     5     4
4     7     2
  col_1 col_2 col_3
1     1     8     9
2     3     6     9
3     5     4    20
4     7     2    14

2. 使用基础 R 的 with() 与 ifelse():

df <- data.frame(col_1 = c(1, 3, 5, 7),  col_2 = c(8, 6, 4, 2))
print(df)
​
# 向数据框 df 添加列 col_3
df["col_3"] <- with(df, ifelse(col_1 < col_2, col_1 + col_2, col_1 * col_2))
print(df)

输出:

  col_1 col_2
1     1     8
2     3     6
3     5     4
4     7     2
  col_1 col_2 col_3
1     1     8     9
2     3     6     9
3     5     4    20
4     7     2    14

3. 使用基础 R 的 apply():

df <- data.frame(col_1 = c(1, 3, 5, 7),  col_2 = c(8, 6, 4, 2))
print(df)
​
# 向数据框 df 添加列 col_3
df["col_3"] <- apply(df, 1, FUN = function(x) if(x[1] < x[2]) x[1] + x[2] else x[1] * x[2])
print(df) 

输出:

  col_1 col_2
1     1     8
2     3     6
3     5     4
4     7     2
  col_1 col_2 col_3
1     1     8     9
2     3     6     9
3     5     4    20
4     7     2    14

4. 使用 dplyr 的 mutate() 配合基础 R 的 ifelse():

df <- data.frame(col_1 = c(1, 3, 5, 7),  col_2 = c(8, 6, 4, 2))
print(df)
​
# 向数据框 df 添加列 col_3
df <- mutate(df, col_3 = ifelse(col_1 < col_2, col_1 + col_2, col_1 * col_2))
print(df)

输出:

  col_1 col_2
1     1     8
2     3     6
3     5     4
4     7     2
  col_1 col_2 col_3
1     1     8     9
2     3     6     9
3     5     4    20
4     7     2    14

29. 如何在 R 中从字符串解析日期?

在 R 中解析日期字符串,应使用 tidyverse 中的 lubridate 包。该包提供多种函数,可依据字符串中的日期模式进行解析并提取标准日期。这些函数包括 ymd()、ymd_hm()、ymd_hms()、dmy()、dmy_hm()、dmy_hms()、mdy()、mdy_hm()、mdy_hms() 等,其中 y、m、d、h、m、s 分别代表年、月、日、时、分、秒。

例如,如果我们对字符串 "05-11-2023"、"05/11/2023" 或 "05.11.2023" 运行 dmy(),都将得到相同结果:2023-11-05。因为三者尽管分隔符不同,但模式一致:日-月-年。

30. R 中 switch() 函数的用途是什么?

switch() 是一种多分支控制语句,用于将表达式与列表项进行匹配并返回相应值。语法如下:

switch(expression, case_1, case_2, case_3....)

传给 switch() 的表达式可以求值为数字或字符串,函数行为因此不同。

1. 若表达式求值为数字,switch() 将按位置匹配返回列表中的项(其索引等于该数字)。若数字大于列表项数量,则返回 NULL。例如:

switch(2, "circle", "triangle", "square")

输出:

"triangle"

2. 若表达式求值为字符串,switch() 将根据名称返回值:

switch("red", "green"="apple", "orange"="carot", "red"="tomato", "yellow"="lemon")

输出:

"tomato"

若存在多重匹配,将返回第一个匹配值。还可以在 switch() 的最后一个参数添加未命名项,作为无匹配时的默认回退。若未设置默认项且无匹配,函数返回 NULL。

switch() 是冗长 if-else 语句的高效替代方案,可减少重复并提升可读性。它通常用于评估单个表达式。我们也可编写更复杂的嵌套 switch 结构以评估多个表达式,但在这种情况下,代码很快会变得难读,从而丧失相对 if-else 的主要优势。

31. apply()、lapply()、sapply() 与 tapply() 有何区别?

这些函数都能在不显式编写循环的情况下,对数据结构迭代并对各元素执行相同操作,但它们在输入输出类型与功能上有所不同。

  • apply()—接收数据框、矩阵或数组,返回向量、列表、矩阵或数组。可按行、按列或双向应用。

  • lapply()—接收向量、列表或数据框,始终返回列表。若输入为数据框,仅按列应用。

  • sapply()—接收向量、列表或数据框,返回尽可能简化的数据结构:输入为向量则返回向量,输入为列表则返回列表,输入为数据框则返回矩阵。

  • tapply()—对不同因子(即分类数据)计算汇总统计。

32. 列举并定义 R 中的控制语句。

R 中有三类控制语句:条件语句、循环语句和跳转语句。

条件语句:

  • if—测试给定条件是否为真,并提供相应操作。

  • if-else—测试给定条件是否为真,为真时执行一组操作,否则执行另一组操作。

  • if... else if... else—逐一测试一系列条件,对每个为真的条件执行相应操作;若均不为真,则执行回退操作。

  • switch—将表达式与列表项匹配,并据此返回列表中的值。

循环语句:

  • for—在 for 循环中对序列进行迭代。

  • while—在 while 循环中检查当前迭代是否满足预定义逻辑条件(可为多个)。

  • repeat—在 repeat 循环中持续执行相同操作,直到满足中断条件(可为多个)。

跳转语句:

  • next—在满足条件时跳过某次迭代并进入下一次。

  • break—在满足条件时于当前迭代停止并退出循环。

  • return—退出函数并返回结果。

33. 什么是正则表达式?在 R 中如何使用?

正则表达式(regex)是在 R 或其他编程语言中用于描述特定文本模式的字符或字符序列,常用于文本挖掘。在 R 中,处理正则主要有两种方式:

  1. 使用基础 R 及其函数(如 grep()、regexpr()、gsub()、regmatches() 等)来定位、匹配、提取和替换正则。
  2. 使用 tidyverse 的专用包 stringr。它提供更直观的函数命名与语法,并具备更丰富的功能,使用更便利。

R 正则表达式指南提供了更多细节。

34. R 中用于机器学习的包有哪些?

  • caret—多种分类与回归算法。
  • e1071—支持向量机(SVM)、朴素贝叶斯、袋装聚类、模糊聚类与 KNN。
  • kernlab—提供基于核的方法用于分类、回归与聚类。
  • randomForest—随机森林分类与回归。
  • xgboost—梯度提升、线性回归与决策树。
  • rpart—分类、回归与生存树的递归分割。
  • glmnet—对线性回归、逻辑回归与多项式回归使用 lasso 与弹性网正则化。
  • nnet—神经网络与多项对数线性模型。
  • tensorflow—TensorFlow 的 R 接口,用于深度神经网络与基于数据流图的数值计算。
  • Keras—Keras 的 R 接口,用于深度神经网络。

35. 如何在 R 中进行特征选择?

我们以 caret 包为例,介绍三种方法及其实现。

  1. 检测并移除数据集中高度相关的特征。

需要创建所有特征的相关矩阵,然后识别高度相关的特征,通常相关系数大于 0.75:

corr_matrix <- cor(features)
highly_correlated <- findCorrelation(corr_matrix, cutoff=0.75)
print(highly_correlated)
  1. 按重要性对数据框的特征进行排序。

需要创建一个训练方案来控制训练参数,用其构建选定模型,然后评估该模型的变量重要性:

control <- trainControl(method="repeatedcv", number=10, repeats=5)
model <- train(response_variable~., data=df, method="lvq", preProcess="scale", trControl=control)
importance <- varImp(model)
print(importance)
  1. 自动选择最优特征。

caret 提供的最流行方法之一是向后选择算法——递归特征消除(RFE)。

需要用选定的重采样方法与预定义函数列表计算控制参数,将特征、目标变量、保留特征数量与控制参数传入 RFE 算法,然后提取选出的预测变量:

control <- rfeControl(functions=caretFuncs, method="cv", number=10)
results <- rfe(features, target_variable, sizes=c(1:8), rfeControl=control)
print(predictors(results))

若您需要强化在 R 中的机器学习技能,这里有一份扎实全面的资源:机器学习科学家(R)。

36. 什么是相关与协方差?如何在 R 中计算?

相关性衡量两个变量线性关系的强度与方向,取值范围为 -1(完全负相关)到 1(完全正相关)。协方差衡量两个变量相对变化的程度以及线性关系的方向。与相关不同,协方差没有取值范围限制。

在 R 中,计算相关用 cor(),计算协方差用 cov()。两者语法相同:传入想要计算的两个变量(向量)(如 cor(vector_1, vector_2) 或 cov(vector_1, vector_2)),或直接传入整个数据框(如 cor(df) 或 cov(df))以计算各变量之间的相关或协方差。对于两个向量,结果是单个值;对于数据框,结果是相关(或协方差)矩阵。

37. 列举并定义在 R 中评估模型准确性的多种方法。

以下列出若干方法及其在 R 的 caret 包中的实现。

  • 数据划分—将整个数据集划分为训练集与测试集。训练集用于拟合模型,测试集用于在未见数据上评估性能。此方法在大数据上尤其有效。在 R 中实现数据划分,可使用 createDataPartition() 并将 p 参数设为训练集所占比例。
  • 自助法重采样(Bootstrap)—从数据集中随机抽样并在样本上估计模型。重采样迭代多次,且采用放回抽样。在 R 中实现时,在定义模型训练控制时将 trainControl() 的 method 参数设为 "boot"。
  • 交叉验证方法
    • k 折交叉验证—将数据集分为 k 个子集。模型在 k-1 个子集上训练,并在剩余一个子集上测试。对所有子集重复上述过程,最后评估模型准确性。
    • 重复 k 折交叉验证—与 k 折原理相同,但将数据集多次划分为 k 个子集。每次重复计算模型准确性,最终的准确性取所有重复的平均值。
    • 留一法交叉验证(LOOCV)—每次留出一个观测作为测试,其余观测用于训练;对所有观测重复。

在 R 中实现这些交叉验证方法时,在定义训练控制时将 trainControl() 的 method 参数分别设为 "cv"、"repeatedcv" 或 "LOOCV"。

38. 什么是卡方检验?如何在 R 中执行?

卡方假设检验用于判断两个分类变量是否独立,或它们之间是否存在相关性。在 R 中使用 stats 包的 chisq.test() 完成。步骤如下:

1. 使用基础 R 的 table() 函数,以目标分类变量创建列联表:

table = table(df["var_1"], df["var_2"]) 

2. 将列联表传入 chisq.test():

chisq.test(table) 

您可以在我们的课程 R 中的假设检验 中复习卡方检验与其他假设检验。

39. R 中的 Shiny 是什么?

Shiny 是一个开源 R 包,使得仅用 R(无需 HTML、CSS 或 JavaScript 知识)即可轻松快速构建完全交互的 Web 应用与网页。Shiny 提供丰富的基础与高级特性、组件、布局、示例应用及其底层代码供扩展与自定义,并汇集了来自各领域(技术、体育、银行、教育等)的用户作品展示。

40. with() 与 within() 函数有何区别?

with() 会在数据框的一列或多列上评估 R 表达式,并输出结果,但不修改数据框。within() 会在数据框的一列或多列上评估表达式,修改数据框,并输出结果。下面以示例数据框展示二者:

df <- data.frame(a = c(1, 2, 3),  b = c(10, 20, 30))
print(df)

with(df, a * b)

print(within(df, c <- a * b))

输出:

  a  b
1 1 10
2 2 20
3 3 30

10  40  90
  a  b  c
1 1 10 10
2 2 20 40
3 3 30 90

使用 within() 时,如需保留修改,需要将函数输出赋给变量。

结语

总之,本文梳理了 40 道最常见的 R 编程面试题及其参考答案。希望借助这些信息,无论您是在寻找 R 相关的工作,还是在为公司招募合适的候选人,都能更有信心,顺利应对面试。

若想通过实战练习回答问题,请查看我们的课程 用 R 练习统计学面试题。

Elena Kosourova

作者

Elena Kosourova

IBM 认证数据科学家(2020)。此前曾在全球油气田担任石油地质学家/地质建模师,拥有 12 年以上国际工作经验。精通 Python、R 和 SQL。专长领域包括:数据清洗、数据处理、数据可视化、数据分析、数据建模、统计、数据叙事、机器学习。具备丰富的数据科学社区管理经验,并长期撰写与审校数据科学及职业发展相关的文章与教程。

主题