eaebec39创建于 2024年10月24日历史提交
package scientific.stats.frequencystat

import std.math.*
import std.unittest.*
import std.unittest.testmacro.*

import scientific.numbers.*
import scientific.linear.*

public func percentileofscore(data: Vector<Float64>, score: Float64, kind!: String = "rank"): Float64 {
    var res = 0.0
    let n = data.size()
    var m1 = 0
    var m2 = 0
    var m = 0.0
    
    if (n == 0) {
        return Float64.NaN
    }

    for (i in 0..n) {
        if (data[i] <= score) {
            m1 += 1
        }
        if (data[i] < score) {
            m2 += 1
        }
    }

    if (kind == "rank") {
        m = Float64(m2 + 1 + m1) * 0.5
    } else if (kind == "weak") {
        m = Float64(m1)
    } else if (kind == "strict") {
        m = Float64(m2)
    } else if (kind == "mean") {
        m = Float64(m2 + m1) * 0.5
    } 

    res = m / Float64(n) * 100.0
    return res 
}

public func percentileofscore(data: Vector<Float64>, score: Vector<Float64>, kind!: String = "rank"): Vector<Float64> {    
    let len = score.size()
    var res = vector<Float64>(len, 0.0)
    
    if (data.size() == 0) {
        return vector<Float64>(len, Float64.NaN)
    }

    for (i in 0..len) {
        res[i] = percentileofscore(data, score[i], kind: kind)
    }
    return res 
}

@Test
public class TestPercentileScore {
    @TestCase
    func testPercentileofscore(): Unit {
        let data = vector<Float64>([1.0, 2.0, 3.0, 3.0, 4.0])
        let res1 = percentileofscore(data, 3.0)
        @Assert(approxEqual(res1,     70.0,     atol:0.1))
        let res2 = percentileofscore(data, 3.0, kind: "strict")
        @Assert(approxEqual(res2,     40.0,     atol:0.1))
        let res3 = percentileofscore(data, 3.0, kind: "weak")
        @Assert(approxEqual(res3,     80.0,     atol:0.1))
        let res4 = percentileofscore(data, 3.0, kind: "mean")
        @Assert(approxEqual(res4,     60.0,     atol:0.1))
    }
}