R 数据处理 —— lubridate

1. 前言

本节我们将介绍 R 中的时间和日期的处理。乍一看,你可能觉得这很简单。

让我们来看看下面三个问题:

  • 每年都是 365 天?
  • 每天都有 24 小时?
  • 每分钟是 60 秒?

当然,你肯定知道一年不一定都是 365 天,但是你知道哪一年是闰年吗?

世界上很多地方都使用夏令时,所以有些日子是 23 小时,有些日子是 25 小时。

你可能不知道有些分钟有 61 秒,因为地球自转正逐渐减慢,时不时地增加闰秒。

有时候,时间和日期是很困难的。因为需要协调地球的自转和公转与地区的月份、时区、夏令时之间的关系。

下面我们将详细介绍如何处理这些数据

1.1 导入

本节的重点是使用 lubridate 包来处理 R 中的日期和时间。

lubridate 不是核心的 tidyverse 包,所以需要手动导入。并利用 nycflights13 作为例子数据来练习

library(tidyverse)

library(lubridate)
library(nycflights13)

2. 创建时间/日期

总共有 3 种形式的日期/时间数据

  • date: tibble 中标题的 <date>
  • time: 一天内的时间,tibble 中标题的 <time>
  • date-time: 日期+时间,唯一标识时间点,tibble 中标题的 <dttm>

本节我们只关注日期和日期+时间,并尽可能使其简单化,如果能用日期就不用日期+时间

要获取当前的日期和日期+时间,可以

> today()
[1] "2021-01-27"
> now()
[1] "2021-01-27 19:48:46 CST"

此外,有三种方法创建日期/时间

  • 根据字符串创建
  • 单个日期-时间组件
  • 现存的日期-时间

它们的工作方式如下

2.1 字符串

日期/时间通常以字符串的形式出现,一种方式我们已经在前面的 readr 中介绍过了,另一种方法是使用 lubridate 包提供的工具

通过制定字符串中年(y)、月(m)、日(d)的出现顺序,会自动转换为日期格式。

> ymd("2017-01-31")
[1] "2017-01-31"
> mdy("January 31st, 2017")
[1] "2017-03-01"
> dmy("31-Jan-2017")
[1] "2017-01-31"

这些函数也可以接受不带引号的数字

> ymd(20170131)
[1] "2017-01-31"

想要创建日期时间的话,可以在 ymd(mdydmy 等) 后面添加一个下划线以及一个或多个 h、m、s

> ymd_hms("2017-01-31 20:11:59")
[1] "2017-01-31 20:11:59 UTC"
> mdy_hm("01/31/2017 08:01")
[1] "2017-01-31 08:01:00 UTC"

还可以添加时区

> ymd(20170131, tz = "UTC")
[1] "2017-01-31 UTC"
2.2 单个组件

有时候我们的数据会像 flights 表一样,日期时间是分开的

> flights %>% 
+     select(year, month, day, hour, minute)
# A tibble: 336,776 x 5
    year month   day  hour minute
   <int> <int> <int> <dbl>  <dbl>
 1  2013     1     1     5     15
 2  2013     1     1     5     29
 3  2013     1     1     5     40
 4  2013     1     1     5     45
 5  2013     1     1     6      0
 6  2013     1     1     5     58
 7  2013     1     1     6      0
 8  2013     1     1     6      0
 9  2013     1     1     6      0
10  2013     1     1     6      0
# … with 336,766 more rows

对于这种数据,可以使用 make_date() 来创建日期,或使用 make_datetime() 来创建日期-时间

> flights %>% 
+     select(year, month, day, hour, minute) %>% 
+     mutate(departure = make_datetime(year, month, day, hour, minute))
# A tibble: 336,776 x 6
    year month   day  hour minute departure          
   <int> <int> <int> <dbl>  <dbl> <dttm>             
 1  2013     1     1     5     15 2013-01-01 05:15:00
 2  2013     1     1     5     29 2013-01-01 05:29:00
 3  2013     1     1     5     40 2013-01-01 05:40:00
 4  2013     1     1     5     45 2013-01-01 05:45:00
 5  2013     1     1     6      0 2013-01-01 06:00:00
 6  2013     1     1     5     58 2013-01-01 05:58:00
 7  2013     1     1     6      0 2013-01-01 06:00:00
 8  2013     1     1     6      0 2013-01-01 06:00:00
 9  2013     1     1     6      0 2013-01-01 06:00:00
