4.8 Groupby 和 Combine

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

function all_grades()
    df1 = grades_2020()
    df1 = select(df1, :name, :grade_2020 => :grade)
    df2 = grades_2021()
    df2 = select(df2, :name, :grade_2021 => :grade)
    rename_bob2(data_col) = replace.(data_col, "Bob 2" => "Bob")
    df2 = transform(df2, :name => rename_bob2 => :name)
    return vcat(df1, df2)
end
all_grades()
name grade
Sally 1.0
Bob 5.0
Alice 8.5
Hank 4.0
Bob 9.5
Sally 9.5
Hank 6.0

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

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

groupby(all_grades(), :name)
GroupedDataFrame with 4 groups based on key: name
Group 1 (2 rows): name = "Sally"
 Row │ name    grade
     │ String  Float64
─────┼─────────────────
   1 │ Sally       1.0
   2 │ Sally       9.5
Group 2 (2 rows): name = "Bob"
 Row │ name    grade
     │ String  Float64
─────┼─────────────────
   1 │ Bob         5.0
   2 │ Bob         9.5
Group 3 (1 row): name = "Alice"
 Row │ name    grade
     │ String  Float64
─────┼─────────────────
   1 │ Alice       8.5
Group 4 (2 rows): name = "Hank"
 Row │ name    grade
     │ String  Float64
─────┼─────────────────
   1 │ Hank        4.0
   2 │ Hank        6.0

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

using Statistics

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

gdf = groupby(all_grades(), :name)
combine(gdf, :grade => mean)
name grade_mean
Sally 5.25
Bob 7.25
Alice 8.5
Hank 5.0

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

4.8.1 Multiple Source Columns

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

group = [:A, :A, :B, :B]
X = 1:4
Y = 5:8
df = DataFrame(; group, X, Y)
group X Y
A 1 5
A 2 6
B 3 7
B 4 8

操作与之前类似:

gdf = groupby(df, :group)
combine(gdf, [:X, :Y] .=> mean; renamecols=false)
group X Y
A 1.5 5.5
B 3.5 7.5

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

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

gdf = groupby(df, :group)
rounded_mean(data_col) = round(Int, mean(data_col))
combine(gdf, [:X, :Y] .=> rounded_mean; renamecols=false)
group X Y
A 2 6
B 4 8


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