为了提高您在 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 中有若干数据类型 ,包括:
Numeric(数值) —十进制数。
Integer(整数) —整型数。
Character(字符) —字母、数字或符号,或它们的任意组合,用双引号或单引号括起。
Factor(因子) —来自预定义可能值集合的类别,通常具有内在顺序。
Logical(逻辑) —布尔值 TRUE 和 FALSE,在底层分别用 1 和 0 表示。
4. 列举并定义 R 中的一些基本数据结构。
Vector(向量) —一维数据结构,用于存储同一数据类型的值。
List(列表) —多维数据结构,可存储任意数据类型和值以及其他数据结构。
Matrix(矩阵) —二维数据结构,用于存储同一数据类型的值。
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
readxl
要更深入了解 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. 由其他数据框 :
df <- cbind( df1, df2) 技术支持
df <- rbind( df1, df2) 技术支持
8. 如何在 R 的数据框中添加新列?
使用 $ 符号:
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 技术支持
使用方括号:
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 技术支持
使用 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
} 技术支持
函数名 —定义后用于调用该函数的对象名。
函数参数 —放在圆括号中、以逗号分隔的变量,每次调用函数时会被设置为实际实参。
函数体 —位于花括号中的代码块,按预定义顺序对输入参数执行操作。通常包含 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 中给变量赋值?
使用赋值运算符 <-,如 my_var <- 1—R 中最常见的赋值方式。
使用等号运算符 =,如 my_var = 1—多用于函数定义内为参数赋值。
使用右向赋值运算符 ->,如 my_var -> 1—可用于管道中。
使用全局赋值运算符,左向(<<-)或右向(->>),如 my_var <<- 1—用于在函数定义内创建全局变量。
16. R 中变量命名有哪些要求?
在课程 高效 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() 函数聚合数据。该函数的关键参数依次为:
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 <- 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" ] <- 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" ] <- 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 <- 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—将表达式与列表项匹配,并据此返回列表中的值。
循环语句:
跳转语句:
33. 什么是正则表达式?在 R 中如何使用?
正则表达式(regex)是在 R 或其他编程语言中用于描述特定文本模式的字符或字符序列,常用于文本挖掘。在 R 中,处理正则主要有两种方式:
使用基础 R 及其函数(如 grep()、regexpr()、gsub()、regmatches() 等)来定位、匹配、提取和替换正则。
使用 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 包为例,介绍三种方法及其实现。
检测并移除数据集中高度相关的特征。
需要创建所有特征的相关矩阵,然后识别高度相关的特征,通常相关系数大于 0.75:
corr_matrix <- cor( features)
highly_correlated <- findCorrelation( corr_matrix, cutoff= 0.75 )
print( highly_correlated) 技术支持
按重要性对数据框的特征进行排序。
需要创建一个训练方案来控制训练参数,用其构建选定模型,然后评估该模型的变量重要性:
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) 技术支持
自动选择最优特征。
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 练习统计学面试题 。
为了提高您在 R 面试中成功的机会,无论您是在找工作还是负责招聘,提前了解可能会被问到的问题(或可以问候选人的问题)总是有益的。
本文汇总了40道基础的 R 编程面试题及其参考答案,涵盖从入门到高级的各个资历水平,并包含若干通用面试问题。为便于阅读,所有技术问题分为三类:入门、进阶和高级问题。
作为准备 R 编程面试的补充资源,您可以参考以下博客和课程:
R 编程通用面试问题
在 R 面试的开场阶段,面试官可能会就候选人整体的 R 使用经验提出一些非技术性问题,例如:
如果您是求职者,应当提前思考这些及类似问题并准备答案。即便您尚无实际的 R 工作经验也不必担心:描述您在 R 编程方面的实习,或您在校期间完成的个人或团队R 项目,同样有效。
此外,如果您应聘的是入门级岗位,面试官并不一定期望您具备丰富(甚至任何)的 R 工作经验。请记住,既然您已收到面试邀请,说明公司已对您的简历表示认可。
入门级 R 编程面试问题
让我们从一些基础的技术性 R 面试题开始,这些问题常见于潜在雇主的考察中。它们要求您掌握基础知识,并具有一定的 R 实操经验。
1. 什么是 R?它有哪些主要特性?
R 是一种广泛用于解决数据科学问题的编程语言与环境,特别为统计计算与数据可视化而设计。其主要特性包括:
2. 使用 R 有哪些劣势?
3. 列举并定义 R 中的一些基本数据类型。
R 中有若干数据类型,包括:
TRUE和FALSE,在底层分别用 1 和 0 表示。4. 列举并定义 R 中的一些基本数据结构。
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() 函数:要在当前 R 工作环境中加载已安装的包,可使用
library()或require()。两者都接收不带引号的包名并加载包,例如library(caret)。不同之处在于找不到包时的行为:library()会抛出错误并停止程序执行,而require()会给出警告并继续执行。7. 如何在 R 中创建数据框?
1. 由一个或多个向量(长度相同)—使用
data.frame()函数:2. 由矩阵—使用
data.frame()函数:3. 由向量列表(长度相同)—使用
data.frame()函数:4. 由其他数据框:
将数据框横向合并(仅当数据框行数相同,且记录相同且顺序一致)—使用
cbind()函数:将数据框纵向合并(仅当它们具有数量相等、名称一致、数据类型相同且顺序一致的列)—使用
rbind()函数:8. 如何在 R 的数据框中添加新列?
$符号:输出:
输出:
使用
cbind()函数:输出:
在上述三种方法中,既可以赋单个值,也可以赋向量,或基于该数据框或其他数据框的现有列计算新列。
9. 如何在 R 的数据框中删除列?
1. 使用 tidyverse 集合中 dplyr 包的
select()函数。每个要删除的列名前加负号:如果待删除的列太多,更合理的方式是只保留其余列而不是删除目标列。此时语法类似,但保留的列名不加负号:
2. 使用基础 R 的内置 subset() 函数。若只需删除一列,将带负号的列名赋给函数的 select 参数。要删除多列,则将带负号的列名构成向量赋给该参数:
如果待删除的列太多,更合理的方式是只保留其余列。此时语法类似,但不加负号:
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 用户青睐:
欲了解 RStudio 是什么、如何安装并开始使用,请参阅RStudio 教程。
12. 什么是 R Markdown?
R Markdown 是一个免费开源的 R 包,为构建数据科学项目提供创作框架。使用它,我们可以编写一个同时包含叙述、代码和图形的 .rmd 文件,并将其渲染为所选输出格式。其主要特点包括:
13. 如何在 R 中创建自定义函数?
在 R 中创建自定义函数,需要使用关键字
function,语法如下:return()(返回函数输出)或print()(打印输出)。一个简单的 R 自定义函数示例:
14. 列举一些 R 中常用的数据可视化包。
进阶 R 编程面试问题
对于更有经验的从业者,面试官很可能会提出需要更深入 R 知识的问题。以下是一些需要准备的内容:
15. 如何在 R 中给变量赋值?
使用赋值运算符
<-,如my_var <- 1—R 中最常见的赋值方式。使用等号运算符
=,如my_var = 1—多用于函数定义内为参数赋值。使用右向赋值运算符
->,如my_var -> 1—可用于管道中。使用全局赋值运算符,左向(
<<-)或右向(->>),如my_var <<- 1—用于在函数定义内创建全局变量。16. R 中变量命名有哪些要求?
变量名可由字母、数字、点与下划线组合而成。不能包含其他符号,包括空格。
变量名必须以字母或点开头。
若以点开头,点后不能紧跟数字。
R 中的保留字(如
TRUE、for、NULL等)不能作为变量名。变量名区分大小写。
在课程 高效 R 代码编写 中,您将学习更多 R 代码编写的最佳实践。
17. R 中有哪些类型的循环?各自语法是什么?
1. for 循环—对序列进行迭代,次数等于其长度(除非使用
break和/或next语句),对序列的每个元素执行相同操作。这是最常见的循环类型。语法如下:2. while 循环—在满足预先定义的逻辑条件(可为多个)之前,反复执行相同操作(除非使用
break和/或next语句)。与 for 不同,while 在执行前并不知晓迭代次数。运行 while 前需先赋初值,并在循环体内每次迭代更新。语法如下:3. repeat 循环—重复执行相同操作,直至满足预定义的中断条件(可为多个)。为引入中断条件,repeat 循环需包含 if 语句代码块,且其中必须含有
break。与 while 相似,repeat 的迭代次数也无法事先知晓。语法如下:您可在教程 R 中的循环 中了解更多。
18. 如何在 R 中聚合数据?
在 R 中使用
aggregate()函数聚合数据。该函数的关键参数依次为:x—要聚合的数据框。by—按哪些因子分组的列表。FUN—对每组计算汇总统计的聚合函数(如mean、max、min、count、sum)。19. 如何在 R 中合并数据?
1. 使用
cbind()函数—仅当数据框行数一致且记录相同且顺序一致:2. 使用
rbind()函数将数据框纵向合并—仅当它们具有数量相等、名称一致、数据类型相同且顺序一致的列:3. 使用
merge()函数按共有列(通常是 ID 列)合并数据框:4. 使用 dplyr 包的
join()函数按共有列(通常为 ID)合并数据框:type参数可取:inner、left、right或full。20. 如何在 R 中拼接字符串?
可使用
paste()或cat()函数拼接两个或更多字符串。前者更常用。两者均可接收任意数量的待拼接字符串,并可接收可选参数sep(以及其他可选参数)—用于指定结果字符串中各部分的分隔符(默认空格)。21. 如何在 R 中转置二维数据?
我们可以对数据框或矩阵进行转置,使列变为行、行变为列。可使用基础 R 的
t()函数,例如:输出:
22. 如何在 R 中将多个操作串联起来?
可使用 tidyverse 提供的管道运算符(
%>%)将多个操作串联。使用该运算符可以构建函数流水线:第一个函数的输出作为第二个函数的输入,依此类推,直至流水线结束。这样无需创建额外变量,并显著提升代码可读性。在数据框上使用管道运算符的示例:
输出:
23. 在 R 中可以创建哪些类型的图表?
数据可视化是 R 语言的一大强项,几乎所有类型的图表都能用 R 创建:
技能路径 使用 R 进行数据可视化 将助您拓展 R 图形的视野。若您希望在更广的语境下学习 R 的数据可视化,请探索全面且对初学者友好的职业路径 R 数据科学家。
24. 什么是 R 中的向量回收(vector recycling)?
当我们尝试对两个长度不同的 R 向量进行运算时,R 解释器会在底层识别较短的向量,按相同顺序循环重复其元素,直到与较长向量长度匹配,然后再执行运算。在开始回收前,解释器会就向量长度不匹配给出警告。
例如,若尝试执行如下加法:
由于向量回收,第二个向量会被转换为
c(1, 2, 3, 1, 2)。因此,最终结果为c(2, 4, 6, 5, 7)。虽然有时向量回收很有用(如当我们期望值呈周期性时),但更多情况下并不合适且易误导。因此,在对向量执行运算前,应留意它们的长度。
25. R 中的 next 和 break 语句有什么作用?
next语句用于在满足某条件时跳过某次迭代,进入下一次。break语句用于在满足某条件时停止并退出循环。若用于嵌套循环中的内层循环,它只会退出该内层循环。在 R 的任意循环类型(for、while、repeat)中都可使用
next与break。它们也可在同一循环中同时使用,例如:输出:
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():输出:
2. 使用基础 R 的
with()与ifelse():输出:
3. 使用基础 R 的
apply():输出:
4. 使用 dplyr 的
mutate()配合基础 R 的ifelse():输出:
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()的表达式可以求值为数字或字符串,函数行为因此不同。1. 若表达式求值为数字,
switch()将按位置匹配返回列表中的项(其索引等于该数字)。若数字大于列表项数量,则返回NULL。例如:输出:
2. 若表达式求值为字符串,
switch()将根据名称返回值:输出:
若存在多重匹配,将返回第一个匹配值。还可以在
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 中,处理正则主要有两种方式:
grep()、regexpr()、gsub()、regmatches()等)来定位、匹配、提取和替换正则。R 正则表达式指南提供了更多细节。
34. R 中用于机器学习的包有哪些?
35. 如何在 R 中进行特征选择?
我们以 caret 包为例,介绍三种方法及其实现。
需要创建所有特征的相关矩阵,然后识别高度相关的特征,通常相关系数大于 0.75:
需要创建一个训练方案来控制训练参数,用其构建选定模型,然后评估该模型的变量重要性:
caret 提供的最流行方法之一是向后选择算法——递归特征消除(RFE)。
需要用选定的重采样方法与预定义函数列表计算控制参数,将特征、目标变量、保留特征数量与控制参数传入 RFE 算法,然后提取选出的预测变量:
若您需要强化在 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 包中的实现。
createDataPartition()并将 p 参数设为训练集所占比例。trainControl()的method参数设为"boot"。在 R 中实现这些交叉验证方法时,在定义训练控制时将
trainControl()的method参数分别设为"cv"、"repeatedcv"或"LOOCV"。38. 什么是卡方检验?如何在 R 中执行?
卡方假设检验用于判断两个分类变量是否独立,或它们之间是否存在相关性。在 R 中使用 stats 包的
chisq.test()完成。步骤如下:1. 使用基础 R 的
table()函数,以目标分类变量创建列联表:2. 将列联表传入
chisq.test():您可以在我们的课程 R 中的假设检验 中复习卡方检验与其他假设检验。
39. R 中的 Shiny 是什么?
Shiny 是一个开源 R 包,使得仅用 R(无需 HTML、CSS 或 JavaScript 知识)即可轻松快速构建完全交互的 Web 应用与网页。Shiny 提供丰富的基础与高级特性、组件、布局、示例应用及其底层代码供扩展与自定义,并汇集了来自各领域(技术、体育、银行、教育等)的用户作品展示。
40.
with()与within()函数有何区别?with()会在数据框的一列或多列上评估 R 表达式,并输出结果,但不修改数据框。within()会在数据框的一列或多列上评估表达式,修改数据框,并输出结果。下面以示例数据框展示二者:输出:
使用
within()时,如需保留修改,需要将函数输出赋给变量。结语
总之,本文梳理了 40 道最常见的 R 编程面试题及其参考答案。希望借助这些信息,无论您是在寻找 R 相关的工作,还是在为公司招募合适的候选人,都能更有信心,顺利应对面试。
若想通过实战练习回答问题,请查看我们的课程 用 R 练习统计学面试题。