10  2013     1     1     6      0 2013-01-01 06:00:00
# … with 336,766 more rows

让我们对 flights 剩下的其他四列时间进行格式化

> flights_dt <- flights %>% 
+     filter(!is.na(dep_time), !is.na(arr_time)) %>% 
+     mutate(
+         dep_time = make_datetime_100(year, month, day, dep_time),
+         arr_time = make_datetime_100(year, month, day, arr_time),
+         sched_dep_time = make_datetime_100(year, month, day, sched_dep_time),
+         sched_arr_time = make_datetime_100(year, month, day, sched_arr_time)
+     ) %>% 
+     select(origin, dest, ends_with("delay"), ends_with("time"))
> 
> flights_dt
# A tibble: 328,063 x 9
   origin dest  dep_delay arr_delay dep_time            sched_dep_time      arr_time           
   <chr>  <chr>     <dbl>     <dbl> <dttm>              <dttm>              <dttm>             
 1 EWR    IAH           2        11 2013-01-01 05:17:00 2013-01-01 05:15:00 2013-01-01 08:30:00
 2 LGA    IAH           4        20 2013-01-01 05:33:00 2013-01-01 05:29:00 2013-01-01 08:50:00
 3 JFK    MIA           2        33 2013-01-01 05:42:00 2013-01-01 05:40:00 2013-01-01 09:23:00
 4 JFK    BQN          -1       -18 2013-01-01 05:44:00 2013-01-01 05:45:00 2013-01-01 10:04:00
 5 LGA    ATL          -6       -25 2013-01-01 05:54:00 2013-01-01 06:00:00 2013-01-01 08:12:00
 6 EWR    ORD          -4        12 2013-01-01 05:54:00 2013-01-01 05:58:00 2013-01-01 07:40:00
 7 EWR    FLL          -5        19 2013-01-01 05:55:00 2013-01-01 06:00:00 2013-01-01 09:13:00
 8 LGA    IAD          -3       -14 2013-01-01 05:57:00 2013-01-01 06:00:00 2013-01-01 07:09:00
 9 JFK    MCO          -3        -8 2013-01-01 05:57:00 2013-01-01 06:00:00 2013-01-01 08:38:00
10 LGA    ORD          -2         8 2013-01-01 05:58:00 2013-01-01 06:00:00 2013-01-01 07:53:00
# … with 328,053 more rows, and 2 more variables: sched_arr_time <dttm>, air_time <dbl>

然后,我们可以看看全年的出发时间的分布

> flights_dt %>% 
+     ggplot(aes(dep_time)) + 
+     geom_freqpoly(binwidth = 86400) # 86400 seconds = 1 day

image.png

也可以查看一天内的出发情况

> flights_dt %>% 
+     filter(dep_time < ymd(20130102)) %>% 
+     ggplot(aes(dep_time)) + 
+     geom_freqpoly(binwidth = 600) # 600 s = 10 minutes

image.png

注意:在日期中 1 表示一天,在时间中 1 表示一秒,86400 秒为一天

2.3 其他类型

有时你可能需要自日期-时间和日期之间相互切换,可以使用 as_datetime()as_date()

> as_datetime(today())
[1] "2021-01-27 UTC"
> as_date(now())
[1] "2021-01-27"

如果想获取相对于 1970-01-01 的偏移的日期/时间,如果偏移是秒,使用 as_datetime(),如果是天,使用 as_date()

> as_datetime(60 * 60 * 10)
[1] "1970-01-01 10:00:00 UTC"
> as_date(365 * 10 + 2)
[1] "1980-01-01"
2.4 思考练习
  1. 如果解析包含无效日期的字符串会怎样?
ymd(c("2010-10-10", "bananas"))
  1. tzone 参数对 today() 有什么作用?

  2. 使用相应的 lubridate 函数来解析以下每个日期

