如何在 Deedle 中执行 "ranking"(如 SAS 或 "dense rank",如 SQL)
How to perform "ranking" (as in SAS or a "dense rank" as in SQL) in Deedle
Sas 有一个名为 rank 的过程,它根据变量的有序集合中的位置将 "rank" 分配给数据帧中的每一行,有点;但排名不仅仅是位置:必须告诉程序有多少组在排名中使用。等级实际上是该行所属的组。
在 SQL 术语中,这称为 dense ranking。
示例(包含salary变量是为了通用,但在本示例中未使用):
假设我们有这个数据框:
如果我们使用 4 个组按年龄排名,sas 会给我们这个:
如果我们按照排名的变量对数据进行排序,就更容易理解发生了什么:
现在我们可以明白为什么排名给了我们在有序集合中的位置,有点像。
排名过程非常有用和酷,但我在 Deedle 的文档中找不到如何执行它。在 Deedle 中有直接的方法吗?还是我需要创建自己的扩展?
我想我可以使用这些函数来完成:
SortRows(frame, key)
chunk size series
我写了自己的扩展:
type Frame<'TRowKey, 'TColumnKey
when 'TRowKey : equality
and 'TColumnKey : equality> with
static member denseRank column (groups:int) rankName frame =
let frameLength = Frame.countRows frame |> float
let chunkSize = frameLength / (float groups) |> Math.Ceiling |> int64
let sorted =
frame
|> Frame.sortRows column
let ranks =
Frame.getCol column frame
|> Series.map(fun k _ ->
int ((Frame.indexForKey k sorted) / chunkSize)
)
let clone = frame.Clone()
clone.AddColumn(rankName, ranks)
clone
其中 indexForKey 是另一个自定义扩展:
// index for row with key
// index starting at 0
static member indexForKey (key:'K) (frame:Frame<'K,_>) : int64 =
frame.RowIndex.Locate key
|> frame.RowIndex.AddressOperations.OffsetOf
我尝试了这个其他定义,希望它 运行 更快。它稍微快一点,但不是很多;欢迎对性能问题提出任何意见:
static member denseRank column (groups:int) rankName frame =
let frameLength = Frame.countRows frame
let chunkSize = (float frameLength) / (float groups) |> Math.Ceiling
let sorted =
frame
|> Frame.sortRows column
let sortedKeys = Frame.getRowKeys sorted
let ranksArr = Array.zeroCreate frameLength
sortedKeys
|> Seq.iteri (fun index _ -> ranksArr.[index] <- index / (int chunkSize))
let ranks = Series(sortedKeys, ranksArr)
let clone = frame.Clone()
clone.AddColumn(rankName, ranks)
clone
Sas 有一个名为 rank 的过程,它根据变量的有序集合中的位置将 "rank" 分配给数据帧中的每一行,有点;但排名不仅仅是位置:必须告诉程序有多少组在排名中使用。等级实际上是该行所属的组。
在 SQL 术语中,这称为 dense ranking。
示例(包含salary变量是为了通用,但在本示例中未使用):
假设我们有这个数据框:
如果我们使用 4 个组按年龄排名,sas 会给我们这个:
如果我们按照排名的变量对数据进行排序,就更容易理解发生了什么:
现在我们可以明白为什么排名给了我们在有序集合中的位置,有点像。
排名过程非常有用和酷,但我在 Deedle 的文档中找不到如何执行它。在 Deedle 中有直接的方法吗?还是我需要创建自己的扩展?
我想我可以使用这些函数来完成:
SortRows(frame, key)
chunk size series
我写了自己的扩展:
type Frame<'TRowKey, 'TColumnKey
when 'TRowKey : equality
and 'TColumnKey : equality> with
static member denseRank column (groups:int) rankName frame =
let frameLength = Frame.countRows frame |> float
let chunkSize = frameLength / (float groups) |> Math.Ceiling |> int64
let sorted =
frame
|> Frame.sortRows column
let ranks =
Frame.getCol column frame
|> Series.map(fun k _ ->
int ((Frame.indexForKey k sorted) / chunkSize)
)
let clone = frame.Clone()
clone.AddColumn(rankName, ranks)
clone
其中 indexForKey 是另一个自定义扩展:
// index for row with key
// index starting at 0
static member indexForKey (key:'K) (frame:Frame<'K,_>) : int64 =
frame.RowIndex.Locate key
|> frame.RowIndex.AddressOperations.OffsetOf
我尝试了这个其他定义,希望它 运行 更快。它稍微快一点,但不是很多;欢迎对性能问题提出任何意见:
static member denseRank column (groups:int) rankName frame =
let frameLength = Frame.countRows frame
let chunkSize = (float frameLength) / (float groups) |> Math.Ceiling
let sorted =
frame
|> Frame.sortRows column
let sortedKeys = Frame.getRowKeys sorted
let ranksArr = Array.zeroCreate frameLength
sortedKeys
|> Seq.iteri (fun index _ -> ranksArr.[index] <- index / (int chunkSize))
let ranks = Series(sortedKeys, ranksArr)
let clone = frame.Clone()
clone.AddColumn(rankName, ranks)
clone