Section 4 给出了 2020 年的成绩 grades_2020

    现在需要将 grades_2020 与 2021 年的成绩合并:

    1. grades_2021()
    namegrade_2021
    Bob 29.5
    Sally9.5
    Hank6.0

    此功能的实现就需要用到 joinDataFrames.jl 列出了不少于七种的 join 函数, 这看起来令人生畏,但请坚持,因为它们都很有用,后面将会逐个讨论所有函数。

    首先讨论的是 innerjoin。 假设存在两个数据集 AB, 分别具有列 A_1, A_2, ..., A_nB_1, B_2, ..., B_m并且 其中的一列具有相同的名字:A_1B_1 都是 :id。 然后对 :id 使用 innerjoin,则将遍历 A_1 中的所有元素并且与 B_1 中的元素进行比较。 如果元素 是相同的,然后将会把 A_2, ..., A_nB_2, ..., B_m 的相应信息添加到 列后。

    好吧,如果你没有明白上面的描述,请不要担心。 请查看如下所示的成绩数据集合并结果:

    1. innerjoin(grades_2020(), grades_2021(); on=:name)
    namegrade_2020grade_2021
    Sally1.09.5
    Hank4.06.0

    注意只有 “Sally” 和 “Hank” 同时存在于两个数据集中。 innerjoin 的名字对应了数学中的 交集, 即“存在于 \(A\) 的元素,也存在于 \(B\),或者说存在于 \(B\) 的元素,也存在于 \(A\)”。

    outerjoin 没有 innerjoin 那么严格,只要在 至少一个数据集中发现包含的 name,就会将相应的列合并到结果中:

      因此,当其中一个原始数据集不存在对应的值时,该方法会创建 missing 值。

      如果使用 crossjoin 将会出现更多的 missing 值。 该方法会给出 行的笛卡尔积,也就是行的乘法,即对于每一行创建一个与另一张表中所有行的组合:

      1. MethodError: no method matching crossjoin(::DataFrame, ::DataFrame; on=:id)
      2. Closest candidates are:
      3. crossjoin(::DataFrames.AbstractDataFrame, ::DataFrames.AbstractDataFrame; makeunique) at ~/.julia/packages/DataFrames/bza1S/src/join/composer.jl:1412 got unsupported keyword argument "on"
      4. crossjoin(::DataFrames.AbstractDataFrame, ::DataFrames.AbstractDataFrame, !Matched::DataFrames.AbstractDataFrame...; makeunique) at ~/.julia/packages/DataFrames/bza1S/src/join/composer.jl:1434 got unsupported keyword argument "on"
      5. ...

      呃,出错了。 因为 crossjoin 并不按行考虑元素,所以不需要将 on 参数指定为想要合并的列:

      1. crossjoin(grades_2020(), grades_2021())
      1. ArgumentError: Duplicate variable names: :name. Pass makeunique=true to make them unique using a suffix automatically.
      2. [1] add_names(ind::DataFrames.Index, add_ind::DataFrames.Index; makeunique::Bool)
      3. @ DataFrames ~/.julia/packages/DataFrames/bza1S/src/other/index.jl:430
      4. [2] merge!(x::DataFrames.Index, y::DataFrames.Index; makeunique::Bool)
      5. ...

      呃,又出错了。 这是一个 DataFrame 和 中很常见的错误。 2020 和 2021 年成绩表有一个重复的列名,即 :name。 与之前一样,DataFrames.jl 的报错输出给出了一个可能修复此错误的简单建议。 尝试仅传递 makeunique=true 解决此问题:

      namegrade_2020name_1grade_2021
      Sally1.0Bob 29.5
      Sally1.0Sally9.5
      Sally1.0Hank6.0
      Bob5.0Bob 29.5
      Bob5.0Sally9.5
      Bob5.0Hank6.0
      Alice8.5Bob 29.5
      Alice8.5Sally9.5
      Alice8.5Hank6.0
      Hank4.0Bob 29.5
      Hank4.0Sally9.5
      Hank4.0Hank6.0

      所以现在,对于 2020 和 2021 年成绩表中的每个人,新表都存在表示其成绩的一行。 对于直接的查询,例如“谁的成绩最高?”,笛卡尔积的结果通常不太可行,但对于“统计学” 查询来说具有一定意义。

      1. leftjoin(grades_2020(), grades_2021(); on=:name)
      namegrade_2020grade_2021
      Sally1.09.5
      Hank4.06.0
      Bob5.0missing
      Alice8.5missing

      此处注意,“Bob” 和 “Alice” 的成绩在 2021 成绩表格中是 缺失 的,这就是为什么对应的位置是 missing 值。 rightjoin 实现了相反的操作:

      1. rightjoin(grades_2020(), grades_2021(); on=:name)

      而现在 2020 中的部分成绩是缺失的。

      注意到, leftjoin(A, B) != rightjoin(B, A),因为它们的列顺序不同。 例如,将下面的输出与之前的输出进行比较:

      1. leftjoin(grades_2021(), grades_2020(); on=:name)
      namegrade_2021grade_2020
      Sally9.51.0
      Hank6.04.0
      Bob 29.5missing

      最后讨论 semijoinantijoin

      semijoininnerjoin 更具有限制性。 它仅返回 存在于左侧 DataFrame 并同时存在于两张 DataFrame 的元素。 这看起来像是 innerjoinleftjoin 的组合。

      namegrade_2020
      Sally1.0
      Hank4.0

      semijoin 相对的是 antijoin。 它仅返回 存在于左侧 DataFrame 但不存在于右侧 DataFrame 的元素