d1 <- "January 1, 2010"
d2 <- "2015-Mar-07"
d3 <- "06-Jun-2017"
d4 <- c("August 19 (2015)", "July 1 (2015)")
d5 <- "12/30/14" # Dec 30, 2014

3. 日期-时间组件

这一部分的重点是介绍访问器函数,用于获取或设置日期-时间组件。

3.1 获取组件

你可以使用下面的访问器函数来获取日期时间组件:

  • year()
  • month()
  • mday() 月份的天,
  • yday() 一年中的天,
  • wday() 星期,
  • hour()
  • minute()
  • second()
> datetime <- ymd_hms("2020-07-08 12:34:56")
> year(datetime)
[1] 2020
> month(datetime)
[1] 7
> mday(datetime)
[1] 8
> yday(datetime)
[1] 190
> wday(datetime)
[1] 4

对于 month()wday() ,您可以设置 label = TRUE 来返回一个月或星期的缩写名称。

设置 abbr = FALSE 返回全名

> month(datetime, label = TRUE)
[1]  7
Levels:  1 <  2 <  3 <  4 <  5 <  6 <  7 <  8 <  9 < 10 < 11 < 12
> wday(datetime, label = TRUE, abbr = FALSE)
[1] 星期三
Levels: 星期日 < 星期一 < 星期二 < 星期三 < 星期四 < 星期五 < 星期六

我们可以使用 wday() 来查看一周的航班

> flights_dt %>% 
+     mutate(wday = wday(dep_time, label = TRUE)) %>% 
+     ggplot(aes(x = wday)) +
+     geom_bar() +
+     theme(text = element_text(family='Kai')) # 显示中文

image.png

如果我们看一小时内每分钟的平均延迟,会看到一个有趣的现象。

> flights_dt %>% 
+   mutate(minute = minute(dep_time)) %>% 
+   group_by(minute) %>% 
+   summarise(
+     avg_delay = mean(arr_delay, na.rm = TRUE),
+     n = n()) %>% 
+   ggplot(aes(minute, avg_delay)) +
+   geom_line()
`summarise()` ungrouping output (override with `.groups` argument)

image.png

我们可以看到,在 20-30 分钟和 50-60 分钟起飞的航班延误要比其他时间少得多

有趣的是,如果我们看预计出发时间,则没有这样的模式

> sched_dep <- flights_dt %>% 
+     mutate(minute = minute(sched_dep_time)) %>% 
+     group_by(minute) %>% 
+     summarise(
+         avg_delay = mean(arr_delay, na.rm = TRUE),
+         n = n())
`summarise()` ungrouping output (override with `.groups` argument)
> #> `summarise()` ungrouping output (override with `.groups` argument)
> 
> ggplot(sched_dep, aes(minute, avg_delay)) +
+     geom_line()

image.png

3.2 四舍五入

类似于浮点数,我们可以使用 floor_date()round_date()ceiling_date() 将日期四舍五入到附近的时间单位

> flights_dt %>% 
+     count(week = floor_date(dep_time, "week")) %>% 
+     ggplot(aes(week, n)) +
+     geom_line()

3.3 设置组件

您还可以使用每个访问器函数来设置日期/时间的组成部分

> (datetime <- ymd_hms("2010-10-08 12:34:56"))
[1] "2010-10-08 12:34:56 UTC"
> year(datetime) <- 2020
> datetime
[1] "2020-10-08 12:34:56 UTC"
> month(datetime) <- 01
> datetime
[1] "2020-01-08 12:34:56 UTC"
> hour(datetime) <- hour(datetime) + 1
> datetime
[1] "2020-01-08 13:34:56 UTC"

此外,您可以使用 update() 创建新的日期时间,而不是在原地进行修改。这也允许您一次设置多个值。

> update(datetime, year = 2020, month = 2, mday = 2, hour = 2)
[1] "2020-02-02 02:34:56 UTC"

如果设置的值太大,它们将自动顺延

> ymd("2015-02-01") %>% 
+     update(mday = 30)
[1] "2015-03-02"
> ymd("2015-02-01") %>% 
+     update(hour = 400)
[1] "2015-02-17 16:00:00 UTC"

