4.8 Groupby 和 Combine

在 R 编程语言中,Wickham (2011) 推广了用于数据转换的 split-apply-combine 模式。 在该模式中,我们先将数据 split 成不同组,然后对每一组 apply 一个或多个函数,最后 combine 每组的结果。 DataFrames.jl 完全支持 split-apply-combine 模式。 本节使用之前的学生成绩数据作为示例。 假设想获得每个学生的平均成绩:

  1. function all_grades()
  2. df1 = grades_2020()
  3. df1 = select(df1, :name, :grade_2020 => :grade)
  4. df2 = grades_2021()
  5. df2 = select(df2, :name, :grade_2021 => :grade)
  6. rename_bob2(data_col) = replace.(data_col, "Bob 2" => "Bob")
  7. df2 = transform(df2, :name => rename_bob2 => :name)
  8. return vcat(df1, df2)
  9. end
  10. all_grades()
namegrade
Sally1.0
Bob5.0
Alice8.5
Hank4.0
Bob9.5
Sally9.5
Hank6.0

按照该模式,先将数据集按照学生名称 split 为不同组,其次对每组数据 apply 均值函数,最后 combine 每组的结果。

在 split 步骤中使用的函数为 groupby,并将函数的第二个参数列 ID 指定为数据集分割的条件。

  1. groupby(all_grades(), :name)
  1. GroupedDataFrame with 4 groups based on key: name
  2. Group 1 (2 rows): name = "Sally"
  3. Row name grade
  4. String Float64
  5. ─────┼─────────────────
  6. 1 Sally 1.0
  7. 2 Sally 9.5
  8. Group 2 (2 rows): name = "Bob"
  9. Row name grade
  10. String Float64
  11. ─────┼─────────────────
  12. 1 Bob 5.0
  13. 2 Bob 9.5
  14. Group 3 (1 row): name = "Alice"
  15. Row name grade
  16. String Float64
  17. ─────┼─────────────────
  18. 1 Alice 8.5
  19. Group 4 (2 rows): name = "Hank"
  20. Row name grade
  21. String Float64
  22. ─────┼─────────────────
  23. 1 Hank 4.0
  24. 2 Hank 6.0

mean 函数来自 Julia 标准库中的 Statistics 模块:

  1. using Statistics

应用此函数时,需调用 combine 函数:

  1. gdf = groupby(all_grades(), :name)
  2. combine(gdf, :grade => mean)
namegrade_mean
Sally5.25
Bob7.25
Alice8.5
Hank5.0

想象一下,如果没有 groupbycombine 函数,则需按照下文这样做。 我们必须循环遍历数据以将其分割为多组,然后循环遍历每组以应用函数,以及 循环遍历每组以收集最终结果。 因此,split-apply-combine 模式是值得掌握的技术。

4.8.1 Multiple Source Columns

但如果我们想将一个函数应用到多列数据,该如何操作?

  1. group = [:A, :A, :B, :B]
  2. X = 1:4
  3. Y = 5:8
  4. df = DataFrame(; group, X, Y)
groupXY
A15
A26
B37
B48

操作与之前类似:

  1. gdf = groupby(df, :group)
  2. combine(gdf, [:X, :Y] .=> mean; renamecols=false)
groupXY
A1.55.5
B3.57.5

注意到,我们在右箭头 => 前使用了 . 点运算符,这表示 mean 函数将应用到多个列 [:X, :Y]

要在combine中使用组合函数,一种简单的方法是创建一个函数来执行预期的组合变换。 例如,对于一组数据,在先应用 mean后调用 round 对值取整(即 Int )。

  1. gdf = groupby(df, :group)
  2. rounded_mean(data_col) = round(Int, mean(data_col))
  3. combine(gdf, [:X, :Y] .=> rounded_mean; renamecols=false)
groupXY
A26
B48

CC BY-NC-SA 4.0 Jose Storopoli, Rik Huijzer, Lazaro Alonso, 刘贵欣 (中文翻译), 田俊 (中文审校)