Dataframe Julia中的多列数据透视表

Dataframe Julia中的多列数据透视表,dataframe,pivot,julia,pivot-table,Dataframe,Pivot,Julia,Pivot Table,我想在julia中的数据帧上做一个透视表。从文档中,我知道我可以通过by和unstack来实现这一点。例如 julia> using DataFrames, Random julia> Random.seed!(42); julia> df = DataFrame( Step = rand(1:3, 15) |> sort, Label1 = rand('A':'B', 15) .|> Symbol,

我想在julia中的数据帧上做一个透视表。从文档中,我知道我可以通过
by
unstack
来实现这一点。例如

julia> using DataFrames, Random

julia> Random.seed!(42);

julia> df = DataFrame(
           Step = rand(1:3, 15) |> sort,
           Label1 = rand('A':'B', 15) .|> Symbol,
           Label2 = rand('Q':'R', 15) .|> Symbol
       )
15×3 DataFrame
│ Row │ Step  │ Label1 │ Label2 │
│     │ Int64 │ Symbol │ Symbol │
├─────┼───────┼────────┼────────┤
│ 1   │ 1     │ A      │ Q      │
│ 2   │ 1     │ A      │ Q      │
│ 3   │ 1     │ B      │ R      │
│ 4   │ 1     │ B      │ R      │
│ 5   │ 1     │ B      │ Q      │
│ 6   │ 2     │ B      │ Q      │
│ 7   │ 2     │ B      │ Q      │
│ 8   │ 2     │ B      │ R      │
│ 9   │ 2     │ B      │ R      │
│ 10  │ 3     │ B      │ R      │
│ 11  │ 3     │ B      │ Q      │
│ 12  │ 3     │ B      │ R      │
│ 13  │ 3     │ A      │ R      │
│ 14  │ 3     │ B      │ R      │
│ 15  │ 3     │ B      │ Q      │

julia> unstack(by(df, [:Step, :Label1, :Label2], nrow), :Label1, :nrow)
6×4 DataFrame
│ Row │ Step  │ Label2 │ A       │ B      │
│     │ Int64 │ Symbol │ Int64?  │ Int64? │
├─────┼───────┼────────┼─────────┼────────┤
│ 1   │ 1     │ Q      │ 2       │ 1      │
│ 2   │ 1     │ R      │ missing │ 2      │
│ 3   │ 2     │ Q      │ missing │ 2      │
│ 4   │ 2     │ R      │ missing │ 2      │
│ 5   │ 3     │ Q      │ missing │ 2      │
│ 6   │ 3     │ R      │ 1       │ 3      │

现在,我如何在两列(这里是Label1和Label2)上进行透视,以获得这两列元素的每个组合的行数?预期的输出将类似于

│ Row │ Step  │ AQ      │ AR      │ BQ      │ BR      │
│     │ Int64 │ Int64?  │ Int64?  │ Int64?  │ Int64?  │
├─────┼───────┼─────────┼─────────┼─────────┼─────────┤
│ 1   │ 1     │ 2       │ missing │ 1       │ 2       │
│ 3   │ 2     │ missing │ missing │ 2       │ 2       │
│ 5   │ 3     │ missing │ 1       │ 2       │ 3       │
提前谢谢!
Tim

First-
by
已被弃用(手册将在几天后更新以反映这一点),因此应写:

julia> unstack(combine(groupby(df, [:Step, :Label1, :Label2]), nrow), :Label1, :nrow)
6×4 DataFrame
│ Row │ Step  │ Label2 │ A       │ B      │
│     │ Int64 │ Symbol │ Int64?  │ Int64? │
├─────┼───────┼────────┼─────────┼────────┤
│ 1   │ 1     │ Q      │ 2       │ 1      │
│ 2   │ 1     │ R      │ missing │ 2      │
│ 3   │ 2     │ Q      │ missing │ 2      │
│ 4   │ 2     │ R      │ missing │ 2      │
│ 5   │ 3     │ Q      │ missing │ 2      │
│ 6   │ 3     │ R      │ 1       │ 3      │
但是,如果您想要行计数,我宁愿执行以下操作:

julia> gdf = groupby(df, [:Step, :Label2], sort=true);

julia> lev = unique(df.Label1)
2-element Array{Symbol,1}:
 :A
 :B

julia> combine(gdf, :Label1 .=> [x -> count(==(l), x) for l in lev] .=> lev)
6×4 DataFrame
│ Row │ Step  │ Label2 │ A     │ B     │
│     │ Int64 │ Symbol │ Int64 │ Int64 │
├─────┼───────┼────────┼───────┼───────┤
│ 1   │ 1     │ Q      │ 2     │ 1     │
│ 2   │ 1     │ R      │ 0     │ 2     │
│ 3   │ 2     │ Q      │ 0     │ 2     │
│ 4   │ 2     │ R      │ 0     │ 2     │
│ 5   │ 3     │ Q      │ 0     │ 2     │
│ 6   │ 3     │ R      │ 1     │ 3     │
因此,在缺少值的地方有
0
not
missing

此模式可概括为多个组:

julia> gdf = groupby(df, :Step, sort=true);

julia> l1 = unique(df.Label1)
2-element Array{Symbol,1}:
 :A
 :B

julia> l2 = unique(df.Label2)
2-element Array{Symbol,1}:
 :Q
 :R

julia> combine(gdf, [[:Label1, :Label2] =>
                     ((x,y) -> count(((x,y),) -> x==v1 && y==v2, zip(x,y))) =>
                     Symbol(v1, v2) for v1 in l1 for v2 in l2])
3×5 DataFrame
│ Row │ Step  │ AQ    │ AR    │ BQ    │ BR    │
│     │ Int64 │ Int64 │ Int64 │ Int64 │ Int64 │
├─────┼───────┼───────┼───────┼───────┼───────┤
│ 1   │ 1     │ 2     │ 0     │ 1     │ 2     │
│ 2   │ 2     │ 0     │ 0     │ 2     │ 2     │
│ 3   │ 3     │ 0     │ 1     │ 2     │ 3     │
使用原始代码的另一种方法是:

julia> unstack(combine(groupby(select(df, :Step, [:Label1, :Label2] => ByRow(Symbol) => :Label), [:Step, :Label]), nrow), :Label, :nrow)
3×5 DataFrame
│ Row │ Step  │ AQ      │ AR      │ BQ     │ BR     │
│     │ Int64 │ Int64?  │ Int64?  │ Int64? │ Int64? │
├─────┼───────┼─────────┼─────────┼────────┼────────┤
│ 1   │ 1     │ 2       │ missing │ 1      │ 2      │
│ 2   │ 2     │ missing │ missing │ 2      │ 2      │
│ 3   │ 3     │ missing │ 1       │ 2      │ 3      │

然而,我同意这不是很容易。此问题已在中进行跟踪并与之相关。

感谢您提供详细的答案。这正是我想要的。在你的回答中,你目前的两种方法似乎都倾向于第一种。你能快速解释一下原因吗?你只需要知道
combine
是如何编写的。第二,你需要知道两个函数。仅此而已。当我在思考如何回答您的问题时,我的第一个解决方案是使用
组合
(虽然公式看起来很难看,但我已经立即编写了它们,而且没有错误-当您掌握了
组合
的逻辑时,“minilanguage”是非常强大的)。另外请注意,对于链接Pipe.jl包非常有用。我没有在回答中使用它来避免给它增加另一层复杂性,但是使用
@pipe
宏(如R中的
%>%
),它们看起来会更干净。也可能我有偏见,我知道内部
unstack
基本上使用了
groupby
,但是在某种程度上比使用
combine
更有效。感谢您的详细解释。听起来我应该多花点时间在
combine
上。是的,在我的代码中,我也立即使用Pipe.jl:)