您可以使用 update() 来显示一天的航班分布

> flights_dt %>% 
+     mutate(dep_hour = update(dep_time, yday = 1)) %>% 
+     ggplot(aes(dep_hour)) +
+     geom_freqpoly(binwidth = 300)

image.png

3.4 思考练习
  1. 一天中的飞行时间分布在一年中如何变化

  2. air_time 与出发和到达之间的持续时间进行比较,解释您的发现(提示:考虑机场的位置)。

  3. 平均延迟时间在一天中如何变化?您应该使用 dep_time 还是 sched_dep_time?为什么?

  4. 如果想最大程度地减少飞机晚点的情况,应该在一周中的哪一天离开?

4. 时间跨度

接下来,我们将介绍日期算术运算。包括加法、减法和除法。

在这里,我们要先了解三个代表时间跨度的类:

  • durations: 持续时间,表示精确的秒数
  • periods: 周期,代表有单位的日期,如几周和几个月
  • intervals: 区间,代表起点和终点的区间
4.1 periods

R 中,当两个日期相减时,将得到一个 difftime 对象

> h_age <- today() - ymd(19791014)
> h_age
Time difference of 15082 days

difftime 类对象记录了秒,分钟,小时,天或周的时间跨度

这种模糊性会使 difftime 有点难以处理,因此 lubridate 提供了一种始终用秒来表示的方法:duration

> as.duration(h_age)
[1] "1303084800s (~41.29 years)"

duration 有许多方便的构造函数

> dseconds(15)
[1] "15s"
> dminutes(10)
[1] "600s (~10 minutes)"
> dhours(c(12, 24))
[1] "43200s (~12 hours)" "86400s (~1 days)"  
> ddays(0:5)
[1] "0s"                "86400s (~1 days)"  "172800s (~2 days)" "259200s (~3 days)" "345600s (~4 days)"
[6] "432000s (~5 days)"
> dweeks(3)
[1] "1814400s (~3 weeks)"
> dyears(1)
[1] "31557600s (~1 years)"

duration 始终以秒为单位来记录时间,可以通过传入分钟、小时、天、周和年等单位来创建较大的单位。

你可以使用加法或乘法

> 2 * dyears(1)
[1] "63115200s (~2 years)"
> dyears(1) + dweeks(12) + dhours(15)
[1] "38869200s (~1.23 years)"

对天的加法减法

tomorrow <- today() + ddays(1)
last_year <- today() - dyears(1)

但是由于 duration 代表的是精确的时间,因此有时可能会得到意外的结果

> one_pm <- ymd_hms("2016-03-12 13:00:00", tz = "America/New_York")
> one_pm
[1] "2016-03-12 13:00:00 EST"
> one_pm + ddays(1)
[1] "2016-03-13 14:00:00 EDT"

为什么会变成下午两点呢?你可以注意到了,时区已经变了。

由于 DST 的原因,312 日只有 23 个小时,因此,如果加上一天的秒数,我们将得到不同的时间。

4.2 Periods

为了解决这个问题,lubridate 提供了 periods,它是一个时间跨度,但是没有固定的秒数。

而是人为定义的时间单位,如天或月。

> one_pm
[1] "2016-03-12 13:00:00 EST"
> one_pm + days(1)
[1] "2016-03-13 13:00:00 EDT"

类似 duration,也有许多函数用于创建 periods

> 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" "4m 0d 0H 0M 0S" "5m 0d 0H 0M 0S"
[6] "6m 0d 0H 0M 0S"
> weeks(3)
[1] "21d 0H 0M 0S"
> years(1)
[1] "1y 0m 0d 0H 0M 0S"

periods 进行加法和乘法

> 10 * (months(6) + days(1))
[1] "60m 10d 0H 0M 0S"
> days(50) + hours(25) + minutes(2)
[1] "50d 25H 2M 0S"

durations 相比较,periods 更符合我们的预期

> ymd("2016-01-01") + dyears(1)
[1] "2016-12-31 06:00:00 UTC"
> ymd("2016-01-01") + years(1)
[1] "2017-01-01"
> one_pm + ddays(1)
[1] "2016-03-13 14:00:00 EDT"
> one_pm + days(1)
[1] "2016-03-13 13:00:00 EDT"

