在R语言中,日期通常使用 Date 类型表示。
很多时候,我们看到的数据像日期:
2024-01-05
但它可能只是字符型,也就是 character。
所以处理日期的第一步通常是:
先把字符型日期转换成真正的日期型。
df <- data.frame(
id = 1:6,
name = c("A", "B", "C", "D", "E", "F"),
date = c("2024-01-05", "2024-01-12", "2024-02-03",
"2024-02-20", "2024-03-01", "2024-03-15"),
sales = c(100, 120, 90, 150, 200, 180)
)
df
## id name date sales
## 1 1 A 2024-01-05 100
## 2 2 B 2024-01-12 120
## 3 3 C 2024-02-03 90
## 4 4 D 2024-02-20 150
## 5 5 E 2024-03-01 200
## 6 6 F 2024-03-15 180
运行后你会看到类似结果:
id name date sales
1 1 A 2024-01-05 100
2 2 B 2024-01-12 120
3 3 C 2024-02-03 90
4 4 D 2024-02-20 150
5 5 E 2024-03-01 200
6 6 F 2024-03-15 180
str(df)
## 'data.frame': 6 obs. of 4 variables:
## $ id : int 1 2 3 4 5 6
## $ name : chr "A" "B" "C" "D" ...
## $ date : chr "2024-01-05" "2024-01-12" "2024-02-03" "2024-02-20" ...
## $ sales: num 100 120 90 150 200 180
你会看到 date 这一列大概率是:
date: chr
这说明它现在是字符型,不是真正的日期型。
如果日期格式是标准格式:
年-月-日
2024-01-05
可以直接使用:
df$date <- as.Date(df$date)
df
## id name date sales
## 1 1 A 2024-01-05 100
## 2 2 B 2024-01-12 120
## 3 3 C 2024-02-03 90
## 4 4 D 2024-02-20 150
## 5 5 E 2024-03-01 200
## 6 6 F 2024-03-15 180
再次查看数据结构:
str(df)
## 'data.frame': 6 obs. of 4 variables:
## $ id : int 1 2 3 4 5 6
## $ name : chr "A" "B" "C" "D" ...
## $ date : Date, format: "2024-01-05" "2024-01-12" ...
## $ sales: num 100 120 90 150 200 180
这时你应该会看到:
date: Date
说明转换成功。
因为只有真正的日期型,才方便:
有时候日期不是 2024-01-05,而是其他格式。
date1 <- "2024/01/05"
as.Date(date1, format = "%Y/%m/%d")
## [1] "2024-01-05"
输出结果类似:
[1] "2024-01-05"
比如:
05/01/2024
如果它表示的是 2024年1月5日,那么格式应该写:
date2 <- "05/01/2024"
as.Date(date2, format = "%d/%m/%Y")
## [1] "2024-01-05"
如果:
01/05/2024
表示的是 2024年1月5日,也就是“月/日/年”,应该写:
date3 <- "01/05/2024"
as.Date(date3, format = "%m/%d/%Y")
## [1] "2024-01-05"
| 符号 | 含义 | 示例 |
|---|---|---|
%Y |
四位年份 | 2024 |
%y |
两位年份 | 24 |
%m |
两位月份 | 01 |
%d |
两位日期 | 05 |
%B |
英文完整月份 | January |
%b |
英文缩写月份 | Jan |
例如:
as.Date("2024年01月05日", format = "%Y年%m月%d日")
## [1] "2024-01-05"
现在我们的 df$date 已经是日期型。
df$year <- format(df$date, "%Y")
df$month <- format(df$date, "%m")
df$day <- format(df$date, "%d")
df
## id name date sales year month day
## 1 1 A 2024-01-05 100 2024 01 05
## 2 2 B 2024-01-12 120 2024 01 12
## 3 3 C 2024-02-03 90 2024 02 03
## 4 4 D 2024-02-20 150 2024 02 20
## 5 5 E 2024-03-01 200 2024 03 01
## 6 6 F 2024-03-15 180 2024 03 15
输出结果类似:
id name date sales year month day
1 1 A 2024-01-05 100 2024 01 05
2 2 B 2024-01-12 120 2024 01 12
3 3 C 2024-02-03 90 2024 02 03
4 4 D 2024-02-20 150 2024 02 20
5 5 E 2024-03-01 200 2024 03 01
6 6 F 2024-03-15 180 2024 03 15
注意:
format() 提取出来的结果通常是字符型。
可以检查:
str(df)
## 'data.frame': 6 obs. of 7 variables:
## $ id : int 1 2 3 4 5 6
## $ name : chr "A" "B" "C" "D" ...
## $ date : Date, format: "2024-01-05" "2024-01-12" ...
## $ sales: num 100 120 90 150 200 180
## $ year : chr "2024" "2024" "2024" "2024" ...
## $ month: chr "01" "01" "02" "02" ...
## $ day : chr "05" "12" "03" "20" ...
如果想把月份变成数值型:
df$month_num <- as.numeric(format(df$date, "%m"))
df
## id name date sales year month day month_num
## 1 1 A 2024-01-05 100 2024 01 05 1
## 2 2 B 2024-01-12 120 2024 01 12 1
## 3 3 C 2024-02-03 90 2024 02 03 2
## 4 4 D 2024-02-20 150 2024 02 20 2
## 5 5 E 2024-03-01 200 2024 03 01 3
## 6 6 F 2024-03-15 180 2024 03 15 3
在实际考试中,经常需要按月份汇总数据。
这时可以创建一列 year_month。
df$year_month <- format(df$date, "%Y-%m")
df
## id name date sales year month day month_num year_month
## 1 1 A 2024-01-05 100 2024 01 05 1 2024-01
## 2 2 B 2024-01-12 120 2024 01 12 1 2024-01
## 3 3 C 2024-02-03 90 2024 02 03 2 2024-02
## 4 4 D 2024-02-20 150 2024 02 20 2 2024-02
## 5 5 E 2024-03-01 200 2024 03 01 3 2024-03
## 6 6 F 2024-03-15 180 2024 03 15 3 2024-03
输出结果类似:
id name date sales year month day month_num year_month
1 1 A 2024-01-05 100 2024 01 05 1 2024-01
2 2 B 2024-01-12 120 2024 01 12 1 2024-01
3 3 C 2024-02-03 90 2024 02 03 2 2024-02
4 4 D 2024-02-20 150 2024 02 20 2 2024-02
5 5 E 2024-03-01 200 2024 03 01 3 2024-03
6 6 F 2024-03-15 180 2024 03 15 3 2024-03
df$weekday <- weekdays(df$date)
df
## id name date sales year month day month_num year_month weekday
## 1 1 A 2024-01-05 100 2024 01 05 1 2024-01 星期五
## 2 2 B 2024-01-12 120 2024 01 12 1 2024-01 星期五
## 3 3 C 2024-02-03 90 2024 02 03 2 2024-02 星期六
## 4 4 D 2024-02-20 150 2024 02 20 2 2024-02 星期二
## 5 5 E 2024-03-01 200 2024 03 01 3 2024-03 星期五
## 6 6 F 2024-03-15 180 2024 03 15 3 2024-03 星期五
输出可能是中文:
星期五
星期一
也可能是英文:
Friday
Monday
这取决于你的电脑语言环境。
如果想得到星期数字,可以用:
df$weekday_num <- as.numeric(format(df$date, "%u"))
df
## id name date sales year month day month_num year_month weekday
## 1 1 A 2024-01-05 100 2024 01 05 1 2024-01 星期五
## 2 2 B 2024-01-12 120 2024 01 12 1 2024-01 星期五
## 3 3 C 2024-02-03 90 2024 02 03 2 2024-02 星期六
## 4 4 D 2024-02-20 150 2024 02 20 2 2024-02 星期二
## 5 5 E 2024-03-01 200 2024 03 01 3 2024-03 星期五
## 6 6 F 2024-03-15 180 2024 03 15 3 2024-03 星期五
## weekday_num
## 1 5
## 2 5
## 3 6
## 4 2
## 5 5
## 6 5
其中:
| 数字 | 含义 |
|---|---|
| 1 | 星期一 |
| 2 | 星期二 |
| 3 | 星期三 |
| 4 | 星期四 |
| 5 | 星期五 |
| 6 | 星期六 |
| 7 | 星期日 |
比如我们想计算每一行日期距离最早日期过了多少天。
df$days_from_start <- df$date - min(df$date)
df
## id name date sales year month day month_num year_month weekday
## 1 1 A 2024-01-05 100 2024 01 05 1 2024-01 星期五
## 2 2 B 2024-01-12 120 2024 01 12 1 2024-01 星期五
## 3 3 C 2024-02-03 90 2024 02 03 2 2024-02 星期六
## 4 4 D 2024-02-20 150 2024 02 20 2 2024-02 星期二
## 5 5 E 2024-03-01 200 2024 03 01 3 2024-03 星期五
## 6 6 F 2024-03-15 180 2024 03 15 3 2024-03 星期五
## weekday_num days_from_start
## 1 5 0 days
## 2 5 7 days
## 3 6 29 days
## 4 2 46 days
## 5 5 56 days
## 6 5 70 days
此时 days_from_start 是一个日期差对象。
如果想转为普通数字:
df$days_from_start <- as.numeric(df$date - min(df$date))
df
## id name date sales year month day month_num year_month weekday
## 1 1 A 2024-01-05 100 2024 01 05 1 2024-01 星期五
## 2 2 B 2024-01-12 120 2024 01 12 1 2024-01 星期五
## 3 3 C 2024-02-03 90 2024 02 03 2 2024-02 星期六
## 4 4 D 2024-02-20 150 2024 02 20 2 2024-02 星期二
## 5 5 E 2024-03-01 200 2024 03 01 3 2024-03 星期五
## 6 6 F 2024-03-15 180 2024 03 15 3 2024-03 星期五
## weekday_num days_from_start
## 1 5 0
## 2 5 7
## 3 6 29
## 4 2 46
## 5 5 56
## 6 5 70
输出结果类似:
id name date sales year month day month_num year_month weekday weekday_num days_from_start
1 1 A 2024-01-05 100 2024 01 05 1 2024-01 星期五 5 0
2 2 B 2024-01-12 120 2024 01 12 1 2024-01 星期五 5 7
3 3 C 2024-02-03 90 2024 02 03 2 2024-02 星期六 6 29
4 4 D 2024-02-20 150 2024 02 20 2 2024-02 星期二 2 46
5 5 E 2024-03-01 200 2024 03 01 3 2024-03 星期五 5 56
6 6 F 2024-03-15 180 2024 03 15 3 2024-03 星期五 5 70
重新创建一个活动数据框。
activity <- data.frame(
id = 1:4,
activity = c("活动A", "活动B", "活动C", "活动D"),
start_date = c("2024-01-01", "2024-02-10", "2024-03-05", "2024-04-01"),
end_date = c("2024-01-10", "2024-02-18", "2024-03-20", "2024-04-12")
)
activity
## id activity start_date end_date
## 1 1 活动A 2024-01-01 2024-01-10
## 2 2 活动B 2024-02-10 2024-02-18
## 3 3 活动C 2024-03-05 2024-03-20
## 4 4 活动D 2024-04-01 2024-04-12
查看类型:
str(activity)
## 'data.frame': 4 obs. of 4 variables:
## $ id : int 1 2 3 4
## $ activity : chr "活动A" "活动B" "活动C" "活动D"
## $ start_date: chr "2024-01-01" "2024-02-10" "2024-03-05" "2024-04-01"
## $ end_date : chr "2024-01-10" "2024-02-18" "2024-03-20" "2024-04-12"
把两个日期列都转换成日期型:
activity$start_date <- as.Date(activity$start_date)
activity$end_date <- as.Date(activity$end_date)
str(activity)
## 'data.frame': 4 obs. of 4 variables:
## $ id : int 1 2 3 4
## $ activity : chr "活动A" "活动B" "活动C" "活动D"
## $ start_date: Date, format: "2024-01-01" "2024-02-10" ...
## $ end_date : Date, format: "2024-01-10" "2024-02-18" ...
计算持续天数:
activity$duration <- as.numeric(activity$end_date - activity$start_date)
activity
## id activity start_date end_date duration
## 1 1 活动A 2024-01-01 2024-01-10 9
## 2 2 活动B 2024-02-10 2024-02-18 8
## 3 3 活动C 2024-03-05 2024-03-20 15
## 4 4 活动D 2024-04-01 2024-04-12 11
输出结果类似:
id activity start_date end_date duration
1 1 活动A 2024-01-01 2024-01-10 9
2 2 活动B 2024-02-10 2024-02-18 8
3 3 活动C 2024-03-05 2024-03-20 15
4 4 活动D 2024-04-01 2024-04-12 11
注意:
2024-01-10 减去 2024-01-01 的结果是 9。
如果题目认为包含开始当天和结束当天,可能要加 1:
activity$duration_include_start <- activity$duration + 1
activity
## id activity start_date end_date duration duration_include_start
## 1 1 活动A 2024-01-01 2024-01-10 9 10
## 2 2 活动B 2024-02-10 2024-02-18 8 9
## 3 3 活动C 2024-03-05 2024-03-20 15 16
## 4 4 活动D 2024-04-01 2024-04-12 11 12
df_after_feb <- df[df$date >= as.Date("2024-02-01"), ]
df_after_feb
## id name date sales year month day month_num year_month weekday
## 3 3 C 2024-02-03 90 2024 02 03 2 2024-02 星期六
## 4 4 D 2024-02-20 150 2024 02 20 2 2024-02 星期二
## 5 5 E 2024-03-01 200 2024 03 01 3 2024-03 星期五
## 6 6 F 2024-03-15 180 2024 03 15 3 2024-03 星期五
## weekday_num days_from_start
## 3 6 29
## 4 2 46
## 5 5 56
## 6 5 70
df_feb <- df[df$date >= as.Date("2024-02-01") &
df$date <= as.Date("2024-02-29"), ]
df_feb
## id name date sales year month day month_num year_month weekday
## 3 3 C 2024-02-03 90 2024 02 03 2 2024-02 星期六
## 4 4 D 2024-02-20 150 2024 02 20 2 2024-02 星期二
## weekday_num days_from_start
## 3 6 29
## 4 2 46
输出结果类似:
id name date sales year month day month_num year_month weekday weekday_num days_from_start
3 3 C 2024-02-03 90 2024 02 03 2 2024-02 星期六 6 29
4 4 D 2024-02-20 150 2024 02 20 2 2024-02 星期二 2 46
monthly_sales <- aggregate(sales ~ year_month, data = df, sum)
monthly_sales
## year_month sales
## 1 2024-01 220
## 2 2024-02 240
## 3 2024-03 380
输出结果类似:
year_month sales
1 2024-01 220
2 2024-02 240
3 2024-03 380
解释:
monthly_mean_sales <- aggregate(sales ~ year_month, data = df, mean)
monthly_mean_sales
## year_month sales
## 1 2024-01 110
## 2 2024-02 120
## 3 2024-03 190
输出结果类似:
year_month sales
1 2024-01 110
2 2024-02 120
3 2024-03 190
如果你的课程讲了 dplyr,可以使用下面写法。
如果没有安装,先运行:
install.packages("dplyr")
加载包:
library(dplyr)
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
使用 mutate() 创建新变量,使用 group_by()
和 summarise() 汇总。
df_summary <- df %>%
mutate(year_month = format(date, "%Y-%m")) %>%
group_by(year_month) %>%
summarise(
total_sales = sum(sales),
mean_sales = mean(sales),
count = n()
)
df_summary
## # A tibble: 3 × 4
## year_month total_sales mean_sales count
## <chr> <dbl> <dbl> <int>
## 1 2024-01 220 110 2
## 2 2024-02 240 120 2
## 3 2024-03 380 190 2
输出类似:
# A tibble: 3 × 4
year_month total_sales mean_sales count
<chr> <dbl> <dbl> <int>
1 2024-01 220 110 2
2 2024-02 240 120 2
3 2024-03 380 190 2
lubridate 是专门处理日期时间的包。
如果没有安装:
install.packages("lubridate")
加载包:
library(lubridate)
##
## Attaching package: 'lubridate'
## The following objects are masked from 'package:base':
##
## date, intersect, setdiff, union
ymd("2024-01-05")
## [1] "2024-01-05"
ymd("2024/01/05")
## [1] "2024-01-05"
dmy("05/01/2024")
## [1] "2024-01-05"
mdy("01/05/2024")
## [1] "2024-01-05"
df$year2 <- year(df$date)
df$month2 <- month(df$date)
df$day2 <- day(df$date)
df
## id name date sales year month day month_num year_month weekday
## 1 1 A 2024-01-05 100 2024 01 05 1 2024-01 星期五
## 2 2 B 2024-01-12 120 2024 01 12 1 2024-01 星期五
## 3 3 C 2024-02-03 90 2024 02 03 2 2024-02 星期六
## 4 4 D 2024-02-20 150 2024 02 20 2 2024-02 星期二
## 5 5 E 2024-03-01 200 2024 03 01 3 2024-03 星期五
## 6 6 F 2024-03-15 180 2024 03 15 3 2024-03 星期五
## weekday_num days_from_start year2 month2 day2
## 1 5 0 2024 1 5
## 2 5 7 2024 1 12
## 3 6 29 2024 2 3
## 4 2 46 2024 2 20
## 5 5 56 2024 3 1
## 6 5 70 2024 3 15
df$weekday2 <- wday(df$date, label = TRUE)
df
## id name date sales year month day month_num year_month weekday
## 1 1 A 2024-01-05 100 2024 01 05 1 2024-01 星期五
## 2 2 B 2024-01-12 120 2024 01 12 1 2024-01 星期五
## 3 3 C 2024-02-03 90 2024 02 03 2 2024-02 星期六
## 4 4 D 2024-02-20 150 2024 02 20 2 2024-02 星期二
## 5 5 E 2024-03-01 200 2024 03 01 3 2024-03 星期五
## 6 6 F 2024-03-15 180 2024 03 15 3 2024-03 星期五
## weekday_num days_from_start year2 month2 day2 weekday2
## 1 5 0 2024 1 5 周五
## 2 5 7 2024 1 12 周五
## 3 6 29 2024 2 3 周六
## 4 2 46 2024 2 20 周二
## 5 5 56 2024 3 1 周五
## 6 5 70 2024 3 15 周五
如果你想让星期从星期一开始:
df$weekday_monday <- wday(df$date, label = TRUE, week_start = 1)
df
## id name date sales year month day month_num year_month weekday
## 1 1 A 2024-01-05 100 2024 01 05 1 2024-01 星期五
## 2 2 B 2024-01-12 120 2024 01 12 1 2024-01 星期五
## 3 3 C 2024-02-03 90 2024 02 03 2 2024-02 星期六
## 4 4 D 2024-02-20 150 2024 02 20 2 2024-02 星期二
## 5 5 E 2024-03-01 200 2024 03 01 3 2024-03 星期五
## 6 6 F 2024-03-15 180 2024 03 15 3 2024-03 星期五
## weekday_num days_from_start year2 month2 day2 weekday2 weekday_monday
## 1 5 0 2024 1 5 周五 周五
## 2 5 7 2024 1 12 周五 周五
## 3 6 29 2024 2 3 周六 周六
## 4 2 46 2024 2 20 周二 周二
## 5 5 56 2024 3 1 周五 周五
## 6 5 70 2024 3 15 周五 周五
日期列也可以作为横轴。
plot(df$date, df$sales,
type = "b",
main = "Sales by Date",
xlab = "Date",
ylab = "Sales")
这里:
type = "b" 表示点和线都显示;错误示例:
df$date >= "2024-02-01"
虽然有时能运行,但不规范。
推荐写法:
df$date >= as.Date("2024-02-01")
## [1] FALSE FALSE TRUE TRUE TRUE TRUE
例如:
as.Date("05/01/2024")
R不一定知道它是日/月/年还是月/日/年。
应该明确写:
as.Date("05/01/2024", format = "%d/%m/%Y")
## [1] "2024-01-05"
或者:
as.Date("05/01/2024", format = "%m/%d/%Y")
## [1] "2024-05-01"
如果月份是字符:
"1", "10", "2"
排序可能会变成:
1, 10, 2
所以做月份排序时,最好使用:
df$month_num <- as.numeric(format(df$date, "%m"))
df[order(df$month_num), ]
## id name date sales year month day month_num year_month weekday
## 1 1 A 2024-01-05 100 2024 01 05 1 2024-01 星期五
## 2 2 B 2024-01-12 120 2024 01 12 1 2024-01 星期五
## 3 3 C 2024-02-03 90 2024 02 03 2 2024-02 星期六
## 4 4 D 2024-02-20 150 2024 02 20 2 2024-02 星期二
## 5 5 E 2024-03-01 200 2024 03 01 3 2024-03 星期五
## 6 6 F 2024-03-15 180 2024 03 15 3 2024-03 星期五
## weekday_num days_from_start year2 month2 day2 weekday2 weekday_monday
## 1 5 0 2024 1 5 周五 周五
## 2 5 7 2024 1 12 周五 周五
## 3 6 29 2024 2 3 周六 周六
## 4 2 46 2024 2 20 周二 周二
## 5 5 56 2024 3 1 周五 周五
## 6 5 70 2024 3 15 周五 周五
# 创建数据
df <- data.frame(
date = c("2024-01-05", "2024-02-03", "2024-03-01"),
sales = c(100, 90, 200)
)
# 字符转日期
df$date <- as.Date(df$date)
# 提取年月日
df$year <- format(df$date, "%Y")
df$month <- format(df$date, "%m")
df$day <- format(df$date, "%d")
# 提取年月
df$year_month <- format(df$date, "%Y-%m")
# 计算日期差
df$days_from_start <- as.numeric(df$date - min(df$date))
# 按日期筛选
df_after_feb <- df[df$date >= as.Date("2024-02-01"), ]
# 按月汇总
monthly_sales <- aggregate(sales ~ year_month, data = df, sum)
df
## date sales year month day year_month days_from_start
## 1 2024-01-05 100 2024 01 05 2024-01 0
## 2 2024-02-03 90 2024 02 03 2024-02 29
## 3 2024-03-01 200 2024 03 01 2024-03 56
df_after_feb
## date sales year month day year_month days_from_start
## 2 2024-02-03 90 2024 02 03 2024-02 29
## 3 2024-03-01 200 2024 03 01 2024-03 56
monthly_sales
## year_month sales
## 1 2024-01 100
## 2 2024-02 90
## 3 2024-03 200
请完成下面任务:
orders <- data.frame(
order_id = 1:5,
order_date = c("2024/01/02", "2024/01/20", "2024/02/05",
"2024/02/18", "2024/03/01"),
amount = c(200, 150, 300, 250, 400)
)
orders
## order_id order_date amount
## 1 1 2024/01/02 200
## 2 2 2024/01/20 150
## 3 3 2024/02/05 300
## 4 4 2024/02/18 250
## 5 5 2024/03/01 400
要求:
order_date 转换成日期型;year_month,格式为
"2024-01";orders$order_date <- as.Date(orders$order_date, format = "%Y/%m/%d")
orders$year_month <- format(orders$order_date, "%Y-%m")
orders_after_feb <- orders[orders$order_date >= as.Date("2024-02-01"), ]
monthly_amount <- aggregate(amount ~ year_month, data = orders, sum)
orders
## order_id order_date amount year_month
## 1 1 2024-01-02 200 2024-01
## 2 2 2024-01-20 150 2024-01
## 3 3 2024-02-05 300 2024-02
## 4 4 2024-02-18 250 2024-02
## 5 5 2024-03-01 400 2024-03
orders_after_feb
## order_id order_date amount year_month
## 3 3 2024-02-05 300 2024-02
## 4 4 2024-02-18 250 2024-02
## 5 5 2024-03-01 400 2024-03
monthly_amount
## year_month amount
## 1 2024-01 350
## 2 2024-02 550
## 3 2024-03 400