Custom sorting for SubDataFrame
I am trying to apply a custom sorting algorithm to a bunch of sub-iris to make some graphs. Using this question , I can sort my data file with custom order:
julia> using DataFrames
julia> df = DataFrame(x = rand(10), y = rand([:low, :med, :high], 10), z = rand([:a, :b], 10))
10ร3 DataFrames.DataFrame
โ Row โ x โ y โ z โ
โโโโโโโผโโโโโโโโโโโโผโโโโโโโผโโโโค
โ 1 โ 0.436891 โ low โ b โ
โ 2 โ 0.370725 โ high โ b โ
โ 3 โ 0.521269 โ low โ b โ
โ 4 โ 0.071102 โ high โ a โ
โ 5 โ 0.969407 โ high โ a โ
โ 6 โ 0.0416023 โ med โ b โ
โ 7 โ 0.63486 โ med โ b โ
โ 8 โ 0.4352 โ high โ b โ
โ 9 โ 0.626739 โ low โ b โ
โ 10 โ 0.151149 โ low โ a โ
julia> o = [:low, :med, :high]
3-element Array{Symbol,1}:
:low
:med
:high
julia> custom_sort(x,y) = findfirst(o, x) < findfirst(o, y)
custom_sort (generic function with 1 method)
julia> sort!(df, cols=[:y], lt=custom_sort)
10ร3 DataFrames.DataFrame
โ Row โ x โ y โ z โ
โโโโโโโผโโโโโโโโโโโโผโโโโโโโผโโโโค
โ 1 โ 0.436891 โ low โ b โ
โ 2 โ 0.521269 โ low โ b โ
โ 3 โ 0.626739 โ low โ b โ
โ 4 โ 0.151149 โ low โ a โ
โ 5 โ 0.0416023 โ med โ b โ
โ 6 โ 0.63486 โ med โ b โ
โ 7 โ 0.370725 โ high โ b โ
โ 8 โ 0.071102 โ high โ a โ
โ 9 โ 0.969407 โ high โ a โ
โ 10 โ 0.4352 โ high โ b โ
and it works great. The problem is, when I do groupby()
, the custom sort is lost:
julia> groupby(df, [:y, :z])
DataFrames.GroupedDataFrame 5 groups with keys: Symbol[:y, :z]
First Group:
2ร3 DataFrames.SubDataFrame{Array{Int64,1}}
โ Row โ x โ y โ z โ
โโโโโโโผโโโโโโโโโโโผโโโโโโโผโโโโค
โ 1 โ 0.071102 โ high โ a โ
โ 2 โ 0.969407 โ high โ a โ
โฎ
Last Group:
2ร3 DataFrames.SubDataFrame{Array{Int64,1}}
โ Row โ x โ y โ z โ
โโโโโโโผโโโโโโโโโโโโผโโโโโโผโโโโค
โ 1 โ 0.0416023 โ med โ b โ
โ 2 โ 0.63486 โ med โ b โ
Is there a way to sort SubDataFrame
so that eg. the first group has y == :low
and z == a
?
source to share
groupby
uses PooledArray mechanism to split the DataFrame into groups. When creating a PooledArray from a vector, the order is not saved ... unless specified in the PooledArray constructor. It can be groupby
tricked by making the columns already in PooledArrays with the desired order. In code:
julia> df[:y] = PooledDataArray(df[:y],[:low,:med,:high])
julia> df[:z] = PooledDataArray(df[:z],[:a,:b])
julia> groupby(df, [:y, :z])
DataFrames.GroupedDataFrame 6 groups with keys: Symbol[:y, :z]
First Group:
1ร3 DataFrames.SubDataFrame{Array{Int64,1}}
โ Row โ x โ y โ z โ
โโโโโโโผโโโโโโโโโโโผโโโโโโผโโโโค
โ 1 โ 0.833255 โ low โ a โ
โฎ
Last Group:
1ร3 DataFrames.SubDataFrame{Array{Int64,1}}
โ Row โ x โ y โ z โ
โโโโโโโผโโโโโโโโโโโผโโโโโโโผโโโโค
โ 1 โ 0.604117 โ high โ b โ
This can also be automated for more columns or columns with more values โโwith the following loop:
for v in [:y,:z]
df[v] = PooledDataArray(df[v],unique(Vector(df[v])))
end
which does the same thing as the explicit assignments before.
source to share