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

?

+3


source to share


1 answer


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.

+2


source







All Articles