来让我用 periods 来解决与航班日期有关的问题。有些飞机在离开纽约市之前似乎已经到达目的地

> flights_dt %>% 
+     filter(arr_time < dep_time) 
# A tibble: 10,633 x 9
   origin dest  dep_delay arr_delay dep_time            sched_dep_time      arr_time           
   <chr>  <chr>     <dbl>     <dbl> <dttm>              <dttm>              <dttm>             
 1 EWR    BQN           9        -4 2013-01-01 19:29:00 2013-01-01 19:20:00 2013-01-01 00:03:00
 2 JFK    DFW          59        NA 2013-01-01 19:39:00 2013-01-01 18:40:00 2013-01-01 00:29:00
 3 EWR    TPA          -2         9 2013-01-01 20:58:00 2013-01-01 21:00:00 2013-01-01 00:08:00
 4 EWR    SJU          -6       -12 2013-01-01 21:02:00 2013-01-01 21:08:00 2013-01-01 01:46:00
 5 EWR    SFO          11       -14 2013-01-01 21:08:00 2013-01-01 20:57:00 2013-01-01 00:25:00
 6 LGA    FLL         -10        -2 2013-01-01 21:20:00 2013-01-01 21:30:00 2013-01-01 00:16:00
 7 EWR    MCO          41        43 2013-01-01 21:21:00 2013-01-01 20:40:00 2013-01-01 00:06:00
 8 JFK    LAX          -7       -24 2013-01-01 21:28:00 2013-01-01 21:35:00 2013-01-01 00:26:00
 9 EWR    FLL          49        28 2013-01-01 21:34:00 2013-01-01 20:45:00 2013-01-01 00:20:00
10 EWR    FLL          -9       -14 2013-01-01 21:36:00 2013-01-01 21:45:00 2013-01-01 00:25:00
# … with 10,623 more rows, and 2 more variables: sched_arr_time <dttm>, air_time <dbl>

这些是夜间航班。起飞和到达时间使用了相同的日期信息,但这些航班是在第二天到达的。

我们可以通过在每个夜间航班的到达时间上加上 days(1) 来解决这个问题

flights_dt <- flights_dt %>% 
  mutate(
    overnight = arr_time < dep_time,
    arr_time = arr_time + days(overnight * 1),
    sched_arr_time = sched_arr_time + days(overnight * 1)
  )

现在,我们所有的飞行都遵循物理定律

> flights_dt %>% 
+     filter(overnight, arr_time < dep_time) 
# A tibble: 0 x 10
# … with 10 variables: origin <chr>, dest <chr>, dep_delay <dbl>, arr_delay <dbl>, dep_time <dttm>,
#   sched_dep_time <dttm>, arr_time <dttm>, sched_arr_time <dttm>, air_time <dbl>, overnight <lgl>
4.3 intervals

dyears(1) / ddays(365) 应该返回的是 1,因此 durations 总是表示秒数,而一年表示为 365 天的秒数

years(1) / days(1) 返回的是什么?如果是 2015 年返回的是 365,而 2016 返回的是 366

对于 lubridate 来说,当没有足够的信息来给出一个明确的答案。它会给出一个估计值

> years(1) / days(1)
[1] 365.25

如果你想要更精确的值,可以使用 interval

interval 是一个有起点的 durations,因此您可以准确地确定它的持续时间

> next_year <- today() + years(1)
> (today() %--% next_year) / ddays(1)
[1] 365

要找出间隔中有多少个周期,您需要使用整数除法

> (today() %--% next_year) %/% days(1)
[1] 365
4.4 总结

如何在持续时间、周期和间隔之间进行选择?一如既往,选择最简单的数据结构来解决您的问题。

  • 如果您只关心物理时间,使用持续时间;
  • 如果需要增加人为定义的时间,使用周期;
  • 如果需要计算人为定义的单位长度的跨度,使用一个间隔。

image.png

4.5 思考练习
  1. 创建一个向量,存储了 2015 年每月的第一天。创建一个包含本年度每月的第一天的日期向量。

  2. 编写一个函数,给定您的生日(以日期为单位),返回您的年龄(岁)。

