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

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

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

public class CumfreqRes {
    public let cumcount: Vector<Float64>
    public let lowerlimit: Float64
    public let binsize: Float64

    public init(cumcount: Vector<Float64>, lowerlimit: Float64, binsize: Float64) {
        this.cumcount = cumcount
        this.lowerlimit = lowerlimit
        this.binsize = binsize
    }
}



public func cumfreq(data: Vector<Float64>, limits: (Float64, Float64), weights: Vector<Float64>, numbins!: Int64 = 10): CumfreqRes {
    
    let cumcount = vector<Float64>(numbins, 0.0)
    let lowerlimit = limits[0]

    let binsize = (limits[1] - lowerlimit) / Float64(numbins)
    let datasec = vector<Float64>(numbins + 1, 0.0)
    for(i in 0..(numbins + 1)) {
        datasec[i] = lowerlimit + Float64(i) * binsize
    }

    let n = data.size()
    for(i in 0..n) {
        for(j in 0..numbins) {
            if(data[i] >= datasec[j] && data[i] < datasec[j + 1]) {
                cumcount[j] += weights[i]
                break
            } else if(j == (numbins - 1) && data[i] == datasec[j + 1]) {
                cumcount[j] += weights[i]
                break
            }
        }
    }


    for(i in 1..numbins) {
        cumcount[i] = cumcount[i - 1] + cumcount[i]
    }

    return CumfreqRes(cumcount, lowerlimit, binsize)
}



public func cumfreq(data: Vector<Float64>, numbins!: Int64 = 10): CumfreqRes {
    
    let l = min(data)
    let r = max(data)
    let s = 0.5 * (r - l) / Float64(numbins - 1)
    let limits = (l - s, r + s)

    let n = data.size()
    let weights = vector<Float64>(n, 1.0)
    
    return cumfreq(data, limits, weights, numbins: numbins)
}


public func cumfreq(data: Vector<Float64>, limits: (Float64, Float64), numbins!: Int64 = 10): CumfreqRes {
    
    let n = data.size()
    let weights = vector<Float64>(n, 1.0)
    
    return cumfreq(data, limits, weights, numbins: numbins)
}


public func cumfreq(data: Vector<Float64>, weights: Vector<Float64>, numbins!: Int64 = 10): CumfreqRes {
    
    let l = min(data)
    let r = max(data)
    let s = 0.5 * (r - l) / Float64(numbins - 1)
    let limits = (l - s, r + s)
    
    return cumfreq(data, limits, weights, numbins: numbins)
}


@Test
public class TestCumFreq {
    @TestCase
    func testCumfreq(): Unit {
        let data = vector([1.0, 3.0, 27.0, 2.0, 5.0, 13.0])
        let res = cumfreq(data, numbins: 4)
        @Assert(approxEqual(res.cumcount,    vector([4.0,  5.0,  5.0,  6.0])))
        @Assert(approxEqual(res.lowerlimit,  -3.33333333333,    atol:1e-6))
        @Assert(approxEqual(res.binsize,     8.66666666667,     atol:1e-6))
    }
}