标签 tidyverse 下的文章

首先通过 count() 计算出各种 cut 的钻石各有多少个,存到名为 n 的列里,然后通过 mutate 计算出总和为1的占比。此时如果用 geom_col() 画图可以得出一个高度为1的堆积图。

library(tidyverse)

diamonds %>%
  count(cut) %>%
  mutate(p = n / sum(n)) %>%
  ggplot(aes("", p, fill = cut)) +
  geom_col() +
  scale_fill_brewer(type = "div")

p1.png

再加以 coord_polar() 变换转换为极座标,就可以画出一张饼图了。在此基础上多叠加一层 geom_text() 就实现了百分比的显示,非常灵活。

diamonds %>%
  count(cut) %>%
  mutate(p = n / sum(n)) %>%
  mutate(labels = scales::label_percent(accuracy = 0.01)(n / sum(n))) %>%
  ggplot(aes("", p, fill = cut)) +
  geom_col() +
  geom_text(aes(label = labels), position = position_stack(0.5)) +
  coord_polar("y") +
  scale_fill_brewer(type = "div")

p2.png

如果不想显示极座标轴和灰色背景,可以通过加上 theme_void() 来实现。对于重叠的文字则是可以用 ggrepel 打散,最终效果如图。

p3.png

tidyr 本身就提供了 unnest() 系列函数,可以用于展开嵌套的数据结构。配合 fromJSON() 使用就可以实现 JSON 字段的展开。

library(tidyverse)
library(jsonlite)

spread_all <- function(data, cols) {
  data %>%
    mutate(across(all_of(cols), function(x)
      map(x, fromJSON))) %>%
    unnest_wider(all_of(cols))
}

# 用法
df %>%
  spread_all(c("x", "y"))

为了加速 JSON 的解析,我们可以引入 furrr 包来实现并发解析。

library(furrr)
# make future_map parallel
plan(multisession)

spread_all <- function(data, cols) {
  data %>%
    mutate(across(all_of(cols), function(x)
      future_map(x, fromJSON))) %>%
    unnest_wider(all_of(cols))
}

如何将多个同样格式的 csv 文件合并读取到一个 tibble 里呢?很自然的会想到先用 read_csv() 分别读取每个文件,再用 reduce(rbind) 聚合到一起。这样确实能用,但对于大数据集来说性能很差。

readr 从 2.0.0 开始原生支持同时读取多个文件的功能,只需要把文件名字符串向量里传给 file 参数就行。实测在数据量很大的时候和 rbind 相比可以显著减少读取时间。这个功能在 readr 包的文档中没有描述,导致我走了不少弯路才发现 readr 原生就支持多文件读取。

另外 vroom 从 1.0.0 开始就原生支持了这个功能,用法一样不过 vroom 对于文件中的字符数据是懒加载的,在某些场景下可以提升性能。具体能否提升性能要看使用方式了,可以用 system.time({}) 实测一下。