5. 时区

获取当前时区

> Sys.timezone()
[1] "Asia/Shanghai"

使用 OlsonNames() 查看所有时区名称的完整列表:

> length(OlsonNames())
[1] 593
> head(OlsonNames())
[1] "Africa/Abidjan"     "Africa/Accra"       "Africa/Addis_Ababa" "Africa/Algiers"    
[5] "Africa/Asmara"      "Africa/Asmera"

R 中,时区仅仅是控制打印日期时间的属性。

例如,下面这三个对象表示同一时间点

> (x1 <- ymd_hms("2015-06-01 12:00:00", tz = "America/New_York"))
[1] "2015-06-01 12:00:00 EDT"
> (x2 <- ymd_hms("2015-06-01 18:00:00", tz = "Europe/Copenhagen"))
[1] "2015-06-01 18:00:00 CEST"
> (x3 <- ymd_hms("2015-06-02 04:00:00", tz = "Pacific/Auckland"))
[1] "2015-06-02 04:00:00 NZST"

您可以使用减法验证它们是否是同一时间

> x1 - x2
Time difference of 0 secs
> x1 - x3
Time difference of 0 secs

除非另有说明,否则 lubridate 始终使用 UTC

UTC(协调世界时)是科学界使用的标准时区,大致相当于其前身 GMT(格林威治标准时间)

> x4 <- c(x1, x2, x3)
> x4
[1] "2015-06-01 12:00:00 EDT" "2015-06-01 12:00:00 EDT" "2015-06-01 12:00:00 EDT"

你可以通过两种方式来更改时区

  • 保持时间不变,只更改其显示方式。即时间正确但您想要更自然的显示时,可以使用此功能
> x4a <- with_tz(x4, tzone = "Australia/Lord_Howe")
> x4a
[1] "2015-06-02 02:30:00 +1030" "2015-06-02 02:30:00 +1030" "2015-06-02 02:30:00 +1030"
> x4a - x4
Time differences in secs
[1] 0 0 0
  • 及时更改基础时刻。当您的时间被标记为不正确的时区,并且需要修复时,可以请使用此选项
> x4b <- force_tz(x4, tzone = "Australia/Lord_Howe")
> x4b
[1] "2015-06-01 12:00:00 +1030" "2015-06-01 12:00:00 +1030" "2015-06-01 12:00:00 +1030"
> x4b - x4
Time differences in hours
[1] -14.5 -14.5 -14.5
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
R语言是数据科学非常流行和强大的一种编程语言,用于数据分析和数据挖掘。尽管它提供了丰富的功能和包,但在使用R进行数据挖掘时,仍然存在一些常见的问题。 首先,R语言的学习曲线相对陡峭,尤其对于初学者来说。R语言的语法和概念与其他编程语言有所不同,需要一定的时间和精力来掌握。因此,在开始使用R进行数据挖掘之前,建议用户先学习基本的R语言知识和技能。 其次,R语言数据处理速度相对较慢。由于R是一种解释型语言,对于大型数据集的处理可能会显得比较缓慢。为了提高数据挖掘的效率,可以使用一些优化技巧,如向量化、使用并行计算等。此外,R在内存管理方面也有一些限制,处理大型数据集时可能会导致内存溢出等问题。 另外,R语言社区的包和函数数量庞大,但质量参差不齐。用户在进行数据挖掘时,可能会遇到某些包或函数不兼容、文档不全面等问题。为了解决这些问题,用户可以仔细查看包的文档和说明,寻求社区的帮助和讨论,或者使用经过广泛测试和应用的常用包。 此外,数据挖掘分析常涉及到特征选择、数据清洗、模型选择和调参等问题。这些问题需要专业背景和经验支持。对于初学者或者没有相关领域知识的人来说,可能需要花费更多的时间和精力来理解和解决这些问题。 总之,虽然R语言在数据挖掘领域有着广泛的应用,但在实际操作也存在一些常见的问题。通过学习和积累经验,用户可以更好地应对和解决这些问题,提高数据挖掘的效率和准确性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

名本无名

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值