9  数值数字变量

大多数情况下,数值会以 R 的标准数值类型(如 integerdouble)形式存在。但有时会遇到字符串形式的数字,可能是从列名透视过来的数据,或者数据导入过程中出现了错误。

readr::parse_number()readr::parse_double() 函数可以帮助我们将字符串转换为数值,忽略其中的非数字字符。

# parse_double()
x <- c("1", "2", "3")
parse_double(x)
[1] 1 2 3
# parse_number()
y <- c("$100", "200%", "300 dollars")
parse_number(y)
[1] 100 200 300

9.1 计数

  • dplyr::count(): 用于计算数据框中某些变量的频率。

    • sort 参数可以指定是否按频率排序结果。
    • wt参数可以指定一个变量,用于计算加权频率。
  • dplyr::tally(): 用于计算数据框的总行数。

  • dplyr::add_count()dplyr::add_tally(): 与没有add_前缀的是等价的,唯一的不同是使用mutate()代替了summarise()。前者用于在数据框中添加一个新列,表示某个变量的频率,后者用于在数据框中添加一个新列,表示数据框的总行数。

  • dplyr::n_distinct(): 用于计算某个变量中不同(唯一)值的数量。

除了 count(),也可以手动组合 group_by()summarize()n() 来完成相同操作。这种方式更灵活,可以同时进行其他统计。但当我们更需要快速查看数据的频数统计情况时,使用count()显然更加便捷。
# 使用 count() 计算每个目的地对应的航班数量,并按数量排序
flights |>
  count(dest, sort = T)
# A tibble: 105 × 2
   dest      n
   <chr> <int>
 1 ORD   17283
 2 ATL   17215
 3 LAX   16174
 4 BOS   15508
 5 MCO   14082
 6 CLT   14064
 7 SFO   13331
 8 FLL   12055
 9 MIA   11728
10 DCA    9705
# ℹ 95 more rows
# 使用 n_distinct() 计算哪些目的地有最多航空公司服务
flights |>
  group_by(dest) |>
  summarize(num_carriers = n_distinct(carrier)) |>
  arrange(desc(num_carriers))
# A tibble: 105 × 2
   dest  num_carriers
   <chr>        <int>
 1 ATL              7
 2 BOS              7
 3 CLT              7
 4 ORD              7
 5 TPA              7
 6 AUS              6
 7 DCA              6
 8 DTW              6
 9 IAD              6
10 MSP              6
# ℹ 95 more rows
# 使用 count() 计算每架飞机飞行的总里程
flights |>
  count(tailnum, wt = distance)
# A tibble: 4,044 × 2
   tailnum      n
   <chr>    <dbl>
 1 D942DN    3418
 2 N0EGMQ  250866
 3 N10156  115966
 4 N102UW   25722
 5 N103US   24619
 6 N104UW   25157
 7 N10575  150194
 8 N105UW   23618
 9 N107US   21677
10 N108UW   32070
# ℹ 4,034 more rows

9.2 数值计算

  • pmin()pmax(): 分别用于逐行计算一组数值的最小值和最大值。
min()/max()则是整体取最小/最大,会返回一个标量。
df <- tribble(
  ~x , ~y ,
   1 ,  3 ,
   5 ,  2 ,
   7 , NA
)
df |>
  mutate(
    # 逐行返回最值
    pmin_xy = pmin(x, y, na.rm = TRUE),
    pmax_xy = pmax(x, y, na.rm = TRUE),
    # 整体返回最值
    max_xy = max(x, y, na.rm = TRUE),
    min_xy = min(x, y, na.rm = TRUE)
  )
# A tibble: 3 × 6
      x     y pmin_xy pmax_xy max_xy min_xy
  <dbl> <dbl>   <dbl>   <dbl>  <dbl>  <dbl>
1     1     3       1       3      7      1
2     5     2       2       5      7      1
3     7    NA       7       7      7      1
  • floor()ceiling()round(): 分别用于向下取整、向上取整和四舍五入。注意,R 默认采用“四舍六入,五取偶”的修约策略。
