gitee.com/quant1x/num@v0.3.2/median.go (about)

     1  package num
     2  
     3  import (
     4  	"gitee.com/quant1x/num/internal/partial"
     5  	"math"
     6  	"slices"
     7  )
     8  
     9  // Median returns median value of series.
    10  // Linear interpolation is used for odd length.
    11  //
    12  //	中间值
    13  //	TODO:未加验证,
    14  func Median[T Number](values []T) DType {
    15  	if len(values) == 0 {
    16  		return NaN()
    17  	}
    18  	if len(values) == 1 {
    19  		return DType(0)
    20  	}
    21  
    22  	if len(values)%2 == 0 {
    23  		i := len(values) / 2
    24  		return DType(values[i-1]+values[i]) / 2
    25  	}
    26  
    27  	return DType(values[len(values)/2])
    28  }
    29  
    30  func __median_go[T Number](x []T) T {
    31  	xLen := len(x)
    32  	if xLen == 0 {
    33  		return T(0)
    34  	}
    35  	if xLen == 1 {
    36  		return x[0]
    37  	}
    38  	if len(x)%2 == 1 {
    39  		x = slices.Clone(x)
    40  		i := len(x) / 2
    41  		partial.TopK(x, i+1)
    42  		return x[i]
    43  	}
    44  	q := float64(0.5)
    45  
    46  	return __quantile_go(x, T(q))
    47  }
    48  
    49  func __quantile_go[T Number](x []T, q T) T {
    50  	xLen := len(x)
    51  	if xLen == 0 {
    52  		return T(0)
    53  	}
    54  	if xLen == 1 {
    55  		return x[0]
    56  	}
    57  	if q == T(0) {
    58  		return __go_min(x)
    59  	}
    60  	if q == T(1) {
    61  		return __go_max(x)
    62  	}
    63  	x = slices.Clone(x)
    64  	f := T(len(x)-1) * q
    65  	i := int(math.Floor(float64(f)))
    66  	if float64(q) < float64(0.5) {
    67  		partial.TopK(x, i+2)
    68  		a := __go_max(x[:i+1])
    69  		b := x[i+1]
    70  		return a + (b-a)*(f-T(i))
    71  	} else {
    72  		partial.TopK(x, i+1)
    73  		a := x[i]
    74  		b := __go_min(x[i+1:])
    75  		return a + (b-a)*(f-T(i))
    76  	}
    77  }