【问题标题】:F# - Replace Float With Label Based On Percentile ComparisonF# - 基于百分位比较用标签替换浮点数
【发布时间】:2018-10-31 03:04:58
【问题描述】:

我需要根据与 prcntls 中的百分位数的比较,将 tmp 中的值映射到 tmpRplcd 中的标签,但是 Array .map2 行失败,因为数组的长度不同。

module SOQN = 
   open System
   open MathNet.Numerics.Statistics
   let tmp = [| 13.0; 17.0; 23.0; 11.0; 11.0; 13.0; 31.0; 
                19.0; 47.0; 29.0; 29.0; 19.0; 43.0; 37.0 |]
   let tmpPrcntls = 
      tmp
      |> Array.sort
   let lbls = [| "p0"; "p1"; "p2"; "p3"; "p4";"p5" |]
   let prcntls = [| Statistics.Percentile(tmpPrcntls,0)   // 11.0
                    Statistics.Percentile(tmpPrcntls,20)  // 13.0
                    Statistics.Percentile(tmpPrcntls,40)  // 19.0
                    Statistics.Percentile(tmpPrcntls,60)  // 28.6
                    Statistics.Percentile(tmpPrcntls,80)  // 35.8
                    Statistics.Percentile(tmpPrcntls,100) // 47.0
                 |]
   let lkpTbl = Map(Array.zip prcntls lbls)
   let tmpRplcd:string[] = 
      tmp
      |> Array.map2 (fun x y -> if x <= y then lkpTbl.[y] else "") prcntls
   let main = 
      printfn ""
      printfn "Percentile Test"
      printfn ""
      printfn "tmpPrcntls: %A" tmpPrcntls
      printfn "prcntls:%A" prcntls
      printfn "tmpRplcd:%A" tmpRplcd
      0
   [<EntryPoint>]
   main
   |> ignore

 // Expected Result:
 // tmpRplcd = [| "p1"; "p2"; "p3"; "p0"; "p0"; "p1"; "p4"; 
 //               "p2"; "p5"; "p4"; "p4"; "p2"; "p5"; "p5" |]   

我哪里错了?

【问题讨论】:

    标签: arrays dictionary f# percentile


    【解决方案1】:

    以下是您打算对 F# 程序执行的操作。

    我从http://www.dummies.com/education/math/statistics/how-to-calculate-percentiles-in-statistics/ 提出了一个百分位数计算的实现,它显示在下面的统计模块中。

    namespace FSharpBasics
    
    module Statistics =
        let percentile p (array: float[]) =
            let threshold = (float p / 100.0) * float (array |> Array.length)
            let thresholdCeiling = int (System.Math.Ceiling threshold)
            let thresholdInteger = int (threshold)
            array
                |> Array.sort
                |> Array.skip (thresholdCeiling - 1)
                |> Array.truncate (if thresholdInteger = thresholdCeiling then 2 else 1)
                |> Array.average
    
    module PercentileTest =
        open System
    
        let tmp = [| 13.0; 17.0; 23.0; 11.0; 11.0; 13.0; 31.0;
                     19.0; 47.0; 29.0; 29.0; 19.0; 43.0; 37.0 |]
    
        let lbls = 
            [| for n in 0..20..100 -> "p" + string (n / 20) |]
    
        let prcntls = 
            [| for n in 0..20..100 -> Statistics.percentile n tmp |]
    
        let tmpPrcntls = 
            tmp |> Array.sort
    
        let lkpTbl = 
            Array.zip prcntls lbls
    
        let tmpRplcd : string[] =
            tmp
            |> Array.map (fun x -> 
                    lkpTbl 
                    |> Array.filter (fun (prcntl, lbl) -> prcntl <= x)
                    |> Array.last
                    |> snd)
    
        [<EntryPoint>]
        let main argv =
            printfn ""
            printfn "Percentile Test"
            printfn ""
            printfn "tmp: %A" tmp
            printfn "tmpPrcntls: %A" tmpPrcntls
            printfn "prcntls: %A" prcntls
            printfn "tmpRplcd: %A" tmpRplcd
            System.Console.ReadKey() |> ignore
            0 // return an integer exit code
    (*---- output ----
    
    Percentile Test
    
    tmp: [|13.0; 17.0; 23.0; 11.0; 11.0; 13.0; 31.0; 19.0; 47.0; 29.0; 29.0; 19.0; 43.0;
      37.0|]
    tmpPrcntls: [|11.0; 11.0; 13.0; 13.0; 17.0; 19.0; 19.0; 23.0; 29.0; 29.0; 31.0; 37.0; 43.0;
      47.0|]
    prcntls: [|11.0; 13.0; 19.0; 29.0; 37.0; 47.0|]
    tmpRplcd: [|"p1"; "p1"; "p2"; "p0"; "p0"; "p1"; "p3"; "p2"; "p5"; "p3"; "p3"; "p2"; "p4";
     "p4"|]
    ---- ----*)
    

    【讨论】:

    • @MarceloUchimura。谢谢你的详细回复。不幸的是,我的预期输出与程序生成的实际输出不匹配://预期结果:// tmpRplcd = [| “p1”; “p2”; “p3”; “p0”; “p0”; “p1”; “p4”; “p2”; “p5”; “p4”; “p4”; “p2”; “p5”; "p5" |] // 实际结果: // tmpRplcd: [| “p1”; “p1”; “p2”; “p0”; “p0”; “p1”; “p3”; “p2”; “p5”; “p3”; “p3”; “p2”; “p4”; "p4"|]
    • @matekus:不匹配可能是由于使用了不同的统计包。恐怕 tmp 中的最后一个值 37.0 不能在 p5 百分位数中,因为它小于 47.0。
    • @MarceloUchimura,37.0 应该翻译成“p5”。
    • @matekus,恐怕 tmp 中唯一属于 p5 的值是 47.0,这是列表中所有值中的最大值。
    【解决方案2】:

    我认为您对 map2 的使用是错误的 - map2 函数压缩两个数组,然后将给定函数应用于压缩数组。

    根据您的问题,我的猜测是您实际上想做其他事情。对于每个输入,您都希望遍历所有百分位数并找到第一个百分位数,使得该值大于(或小于?)该百分位数。为此,您需要将map2 替换为以下内容:

    let tmpRplcd:string[] = 
      tmp 
      |> Array.map (fun y -> 
        prcntls |> Array.tryPick (fun x ->
          if x <= y then Some(lkpTbl.[x]) else None))
      |> Array.map (fun v -> defaultArg v "")
    

    我没有合适的版本来尝试这个,但我认为这应该可以满足您的需要(我只是不确定您是否需要 x &lt;= y 或相反!)

    【讨论】:

    • 优秀的@TomasPetricek。 x >= y 是正确的选项。再次感谢您的明确解释和您的专业知识。
    猜你喜欢
    • 2022-08-03
    • 2011-02-04
    • 2021-02-25
    • 2021-05-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-10
    • 1970-01-01
    相关资源
    最近更新 更多