这意味着当小数部分正好是0.5时,会将数字舍入到最接近的偶数。例如,round(2.5)会返回2,而round(3.5)会返回4
round(123.456, digits = 2) # 四舍五入到小数点后两位
[1] 123.46
floor(123.456) # 向下取整
[1] 123
ceiling(123.456) # 向上取整
[1] 124
  • cut(): 用于将连续数值划分为离散的区间。

    • 使用labels参数为每一分段设置标签。
    • 参数right = FALSE 表示分段区间是 [a, b)
    • 参数include.lowest = TRUE 表示分段包括最小值。
    x <- c(1, 2, 5, 10, 15, 20)
    cut(
      x,
      breaks = c(0, 5, 10, 15, 20),
      # labels = c("sm", "md", "lg", "xl")
    )
    [1] (0,5]   (0,5]   (0,5]   (5,10]  (10,15] (15,20]
    Levels: (0,5] (5,10] (10,15] (15,20]
  • cumsun()cumprod(): 分别用于计算累积和和累积积;cummin()cummax() 则分别用于计算累积最小值和累积最大值;cummean() 用于计算累积均值。

cut()函数可以将数值变量转换为因子变量,便于进行分类分析和可视化。
x <- 1:3
cumsum(x) # 累积和
[1] 1 3 6
cummean(x) # 累积均值
[1] 1.0 1.5 2.0
cumprod(x) # 累积积
[1] 1 2 6

9.3 通用数值变换

9.3.1 排序

  • dplyr::min_rank(): 用于对数值从小到大进行排名,返回每个数值的排名位置,与desc()函数连用可以用于实现降序排名。dplyr中还有许多变体的排名函数。
    • row_number():不保留并列,按顺序排名相同值。
    • dense_rank():将并列的若干值视为一体,下一个名次不跳号。
    • percent_rank():按百分比标准化排名。
    • cume_dist():累计分布,表示当前值小于等于多少比例。
默认情况下,min_rank() 会为相同的数值分配相同的排名(即并列排名)。
x <- c(1, 2, 2, 3, 4, NA)
min_rank(x)
[1]  1  2  2  4  5 NA
min_rank(desc(x)) # 降序排名
[1]  5  3  3  2  1 NA

9.3.2 偏移量和连续

  • dplyr::lead()函数可以将当前向量向前移动一定单位,默认1位,加上参数n可实现多位偏移。

  • dplyr::lag()则向后移动。返回向量长度与输入一致,并在开头或结尾填充NA

x <- c(2, 5, 11, 11, 19, 35)

lag(x)
[1] NA  2  5 11 11 19
lead(x)
[1]  5 11 11 19 35 NA
  • 有时需要在满足某个条件时开始新的分组。例如,分析网站访问行为时,若两次访问间隔超过某一阈值(如5分钟),就认为是新的访问会话:
events <- tibble(time = c(0, 1, 2, 3, 5, 10, 12, 15, 17, 19, 20, 27, 28, 30))

events |> mutate(
  diff = time - lag(time, default = first(time)),
  has_gap = diff >= 5, # 生成逻辑值,表示是否存在5min的间隔
  group = cumsum(has_gap) # 为每段会话生成连续编号-5min内的都算同一段会话
)
# A tibble: 14 × 4
    time  diff has_gap group
   <dbl> <dbl> <lgl>   <int>
 1     0     0 FALSE       0
 2     1     1 FALSE       0
 3     2     1 FALSE       0
 4     3     1 FALSE       0
 5     5     2 FALSE       0
 6    10     5 TRUE        1
 7    12     2 FALSE       1
 8    15     3 FALSE       1
 9    17     2 FALSE       1
10    19     2 FALSE       1
11    20     1 FALSE       1
12    27     7 TRUE        2
13    28     1 FALSE       2
14    30     2 FALSE       2

9.4 数值摘要

  • mean(): 平均数,对极端值敏感,适合对称分布。

  • median(): 中位数,不受极端值影响,适合偏态分布。

  • min() / max(): 最小/最大值;

  • quantile(x, p): 分位数,常用于排除极端值影响。p取值为[0,1]。

  • sd(x): 标准差,衡量总体波动。

  • IQR(x): 四分位距 = Q3 - Q1,衡量中间 50% 数据的跨度。

  • first(x) / last(x) / nth(x, n): 提取每组数据中的第一个、最后一个、第 n 个元素。支持以下参数:

    • na_rm = TRUE:跳过缺失值;
    • default = ...:位置不存在时提供默认值;
    • order_by = ...:更改排序方式;

以上函数不仅用于 summarize(),也常用于 mutate() 实现标准化变换:

  • x / sum(x):转换为比例。

  • (x - mean(x)) / sd(x):转换为标准分数(Z-score)。

  • (x - min(x)) / (max(x) - min(x)):归一化到 [0, 1]。

  • x / first(x):转换为指数增长(以首值为基准)