install.packages("dplyr")
install.packages("lubridate")R语言数据管理:日期值、因子、排序与计算变量
1. 本节学习目标
在实际数据分析中,拿到原始数据后,通常不能直接画图或建模。
我们经常需要先对数据做一些整理,例如:
- 把字符型日期转换成真正的日期;
- 把分类变量转换成因子;
- 按某个变量排序;
- 根据已有变量计算新变量;
- 根据条件创建分类变量;
- 按组计算平均值、总和等。
本节主要学习以下内容:
- 日期值的基本处理;
- 因子的基本用法;
- 数据排序;
- 计算新变量;
- 条件变量;
- 简单分组汇总。
主要使用两个包:
dplyr
lubridate| 包 | 作用 |
|---|---|
dplyr |
数据整理,如排序、计算变量、分组汇总 |
lubridate |
日期处理 |
2. 加载包
如果没有安装,可以先运行:
加载包:
library(dplyr)
library(lubridate)3. 创建示例数据
先创建一份简单的销售数据。
sales <- data.frame(
id = 1:8,
date = c(
"2024-01-05", "2024-01-12", "2024-02-03", "2024-02-20",
"2024-03-01", "2024-03-15", "2024-04-02", "2024-04-18"
),
region = c("华东", "华北", "华南", "华东", "华北", "华南", "华东", "华北"),
category = c("食品", "服装", "电子", "食品", "服装", "电子", "食品", "服装"),
price = c(20, 150, 3000, 35, 180, 2500, 28, 220),
quantity = c(5, 2, 1, 6, 3, 1, 4, 2)
)
sales id date region category price quantity
1 1 2024-01-05 华东 食品 20 5
2 2 2024-01-12 华北 服装 150 2
3 3 2024-02-03 华南 电子 3000 1
4 4 2024-02-20 华东 食品 35 6
5 5 2024-03-01 华北 服装 180 3
6 6 2024-03-15 华南 电子 2500 1
7 7 2024-04-02 华东 食品 28 4
8 8 2024-04-18 华北 服装 220 2
查看数据结构:
str(sales)'data.frame': 8 obs. of 6 variables:
$ id : int 1 2 3 4 5 6 7 8
$ date : chr "2024-01-05" "2024-01-12" "2024-02-03" "2024-02-20" ...
$ region : chr "华东" "华北" "华南" "华东" ...
$ category: chr "食品" "服装" "电子" "食品" ...
$ price : num 20 150 3000 35 180 2500 28 220
$ quantity: num 5 2 1 6 3 1 4 2
可以看到:
date现在是字符型;region和category也是字符型;price和quantity是数值型。
4. 日期值基础
4.1 什么是日期值?
日期看起来像普通文字,例如:
"2024-01-05"但在数据分析中,我们希望 R 把它识别成真正的日期。
只有这样,才能进行日期计算,例如:
- 提取年份;
- 提取月份;
- 计算两个日期相差多少天;
- 筛选某个时间段的数据。
4.2 日期格式符号基础
在 R 中,日期通常由“年、月、日”组成。
但是不同数据中的日期写法可能不一样,例如:
"2024-03-01"
"2024/03/01"
"03/01/2024"
"01-03-24"R 需要知道这些数字分别代表什么,才能正确转换成日期。
常用日期格式符号如下:
| 格式符号 | 含义 | 示例 |
|---|---|---|
%Y |
四位年份 | 2024 |
%y |
两位年份 | 24 |
%m |
两位月份 | 03 |
%d |
两位日期 | 01 |
%B |
完整月份名称 | March |
%b |
缩写月份名称 | Mar |
%A |
完整星期名称 | Friday |
%a |
缩写星期名称 | Fri |
其中,最常用的是:
%Y
%y
%m
%d4.3 %Y 和 %y 的区别
%Y 表示四位年份。
as.Date("2024-03-01", format = "%Y-%m-%d")[1] "2024-03-01"
这里:
"2024-03-01"对应:
"%Y-%m-%d"意思是:
| 数据中的部分 | 对应格式 |
|---|---|
2024 |
%Y |
03 |
%m |
01 |
%d |
所以:
%Y = 四位年份例如:
2024
1998
2010%y 表示两位年份。
as.Date("24-03-01", format = "%y-%m-%d")[1] "2024-03-01"
这里:
"24-03-01"对应:
"%y-%m-%d"意思是:
| 数据中的部分 | 对应格式 |
|---|---|
24 |
%y |
03 |
%m |
01 |
%d |
所以:
%y = 两位年份例如:
24
98
10简单记忆:
| 符号 | 含义 |
|---|---|
%Y |
大写 Y,四位年份 |
%y |
小写 y,两位年份 |
4.4 as.Date() 中的 format 参数
as.Date() 可以把字符转换成日期。
基本形式是:
as.Date(日期字符, format = "日期格式")例如:
as.Date("2024-03-01", format = "%Y-%m-%d")[1] "2024-03-01"
如果日期中间用 / 分隔,那么格式也要写成 /。
as.Date("2024/03/01", format = "%Y/%m/%d")[1] "2024-03-01"
如果日期顺序是“月/日/年”,例如:
"03/01/2024"表示 2024 年 3 月 1 日,那么应该写:
as.Date("03/01/2024", format = "%m/%d/%Y")[1] "2024-03-01"
如果日期顺序是“日/月/年”,例如:
"01/03/2024"表示 2024 年 3 月 1 日,那么应该写:
as.Date("01/03/2024", format = "%d/%m/%Y")[1] "2024-03-01"
注意:
"03/01/2024"可能表示:
- 2024 年 3 月 1 日;
- 也可能表示 2024 年 1 月 3 日。
所以一定要先弄清楚原始数据中的日期顺序。
4.5 format() 函数:改变日期显示格式
as.Date() 是把字符转换成日期。
format() 是把日期按照指定格式显示出来。
先创建一个日期:
date1 <- as.Date("2024-03-01")
date1[1] "2024-03-01"
把日期显示成“年/月/日”:
format(date1, "%Y/%m/%d")[1] "2024/03/01"
显示成“月-日-年”:
format(date1, "%m-%d-%Y")[1] "03-01-2024"
显示成年份:
format(date1, "%Y")[1] "2024"
显示成月份:
format(date1, "%m")[1] "03"
显示成“年-月”:
format(date1, "%Y-%m")[1] "2024-03"
显示成带中文的格式:
format(date1, "%Y年%m月%d日")[1] "2024年03月01日"
结果是:
"2024年03月01日"4.6 as.Date() 和 format() 的区别
很多初学者容易混淆 as.Date() 和 format()。
| 函数 | 作用 | 结果类型 |
|---|---|---|
as.Date() |
把字符转换成日期 | Date 类型 |
format() |
把日期显示成指定样式 | 字符型 |
例如:
date2 <- as.Date("2024-03-01", format = "%Y-%m-%d")
date2[1] "2024-03-01"
class(date2)[1] "Date"
可以看到,date2 是 Date 类型。
再使用 format():
date3 <- format(date2, "%Y年%m月%d日")
date3[1] "2024年03月01日"
class(date3)[1] "character"
可以看到,date3 变成了字符型。
所以要注意:
format()主要用于改变显示格式,不适合继续做日期计算。
如果后面还要进行日期计算,建议保留 Date 类型。
4.7 常见日期格式示例
下面是一些常见写法。
as.Date("2024-03-01", format = "%Y-%m-%d")[1] "2024-03-01"
as.Date("2024/03/01", format = "%Y/%m/%d")[1] "2024-03-01"
as.Date("03/01/2024", format = "%m/%d/%Y")[1] "2024-03-01"
as.Date("01/03/2024", format = "%d/%m/%Y")[1] "2024-03-01"
as.Date("24-03-01", format = "%y-%m-%d")[1] "2024-03-01"
对应关系如下:
| 原始日期 | 格式写法 | 含义 |
|---|---|---|
"2024-03-01" |
"%Y-%m-%d" |
年-月-日 |
"2024/03/01" |
"%Y/%m/%d" |
年/月/日 |
"03/01/2024" |
"%m/%d/%Y" |
月/日/年 |
"01/03/2024" |
"%d/%m/%Y" |
日/月/年 |
"24-03-01" |
"%y-%m-%d" |
两位年-月-日 |
4.8 在数据框中使用日期格式
假设数据中的日期是字符型。
df_date <- data.frame(
id = 1:4,
date = c("2024-03-01", "2024-03-02", "2024-03-03", "2024-03-04")
)
df_date id date
1 1 2024-03-01
2 2 2024-03-02
3 3 2024-03-03
4 4 2024-03-04
str(df_date)'data.frame': 4 obs. of 2 variables:
$ id : int 1 2 3 4
$ date: chr "2024-03-01" "2024-03-02" "2024-03-03" "2024-03-04"
把 date 转换为日期型:
df_date <- df_date %>%
mutate(
date = as.Date(date, format = "%Y-%m-%d")
)
df_date id date
1 1 2024-03-01
2 2 2024-03-02
3 3 2024-03-03
4 4 2024-03-04
str(df_date)'data.frame': 4 obs. of 2 variables:
$ id : int 1 2 3 4
$ date: Date, format: "2024-03-01" "2024-03-02" ...
如果想生成一个“年月”变量,可以使用 format():
df_date <- df_date %>%
mutate(
year_month = format(date, "%Y-%m")
)
df_date id date year_month
1 1 2024-03-01 2024-03
2 2 2024-03-02 2024-03
3 3 2024-03-03 2024-03
4 4 2024-03-04 2024-03
这里的 year_month 是字符型,适合用于分组统计或标签显示。
例如按年月计数:
df_date %>%
group_by(year_month) %>%
summarise(
count = n(),
.groups = "drop"
)# A tibble: 1 × 2
year_month count
<chr> <int>
1 2024-03 4
5. 因子基础
5.1 什么是因子?
因子是 R 中专门用来表示分类变量的数据类型。
例如:
- 地区:华东、华北、华南;
- 类别:食品、服装、电子;
- 等级:低、中、高;
- 性别:男、女。
简单来说:
因子就是有类别的数据。
5.2 字符变量转为因子
把 region 和 category 转换为因子。
sales <- sales %>%
mutate(
region = factor(region),
category = factor(category)
)
str(sales)'data.frame': 8 obs. of 6 variables:
$ id : int 1 2 3 4 5 6 7 8
$ date : chr "2024-01-05" "2024-01-12" "2024-02-03" "2024-02-20" ...
$ region : Factor w/ 3 levels "华北","华东",..: 2 1 3 2 1 3 2 1
$ category: Factor w/ 3 levels "电子","服装",..: 3 2 1 3 2 1 3 2
$ price : num 20 150 3000 35 180 2500 28 220
$ quantity: num 5 2 1 6 3 1 4 2
查看因子的类别:
levels(sales$region)[1] "华北" "华东" "华南"
levels(sales$category)[1] "电子" "服装" "食品"
5.3 设置因子的显示顺序
有时候我们希望分类变量按照指定顺序显示。
例如地区按照:
华东、华北、华南显示。
sales <- sales %>%
mutate(
region = factor(
region,
levels = c("华东", "华北", "华南")
)
)
levels(sales$region)[1] "华东" "华北" "华南"
因子的顺序会影响表格、绘图和模型中的显示顺序。
5.4 有序因子
有些分类变量本身有顺序,例如:
低、中、高这种变量可以设置成有序因子。
下面根据价格创建价格等级。
sales <- sales %>%
mutate(
price_level = case_when(
price < 100 ~ "低价",
price < 1000 ~ "中价",
TRUE ~ "高价"
),
price_level = factor(
price_level,
levels = c("低价", "中价", "高价"),
ordered = TRUE
)
)
sales id date region category price quantity price_level
1 1 2024-01-05 华东 食品 20 5 低价
2 2 2024-01-12 华北 服装 150 2 中价
3 3 2024-02-03 华南 电子 3000 1 高价
4 4 2024-02-20 华东 食品 35 6 低价
5 5 2024-03-01 华北 服装 180 3 中价
6 6 2024-03-15 华南 电子 2500 1 高价
7 7 2024-04-02 华东 食品 28 4 低价
8 8 2024-04-18 华北 服装 220 2 中价
解释:
case_when()用来根据条件创建分类变量;factor(..., ordered = TRUE)表示这是有顺序的因子。
6. 数据排序基础
6.1 按一个变量升序排序
使用 arrange() 可以排序。
例如,按照价格从小到大排序:
sales %>%
arrange(price) id date region category price quantity price_level
1 1 2024-01-05 华东 食品 20 5 低价
2 7 2024-04-02 华东 食品 28 4 低价
3 4 2024-02-20 华东 食品 35 6 低价
4 2 2024-01-12 华北 服装 150 2 中价
5 5 2024-03-01 华北 服装 180 3 中价
6 8 2024-04-18 华北 服装 220 2 中价
7 6 2024-03-15 华南 电子 2500 1 高价
8 3 2024-02-03 华南 电子 3000 1 高价
6.2 按一个变量降序排序
如果想从大到小排序,可以使用 desc()。
sales %>%
arrange(desc(price)) id date region category price quantity price_level
1 3 2024-02-03 华南 电子 3000 1 高价
2 6 2024-03-15 华南 电子 2500 1 高价
3 8 2024-04-18 华北 服装 220 2 中价
4 5 2024-03-01 华北 服装 180 3 中价
5 2 2024-01-12 华北 服装 150 2 中价
6 4 2024-02-20 华东 食品 35 6 低价
7 7 2024-04-02 华东 食品 28 4 低价
8 1 2024-01-05 华东 食品 20 5 低价
6.3 按多个变量排序
例如先按地区排序,再按价格从高到低排序。
sales %>%
arrange(region, desc(price)) id date region category price quantity price_level
1 4 2024-02-20 华东 食品 35 6 低价
2 7 2024-04-02 华东 食品 28 4 低价
3 1 2024-01-05 华东 食品 20 5 低价
4 8 2024-04-18 华北 服装 220 2 中价
5 5 2024-03-01 华北 服装 180 3 中价
6 2 2024-01-12 华北 服装 150 2 中价
7 3 2024-02-03 华南 电子 3000 1 高价
8 6 2024-03-15 华南 电子 2500 1 高价
解释:
- 先按照
region排序; - 同一个地区内部,再按照
price从大到小排序。
7. 计算变量
7.1 什么是计算变量?
计算变量就是根据已有变量生成新变量。
例如已有:
- 单价
price; - 数量
quantity。
可以计算:
销售额 = 单价 × 数量7.2 使用 mutate() 创建新变量
sales <- sales %>%
mutate(
amount = price * quantity
)
sales id date region category price quantity price_level amount
1 1 2024-01-05 华东 食品 20 5 低价 100
2 2 2024-01-12 华北 服装 150 2 中价 300
3 3 2024-02-03 华南 电子 3000 1 高价 3000
4 4 2024-02-20 华东 食品 35 6 低价 210
5 5 2024-03-01 华北 服装 180 3 中价 540
6 6 2024-03-15 华南 电子 2500 1 高价 2500
7 7 2024-04-02 华东 食品 28 4 低价 112
8 8 2024-04-18 华北 服装 220 2 中价 440
这里:
amount = price * quantity表示新建一个变量 amount,它等于单价乘以数量。
7.3 一次创建多个新变量
例如继续计算折扣后金额。
sales <- sales %>%
mutate(
amount = price * quantity,
discount_amount = amount * 0.9
)
sales id date region category price quantity price_level amount
1 1 2024-01-05 华东 食品 20 5 低价 100
2 2 2024-01-12 华北 服装 150 2 中价 300
3 3 2024-02-03 华南 电子 3000 1 高价 3000
4 4 2024-02-20 华东 食品 35 6 低价 210
5 5 2024-03-01 华北 服装 180 3 中价 540
6 6 2024-03-15 华南 电子 2500 1 高价 2500
7 7 2024-04-02 华东 食品 28 4 低价 112
8 8 2024-04-18 华北 服装 220 2 中价 440
discount_amount
1 90.0
2 270.0
3 2700.0
4 189.0
5 486.0
6 2250.0
7 100.8
8 396.0
解释:
amount是原始销售额;discount_amount是打 9 折后的销售额。
8. 条件变量
8.1 使用 ifelse() 创建二分类变量
如果只有两个类别,可以使用 ifelse()。
例如,根据销售额判断是否为大订单。
sales <- sales %>%
mutate(
big_order = ifelse(amount >= 1000, "大订单", "普通订单")
)
sales id date region category price quantity price_level amount
1 1 2024-01-05 华东 食品 20 5 低价 100
2 2 2024-01-12 华北 服装 150 2 中价 300
3 3 2024-02-03 华南 电子 3000 1 高价 3000
4 4 2024-02-20 华东 食品 35 6 低价 210
5 5 2024-03-01 华北 服装 180 3 中价 540
6 6 2024-03-15 华南 电子 2500 1 高价 2500
7 7 2024-04-02 华东 食品 28 4 低价 112
8 8 2024-04-18 华北 服装 220 2 中价 440
discount_amount big_order
1 90.0 普通订单
2 270.0 普通订单
3 2700.0 大订单
4 189.0 普通订单
5 486.0 普通订单
6 2250.0 大订单
7 100.8 普通订单
8 396.0 普通订单
解释:
ifelse(条件, 条件成立时的结果, 条件不成立时的结果)8.2 使用 case_when() 创建多分类变量
如果有多个条件,推荐使用 case_when()。
例如,把销售额分成低、中、高三类。
sales <- sales %>%
mutate(
amount_level = case_when(
amount < 500 ~ "低销售额",
amount < 2000 ~ "中销售额",
TRUE ~ "高销售额"
)
)
sales id date region category price quantity price_level amount
1 1 2024-01-05 华东 食品 20 5 低价 100
2 2 2024-01-12 华北 服装 150 2 中价 300
3 3 2024-02-03 华南 电子 3000 1 高价 3000
4 4 2024-02-20 华东 食品 35 6 低价 210
5 5 2024-03-01 华北 服装 180 3 中价 540
6 6 2024-03-15 华南 电子 2500 1 高价 2500
7 7 2024-04-02 华东 食品 28 4 低价 112
8 8 2024-04-18 华北 服装 220 2 中价 440
discount_amount big_order amount_level
1 90.0 普通订单 低销售额
2 270.0 普通订单 低销售额
3 2700.0 大订单 高销售额
4 189.0 普通订单 低销售额
5 486.0 普通订单 中销售额
6 2250.0 大订单 高销售额
7 100.8 普通订单 低销售额
8 396.0 普通订单 低销售额
解释:
amount < 500 ~ "低销售额"表示销售额小于 500;amount < 2000 ~ "中销售额"表示销售额小于 2000;TRUE ~ "高销售额"表示其他情况。
注意:
case_when() 会按照从上到下的顺序判断条件。
9. 分组汇总入门
9.1 什么是分组汇总?
分组汇总就是按照某个分类变量分组,然后计算每组的统计量。
例如:
- 每个地区的总销售额;
- 每个类别的平均价格;
- 每个地区有多少订单。
9.2 按地区计算总销售额
sales %>%
group_by(region) %>%
summarise(
total_amount = sum(amount),
.groups = "drop"
)# A tibble: 3 × 2
region total_amount
<fct> <dbl>
1 华东 422
2 华北 1280
3 华南 5500
解释:
group_by(region)表示按地区分组;sum(amount)表示计算每个地区的销售额总和;.groups = "drop"表示汇总后取消分组。
9.3 按地区计算订单数和平均销售额
sales %>%
group_by(region) %>%
summarise(
order_count = n(),
avg_amount = mean(amount),
.groups = "drop"
)# A tibble: 3 × 3
region order_count avg_amount
<fct> <int> <dbl>
1 华东 3 141.
2 华北 3 427.
3 华南 2 2750
解释:
| 函数 | 作用 |
|---|---|
n() |
计算每组有多少行 |
mean() |
计算平均值 |
sum() |
计算总和 |
max() |
计算最大值 |
min() |
计算最小值 |
10. 本节核心函数总结
本节最常用函数如下:
| 函数 | 作用 |
|---|---|
ymd() |
把字符转换成日期 |
year() |
提取年份 |
month() |
提取月份 |
day() |
提取日期中的日 |
wday() |
提取星期 |
factor() |
创建因子 |
levels() |
查看因子水平 |
arrange() |
排序 |
desc() |
降序 |
mutate() |
创建或修改变量 |
ifelse() |
创建二分类变量 |
case_when() |
创建多分类变量 |
group_by() |
分组 |
summarise() |
汇总 |
常用模板:
# 日期转换
df$date <- ymd(df$date)
# 提取月份
df <- df %>%
mutate(month = month(date))
# 创建因子
df <- df %>%
mutate(group = factor(group))
# 设置因子顺序
df <- df %>%
mutate(
level = factor(
level,
levels = c("低", "中", "高"),
ordered = TRUE
)
)
# 排序
df %>%
arrange(desc(x))
# 计算新变量
df <- df %>%
mutate(new_var = x + y)
# 条件变量
df <- df %>%
mutate(
level = case_when(
score >= 90 ~ "优秀",
score >= 80 ~ "良好",
TRUE ~ "继续努力"
)
)
# 分组汇总
df %>%
group_by(group) %>%
summarise(
avg_x = mean(x),
total_x = sum(x),
n = n(),
.groups = "drop"
)11. 小练习
下面只保留一个简单练习。
创建学生成绩数据:
student <- data.frame(
id = 1:6,
name = c("张三", "李四", "王五", "赵六", "钱七", "孙八"),
class = c("一班", "二班", "一班", "三班", "二班", "三班"),
exam_date = c(
"2024-03-01", "2024-03-01", "2024-03-02",
"2024-03-02", "2024-03-03", "2024-03-03"
),
chinese = c(88, 76, 92, 85, 79, 90),
math = c(90, 82, 88, 91, 75, 86),
english = c(85, 78, 94, 87, 81, 89)
)
student id name class exam_date chinese math english
1 1 张三 一班 2024-03-01 88 90 85
2 2 李四 二班 2024-03-01 76 82 78
3 3 王五 一班 2024-03-02 92 88 94
4 4 赵六 三班 2024-03-02 85 91 87
5 5 钱七 二班 2024-03-03 79 75 81
6 6 孙八 三班 2024-03-03 90 86 89
请完成:
- 把
exam_date转换成日期; - 提取考试月份;
- 把
class转换为因子,并设置顺序为一班、二班、三班; - 计算总分
total和平均分average; - 按平均分从高到低排序;
- 按班级计算平均分。
12. 小练习参考答案
student <- student %>%
mutate(
exam_date = ymd(exam_date),
exam_month = month(exam_date),
class = factor(
class,
levels = c("一班", "二班", "三班")
),
total = chinese + math + english,
average = round(total / 3, 1)
)
student id name class exam_date chinese math english exam_month total average
1 1 张三 一班 2024-03-01 88 90 85 3 263 87.7
2 2 李四 二班 2024-03-01 76 82 78 3 236 78.7
3 3 王五 一班 2024-03-02 92 88 94 3 274 91.3
4 4 赵六 三班 2024-03-02 85 91 87 3 263 87.7
5 5 钱七 二班 2024-03-03 79 75 81 3 235 78.3
6 6 孙八 三班 2024-03-03 90 86 89 3 265 88.3
按平均分从高到低排序:
student %>%
arrange(desc(average)) id name class exam_date chinese math english exam_month total average
1 3 王五 一班 2024-03-02 92 88 94 3 274 91.3
2 6 孙八 三班 2024-03-03 90 86 89 3 265 88.3
3 1 张三 一班 2024-03-01 88 90 85 3 263 87.7
4 4 赵六 三班 2024-03-02 85 91 87 3 263 87.7
5 2 李四 二班 2024-03-01 76 82 78 3 236 78.7
6 5 钱七 二班 2024-03-03 79 75 81 3 235 78.3
按班级计算平均分:
student %>%
group_by(class) %>%
summarise(
avg_score = mean(average),
student_count = n(),
.groups = "drop"
)# A tibble: 3 × 3
class avg_score student_count
<fct> <dbl> <int>
1 一班 89.5 2
2 二班 78.5 2
3 三班 88 2
13. 一句话总结
本节可以记住下面这几个函数:
ymd()
factor()
arrange()
mutate()
case_when()
group_by()
summarise()其中:
ymd()用来处理日期;factor()用来处理分类变量;arrange()用来排序;mutate()用来计算新变量;case_when()用来根据条件分类;group_by()和summarise()用来分组汇总。