2017-07-26 2 views
3

J'essaie d'appliquer un algorithme de tri personnalisé à un ensemble de sous-trames afin de créer des tracés. Avec l'aide de this question, je suis capable de trier mes dataframe avec un ordre personnalisé:Tri personnalisé pour SubDataFrame

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 │ 

et il fonctionne très bien. Le problème est, quand je fais alors un groupby(), le tri personnalisé se perd:

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 │ 

Est-il possible que je peux trier les SubDataFrame de sorte que par exemple. le premier groupe a y == :low et z == a?

Répondre

2

groupby tire parti des machines PooledArray pour diviser le DataFrame en groupes. Lorsque vous créez un PooledArray à partir d'un vecteur, l'ordre n'est pas conservé ... sauf si spécifié dans le constructeur PooledArray. Il est possible de tromper groupby en faisant les colonnes déjà dans PooledArrays avec un ordre désiré. Dans le 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 │ 

Cela peut également être automatisée pour plus de colonnes ou de colonnes avec plus de valeurs avec la boucle suivante:

for v in [:y,:z] 
    df[v] = PooledDataArray(df[v],unique(Vector(df[v]))) 
end 

qui fait la même chose que les affectations explicites précédemment.

+0

Vraisemblablement, je dois faire le tri personnalisé sur toutes les colonnes le nécessitant avant de faire 'PooledDataArray' avec votre boucle? – kevbonham

+0

@kevbonham Oui. En fait, il semble que l'on devrait pouvoir trier les colonnes en fonction de l'ordre désiré dans 'groupby', et regrouper les colonnes. Triez ensuite l'ensemble de données avec un ordre différent et faites le 'groupby'. –

+0

Génial, ça marche! Merci! – kevbonham