R func
rep()
rep() (represent/repeat) 函数是 R 中用于重复一个对象(例如,向量、数值或字符串)的核心函数。它非常常用
参数:
x:要重复的对象(向量、列表等)。times:整体重复x的次数。length.out:指定最终结果向量的长度。each:重复x中的每个元素的次数
R
tips_rep = tips[rep(1:nrow(tips),each=2),] # 将tips每行复制1次
head(tips_rep)
paste()
**paste()**函数用于将多个字符串或变量值拼接成一个字符串。这个函数非常直接且简单。
默认情况下,paste()函数会使用空格作为分隔符,但可以通过sep参数来自定义分隔符。
R
info = c(1,2,4,6)
names = c('A','B','C','D')
piepercent = paste(round(100*info/sum(info)), "%") # 生成pie图扇区的标注信息
pie(info, labels=piepercent, main = "XX分析", col=rainbow(4), family='GB1')
字符串相关
substring()
函数用于截取字符串
R
# 从第 2 位截取到第 5 位,索引从1开始,包含结束位置
result <- substring("Runoob", 2, 5)
print(result) # 截取了4个字符
gsub
函数来替换字符串中的特定字符或模式
R
str <- "Hello, World!"
new_str <- gsub("World", "R", str)
# 输出: "Hello, R!"
strsplit
分割字符串
R
str <- "Hello, World!"
split_str <- strsplit(str, ",") # 返回一个list
nchar
nchar() 函数用于计数字符串或数字列表的长度
R
result <- nchar("Google Baidu Taobao") # 长度包含空格
print(result)
大小写
toupper() & tolower() 函数用于将字符串的字母转化为大写或者小写。
ifelse
ifelse 是 R 语言中一个常用的条件判断函数,用于根据条件的真假返回不同的结果。它支持向量化操作,非常适合对向量中的每个元素进行条件判断。
基本语法:ifelse(condition, true_value, false_value)
R
# 示例:判断向量中每个元素是否大于3
x <- c(1, 2, 3, 4, 5)
result <- ifelse(x > 3, "大于3", "小于等于3")
print(result)
# 输出: [1] "小于等于3" "小于等于3" "小于等于3" "大于3" "大于3"
x <- 15
result <- ifelse(x < 10, "小于10",
ifelse(x < 20, "10到20之间",
ifelse(x < 30, "20到30之间", "大于等于30")))
print(result)
# 输出: [1] "10到20之间"
dplyr
dplyr 是 R 语言中最强大的数据操作包之一。 通过 管道符 %>% 连接多个操作, 让代码清晰易读。
filter()
根据指定条件保留或过滤数据
R
library(dplyr)
tips <- read.csv('../../seaborn-data/tips.csv')
iris <- read.csv('../../seaborn-data/iris.csv')
#选出人数最多的记录
tips %>% filter(size == max(size))
# 组合条件
tips %>% filter(size == 4 & total_bill > 25.0)
filter() 支持逻辑运算符
&(且)、|(或)、!(非)
arrange()
对数据行进行排序,默认升序
R
head(arrange(tips,total_bill)) # 正排序
head(arrange(tips,tip,desc(total_bill)))# 到排序,多条件
上例可以用管道
R
tips |> arrange(total_bill) |> head()
tips |> arrange(tip,desc(total_bill) |> head()
|> 等同于 %>%
select()
选择指定的列,支持模糊匹配
R
# 手动选择列
tips %>% select(total_bill, day, smoker) %>% head()
# 模糊匹配
iris %>% select(contains("length")) %>% head()
# 调整列顺序 + everything()
iris %>% select(petal_Width, species, everything()) %>% head()
select 辅助函数:
starts_with("abc")匹配开头contains("ijk")包含字符num_range("x", 1:3)x1, x2, x3ends_with("xyz")匹配结尾matches("regex")正则表达式everything()所有剩余列
mutate()
添加新列或修改现有列
R
# 简单计算
iris %>% mutate(sepal_length_width = sepal_length + sepal_width) %>% head()
# count 生成n列,mutate生成ratio列且是day的汇总
tips_day_count <- tips |>
count(day,smoker)|>
group_by(day) |>
mutate(ratio = sum(n))
#day smoker n ratio
#<chr> <chr> <int> <int>
#Fri No 4 19
#Fri Yes 15 19
#Sat No 45 87
#Sat Yes 42 87
#Sun No 57 76
#Sun Yes 19 76
#Thur No 45 62
#Thur Yes 17 62
summarize()
对数据进行汇总,常与 group_by 联用
聚合操作中包括一个计数(n())或非缺失值的计数(sum(!is_na()))
R
tips %>%
group_by(sex,smoker) %>%
summarise(max_totail=max(total_bill),max_tip=max(tip),n=n())
# 这里的n是分组后的数量
# sex smoker max_totail max_tip n
# <chr> <chr> <dbl> <dbl> <int>
# Female No 35.83 5.2 54
# Female Yes 44.30 6.5 33
# Male No 48.33 9.0 97
# Male Yes 50.81 10.0 60
常用摘要函数
- 位置度量:mean(均值)、median(中位数)
- 分散程度度量:sd(均方误差)、IQR(四分位距)、mad(绝对中位差)
- 秩的度量:min(最小值)、max(最大值)、quantile(x,0.25)(找出 x 中按从小到大顺序大于前25% 而小于后 75% 的值)
- 定位度量:first、last、nth(x,2)
- 计数:n()、sum(!is_na())
- 逻辑值的计数和比例:sum(x > 10) 、mean(y == 0)
tibble
tibble 也是一种数据框,它对传统数据框的功能进行了一些修改,更易于使用。
tibble 在输出时,列名下面有一行字母的缩写,描述了每个变量的类型。tibble 的数据类型包括以下几种:int-整数型、dbl-浮点型、chr-字符串型、lgl-逻辑型(True和False)、fct-因子型、date-日期型、dttm-日期时间型。
创建
可以通过 tibble() 函数使用一个向量来创建新 tibble。tibble() 会自动重复长度为 1 的输 入,并可以使用刚刚创建的新变量
R
library(tidyverse)
tibble(
x = 1:5,
y = 1,
z = x ^ 2 + y
)
类型转换
R
library(tibble)
iris_tibble <- as_tibble(iris)
iris_tibble[1:10,]
tidyr
pivot_longer
pivot_longer 是 R 语言 tidyr 包中的函数,用于将宽格式数据转换为长格式,使数据更易分析。它可以将多列合并为两列,并支持处理缺失值和复杂列名。
R
pivot_longer(
data, # 输入数据框
cols, # 指定要转换的列(如 starts_with("Q"), c(x1, x2))
names_to = "name", # 新生成的变量名列名(默认 "name")
values_to = "value", # 新生成的值列名(默认 "value")
names_sep = NULL, # 列名分隔符(用于拆分复合列名)
names_pattern = NULL # 正则表达式提取多维度信息
)
简单示例
R
library(tidyr)
sales_wide <- data.frame(
region = c("North", "South"),
Q1 = c(100, 150),
Q2 = c(120, 130)
)
sales_long <- pivot_longer(
sales_wide,
cols = starts_with("Q"),# cols=c('Q1','Q2'),
names_to = "quarter",
values_to = "revenue"
)
print(sales_long)
# A tibble: 4 × 3
# region quarter revenue
# <chr> <chr> <dbl>
#1 North Q1 100
#2 North Q2 120
#3 South Q1 150
#4 South Q2 130
#tidyverse
readr
readr 的多数函数用于将文件转换为数据框,主要包含read_csv、read_tsv、read_log等
以read_csv为例:
- read_csv() 函数都使用数据的第一行作为列名称
- 可以使用 skip = n 来跳过前 n 行
- 可以使用comment = "#" 来丢弃所有以 # 开头的行
- 可以使用 col_names = FALSE 来通知 read_csv() 不要将第一行作为列标题,而是将各列依次标注为 X1 至 Xn
- 可以向 col_names 传递一个字符向量,以用作列名称
- na 设定使用哪个值(或哪些值)来表示文件中的缺失值
parse_*
parse_*() 函数族,这些函数接受一个字符向量,并返回一个特定向量,如逻辑、整数或日期向量
- parse_logical:解析bool,例如c("TRUE", "FALSE", "NA") 转换为c(TRUE,FALSE,NA)
- parse_integer:解析数字,例如c("1", "2", "3")转换为c(1,2,3)
- parse_date:解析日期,例如c("2010-01-01", "1979-10-14")) 转为Date[1:2], format: "2010-01-01" "1979-10-14"
数值
R
parse_double("1.23") # 1.23
parse_double("1,23", locale = locale(decimal_mark = ",")) # 1.23
parse_number("$100") # 100 提取数字
parse_number("$123,456,789") #适用于美国 1.23e+08
parse_number("123.456.789",locale = locale(grouping_mark = ".")) #适用于多数欧洲国家 1.23e+08
parse_number("123'456'789",locale = locale(grouping_mark = "''")) #适用于瑞士 1.23e+08
字符串
R
x1 <- "El Ni\xf1o was particularly bad this year"
parse_character(x1, locale = locale(encoding = "Latin1"))
guess_encoding() 函数可以帮助找出编码方式,guess_encoding() 的第一个参数可以是一个文件路径,也可以是一个原始向量
R
guess_encoding(charToRaw(x1))
#> encoding confidence
#> 1 ISO-8859-1 0.46
#> 2 ISO-8859-9 0.23
因子
R 使用因子表示取值范围是已知集合的分类变量。
parse_factor() 函数的 levels 参数被赋予一个已知向量,那么只要存在向量中没有的值,就会生成一条警告。
R
fruit <- c("apple", "banana")
parse_factor(c("apple", "banana", "bananana"), levels = fruit)
# apple banana <NA> #bananana是未知项,转换为NA
日期与时间
- parse_datetime:期待的是符合 ISO 8601 标准的日期时间
- parse_date:期待的是四位数的年份、一个 - 或 /、月、一个 - 或 /,然后是日
- parse_time() 期待的是小时、:、分钟、可选的 : 和秒
日期格式化符号:
- 年:%Y(4 位数);%y(2 位数;00-69 → 2000-2069、70-99 → 1970-1999)
- 月:%m(2 位数);%b(简写名称,如 Jan);%B(完整名称,如 January
- 日:%d(1 位或 2 位数);%e(2 位数)
- 时:%H(0-23 小时);%I(0-12 小时,必须和 %p 一起使用);%p(表示 a.m./p.m.)。
- 分:%M(分钟)
- 秒:%S(整数秒);%OS(实数秒)
- 时区:%Z(时区,America/Chicage 这样的名称);%z(与国际标准时间的时差,如 +0800)
R
parse_date("01/02/15", "%m/%d/%y") # "2015-01-02"
parse_date("01/02/15", "%d/%m/%y") # "2015-02-01"
parse_guess
parse_guess()函数用于猜测数据类型
R
guess_parser("2010-10-01")
#> [1] "date"
guess_parser("15:01")
#> [1] "time"
guess_parser(c("TRUE", "FALSE"))
#> [1] "logical"
guess_parser(c("1", "5", "9"))
#> [1] "integer"
guess_parser(c("12,352,561"))
#> [1] "number"
str(parse_guess("2010-10-10"))
#> Date[1:1], format: "2010-10-10"
写入文件
write_csv() 和 write_tsv()两个函数可以将数据写回到磁盘。
如果想要将 CSV 文件导为 Excel 文件,可以使用 write_excel_csv() 函数,该函数会在文件开头写入一个特殊字符(字节顺序标记),告诉 Excel 这个文件使用的是 UTF-8 编码。
这几个函数中最重要的参数是 x(要保存的数据框)和 path(保存文件的位置)。
stringr
stringr包是专门处理字符串的,函数都以str开头,名称更直观且比系统的好用。
常用函数
- str_length :返回字符串中的字符数量
- str_c:组合两个或更多字符串,可使用 sep 参数来控制字符串间的分隔方式
- str_replace_na:替换缺失值为空字符,防止NA传染
- str_sub:提取字符串的一部分, start 和 end 参数,给出了子串的位置(包括 start 和 end 在内)
- str_to_upper/str_to_lower:大小写转换
正则
str_view/str_view_all
这两个函数接收一个字符向量和一个正则表达式,输出是如何匹配。
R
x <- c('apple','banana','pear')
str_view(x,'an')
# │ b<an><an>a
匹配检查
验证字符向量是否匹配一种模式,可以使用str_detect()函数,返回一个与输出向量长度有相同长度的逻辑向量
R
x <- c('apple','banana','pear')
str_detect(x,'e')
# TRUE FALSE TRUE
获取匹配的数据
R
x[str_detect(x,'e')]
# "apple" "pear"
还可以用str_subset函数,直接返回配的字符
R
str_subset(x,'e')
str_count是str_detect的一个变体,返回的是符合规则的字符数量。
提取匹配内容
str_extract/str_extract_all 可以提取实际匹配的内容
R
str_extract(x,'ana')
# NA "ana" NA
str_extract_all 返回的是一个列表
R
str_extract_all(x,'ana')
# [[1]]
# character(0)
#
# [[2]]
# [1] "ana"
#
# [[3]]
# character(0)
分组匹配
str_match() 函数则可以给出每个独立分组。str_match() 返回的不是字符向量,而是一个矩阵,其中一列是完整匹配,后面的列是每个分组的匹配:
R
has_noun <- sentences |> str_subset("(a|the) ([^ ]+)") |> head(10)
has_noun |> str_match("(a|the) ([^ ]+)")
# [,1] [,2] [,3]
# [1,] "the smooth" "the" "smooth"
# [2,] "the sheet" "the" "sheet"
# [3,] "the depth" "the" "depth"
# [4,] "a chicken" "a" "chicken"
# [5,] "the parked" "the" "parked"
# [6,] "the sun" "the" "sun"
# [7,] "the huge" "the" "huge"
# [8,] "the ball" "the" "ball"
# [9,] "the woman" "the" "woman"
#[10,] "a helps" "a" "helps"
果想要找出每个字符串的所有匹配,需要使用 str_match_all() 函数。
替换
str_replace() 和 str_replace_all() 函数可以使用新字符串替换匹配内容。
R
str_replace(x, "[aeiou]", "-")
# [1] "-pple" "b-nana" "p-ar"
通过提供一个命名向量,使用 str_replace_all() 函数可以同时执行多个替换:
R
x <- c("1 house", "2 cars", "3 people")
str_replace_all(x, c("1" = "one", "2" = "two", "3" = "three"))
# "one house" "two cars" "three people"
除了使用固定字符串替换匹配内容,还可以使用回溯引用来插入匹配中的分组
R
# 交换了第二个单词和第三个单词的顺序:
sentences |>
str_replace("([^ ]+) ([^ ]+) ([^ ]+)", "\\1 \\3 \\2") |>
head(5)
拆分
str_split() 函数可以将字符串拆分为多个片段
R
sentences |> head(5) |> str_split(" ")
"a|b|c|d" |> str_split("\\|") |> pluck(1)
lubridate
lubridate库的主要功能是处理时间、日期
创建日期或时间
获取当前日期可以用today()或now()
R
library(tidyverse)
library(lubridate)
library(nycflights13)
today()
# "2026-03-18"
now()
# "2026-03-18 08:29:24 CST"
也可以通过字符串创建,函数非常简单,用y、m、d、h、m、s组合
R
ymd("2017-01-31") # 返回date类型
#> [1] "2017-01-31"
mdy("January 31st, 2017")
#> [1] "2017-01-31"
dmy("31-Jan-2017")
#> [1] "2017-01-31"
ymd(20170131)
#> [1] "2017-01-31"
ymd_hms("2017-01-31 20:11:59") # 返回datetime类型
#> [1] "2017-01-31 20:11:59 UTC"
mdy_hm("01/31/2017 08:01")
#> [1] "2017-01-31 08:01:00 UTC"
也可以使用 make_date() 、make_datetime()函数创建日期,需要指定y、m、d、h、m、s等参数
R
make_date(2021,3,14)
# 也可以在 data.frame、tibble中使用
flights |>
+ select(year,month,day,hour,minute) |>
+ mutate(departure=make_datetime(year,month,day,hour,minute))
还可以通过as_datetime() 和 as_date() 函数的功能
R
as_date(today()) # 返回date类型
as_datetime(now())# 返回datetime类型
日期时间成分
如果想要提取出日期中的独立成分,可以使用以下访问器函数:year()、month()、mday()(一个月中的第几天)、yday()(一年中的第几天)、week()、wday()(一周中的第几天)、hour()、minute() 和 second()
对于 month() 和 wday() 函数,你可以设置 label = TRUE 来返回月份名称和星期数的缩写,还可以设置 abbr = FALSE 来返回全名
R
datetime <- ymd_hms("2025-07-08 12:34:56")
hour(datetime)
# > [1] 12
year(datetime)
# > [1] 2025
month(datetime)
# > [1] 7
month(datetime,label = TRUE)
# > [1] 7月
# > Levels: 1月 < 2月 < 3月 < 4月 < 5月 < 6月 < 7月 < 8月 < 9月 < 10月 < 11月 < 12月
week(datetime)
# > [1] 27
可以使用每个访问器函数来设置日期时间中的成分:
R
year(datetime) <- 2020
datetime
# > [1] "2020-07-08 12:34:56 UTC"
可以通过 update() 函数创建一个新日期时间。这样也可以同时设置多个成分:
R
update(datetime, year = 2020, month = 2, mday = 2, hour = 2)
# > [1] "2020-02-02 02:34:56 UTC"
时间间隔
- 时期:以秒为单位表示一段精确的时间。
- 阶段:表示由人工定义的一段时间,如几周或几个月。
- 区间:表示从起点到终点的一段时间。
时期
表示时间差别的对象记录时间间隔的单位可以是秒、分钟、小时、日或周。因为这种模棱两可的对象处理起来非常困难,所以 lubridate 提供了总是使用秒为单位的另一种计时对象------时期
R
# 转换
as.duration(today()-ymd(19900904))
# "1121558400s (~35.54 years)"
# 以下是直接创建
dseconds(15)
dminutes(10) # "600s (~10 minutes)"
dhours(c(12, 24)) #> [1] "43200s (~12 hours)" "86400s (~1 days)"
阶段
阶段也是一种时间间隔,但它不以秒为单位;相反,它使用"人工"时间,比如日和月。
R
seconds(15)
#> [1] "15S"
minutes(10)
#> [1] "10M 0S"
hours(c(12, 24))
#> [1] "12H 0M 0S" "24H 0M 0S"
days(7)
#> [1] "7d 0H 0M 0S"
months(1:6)
#> [1] "1m 0d 0H 0M 0S" "2m 0d 0H 0M 0S" "3m 0d 0H 0M 0S"
#> [4] "4m 0d 0H 0M 0S" "5m 0d 0H 0M 0S" "6m 0d 0H 0M 0S"
weeks(3)
#> [1] "21d 0H 0M 0S"
years(1)
#> [1] "1y 0m 0d 0H 0M 0S"
可以对阶段进行加法和乘法操作:
R
10 * (months(6) + days(1))
#> [1] "60m 10d 0H 0M 0S"
days(50) + hours(25) + minutes(2)
#> [1] "50d 25H 2M 0S"
阶段可以和日期相加
R
ymd("2016-01-01") + dyears(1)
#> [1] "2016-12-31"
ymd("2016-01-01") + years(1)
#> [1] "2017-01-01"
区间
区间是带有起点的时期,这使得其非常精确
R
next_year <- today() + years(1)
(today() %--% next_year) / ddays(1)
# > [1] 365
要想知道一个区间内有多少个阶段,需要使用整数除法:
R
(today() %--% next_year) %/% days(1)
# > [1] 365
purrr
可以使用purrr包在R中实现函数式编程。
map_xxx
for和while循环可以用map系列函数代替
- map() 用于输出列表;
- map_lgl() 用于输出逻辑型向量;
- map_int() 用于输出整型向量;
- map_dbl() 用于输出双精度型向量;
- map_chr() 用于输出字符型向量。
每个函数都使用一个向量作为输入,并对向量的每个元素应用一个函数,然后返回和输入向量同样长度(同样名称)的一个新向量。向量的类型由映射函数的后缀决定。
R
df <- tibble(
a=rnorm(10),
b=rnorm(10),
c=rnorm(10),
d=rnorm(10))
map(df,mean)
map_dbl(df,mean,trim=0.5) # 向 .f 传递一些附加参数,供其在每次调用时使用
pmap
先了解一下map2()函数:依次应用二元函数到两个序列的每对元素上
R
mu <- list(5, 10, -3)
sigma <- list(1, 5, 10)
map2(mu,sigma,rnorm,n=5)
#使用 map2() 函数,它可以对两个向量进行同步迭代
如果需要同时对3、4、5、...序列应用二元函数,可以用pmap来解决:应用多元函数到多个序列的每组元素上,可以实现对数据框逐行迭代。
R
n <- list(1, 3, 5)
args1 <- list(n, mu, sigma)
args1 %>%
pmap(rnorm) %>%
str()
R
# 同上
pmap(args1,rnorm) # n 是rnorm的参数
有一种更复杂的情况:不但传给函数的参数不同,甚至函数本身也是不同的,可以使用 invoke_map() 函数
R
f <- c("runif", "rnorm", "rpois")
param <- list(
list(min = -1, max = 1),
list(sd = 5),
list(lambda = 10)
)
invoke_map(f, param, n = 5) %>% str()
walk、pwalk
walk():对一个列表或向量中的每个元素应用函数,不返回任何值pwalk():对多个列表/向量的对应元素 同时应用函数,同样不返回结果,适用于多参数并行遍历
R
data_list <- list(mtcars = mtcars, iris = iris, ToothGrowth = ToothGrowth)
# 使用 walk 保存每个数据框为 CSV
walk(names(data_list), ~ write.csv(data_list[[.x]], file = paste0(.x, ".csv")))
R
files <- c("a.csv", "b.csv")
data <- list(mtcars[1:5, ], iris[1:5, ])
# 同时遍历 files 和 data,写入对应文件
pwalk(list(data, files), ~ write.csv(..1, file = ..2))
reduce
reduce() 函数使用一个"二元"函数(即具有两个基本输入的函数),将其不断应用于一个列表,直到最后只剩下一个元素为止。
R
vs <- list(
c(1, 3, 5, 6, 10),
c(1, 2, 3, 7, 8, 10),
c(1, 2, 3, 4, 8, 9, 10)
)
reduce(vs,sum)
# 93
错误处理
safely()
使用map系列函数操作数据时,有时一些操作的结果并不符合正确的数据类型(一个无效数据),可以使用 safely() 函数来安全地清除。
R
safe_log <- safely(log)
str(safe_log(10)) # 正常情况
ret = str(safe_log('a')) # 对一个字符进行对数计算,这时会产生NULL,而不是直接抛出异常
print(ret[["Result"]]) # NULL
quietly()
quietly() 函数与 safely() 的作用基本相同,但前者的结果中不包含错误对象,而是包含输出、消息和警告
R
ret = x %>% map(quietly(log)) %>%str()
# List of 2
# $ :List of 4
# ..$ result : num 0
# ..$ output : chr ""
# ..$ warnings: chr(0)
# ..$ messages: chr(0)
# $ :List of 4
# ..$ result : num NaN
# ..$ output : chr ""
# ..$ warnings: chr "产生了NaNs"
# ..$ messages: chr(0)
匿名函数(purrr 风格公式)
-
一元函数:序列参数是 .x
比如,f(x) = x^2 + 1, 其 purrr 风格公式(匿名函数)就写为:~ .x ^ 2 + 1
-
二元函数:序列参数是 .x, .y
比如,f(x, y) = x^2 - 3 y, 其 purrr 风格公式(匿名函数)就写为:~ .x ^ 2 - 3 * .y
-
多元函数:序列参数是 ...1, ...2, ...3, 等
比如,f(x, y, z) = ln(x + y + z), 其 purrr 风格公式(匿名函数)就写为:~ log(...1 + ...2 + ...3)
关于这个特殊的"."操作:
R
library(ggplot2)
plots <- mtcars %>%
split(.$cyl) %>%
map(~ggplot(., aes(mpg, wt)) + geom_point())
paths <- stringr::str_c(names(plots), ".pdf")
pwalk(list(paths, plots), ggsave, path = "D:\\")
在管道操作中,这个"."相当于data.frame
其它操作函数
- pluck():同
[]提取列表中的元素 - keep(): 保留满足条件的元素
- dicard(): 删除满足条件的元素
- compact(): 删除列表中的空元素
- append():在列表末尾增加元素
- flatten(): 摊平列表(只摊平一层)