diff --git a/algorithms/aggregates.go b/algorithms/aggregates.go new file mode 100644 index 0000000000000000000000000000000000000000..cad707a67ffef85476683e04fe8f149f33a097e9 --- /dev/null +++ b/algorithms/aggregates.go @@ -0,0 +1,77 @@ +package algorithms + +type Number interface { + ~int64 | float64 +} + +func Sum_Go[T Number](x []T) T { + sum := T(0) + for i := 0; i < len(x); i++ { + sum += x[i] + } + return sum +} + +func CumSum_Go[T Number](x []T) { + sum := T(0) + for i := 0; i < len(x); i++ { + sum += x[i] + x[i] = sum + } +} + +func Prod_Go[T Number](x []T) T { + prod := T(1) + for i := 0; i < len(x); i++ { + prod *= x[i] + } + return prod +} + +func CumProd_Go[T Number](x []T) { + prod := T(1) + for i := 0; i < len(x); i++ { + prod *= x[i] + x[i] = prod + } +} + +func Mean_Go[T Number](x []T) T { + return Sum_Go(x) / T(len(x)) +} + +//func Median_Go[T Number](x []T) T { +// if len(x)%2 == 1 { +// x = slices.Clone(x) +// i := len(x) / 2 +// partial.TopK(x, i+1) +// return x[i] +// } +// return Quantile_Go(x, T(0.5)) +//} +// +//func Quantile_Go[T Number](x []T, q T) T { +// if len(x) == 1 { +// return x[0] +// } +// if q == T(0) { +// return Min_Go(x) +// } +// if q == T(1) { +// return Max_Go(x) +// } +// x = slices.Clone(x) +// f := T(len(x)-1) * q +// i := int(math.Floor(float64(f))) +// if q < 0.5 { +// partial.TopK(x, i+2) +// a := Max_Go(x[:i+1]) +// b := x[i+1] +// return a + (b-a)*(f-T(i)) +// } else { +// partial.TopK(x, i+1) +// a := x[i] +// b := Min_Go(x[i+1:]) +// return a + (b-a)*(f-T(i)) +// } +//} diff --git a/algorithms/max.go b/algorithms/max.go new file mode 100644 index 0000000000000000000000000000000000000000..478199fca1ded0aa83695106c37abe22cca946b5 --- /dev/null +++ b/algorithms/max.go @@ -0,0 +1,39 @@ +package algorithms + +func Max_Go[T Number](x []T) T { + max := x[0] + for _, v := range x[1:] { + if v > max { + max = v + } + } + return max +} + +func ArgMax_Go[T Number](x []T) int { + max := x[0] + idx := 0 + for i, v := range x[1:] { + if v > max { + max = v + idx = 1 + i + } + } + return idx +} + +func Maximum_Go[T Number](x, y []T) { + for i := 0; i < len(x); i++ { + if y[i] > x[i] { + x[i] = y[i] + } + } +} + +func MaximumNumber_Go[T Number](x []T, a T) { + for i := 0; i < len(x); i++ { + if a > x[i] { + x[i] = a + } + } +} diff --git a/algorithms/min.go b/algorithms/min.go new file mode 100644 index 0000000000000000000000000000000000000000..ca467455968f258791b5b0ffe1eabb3ff82b8d10 --- /dev/null +++ b/algorithms/min.go @@ -0,0 +1,39 @@ +package algorithms + +func Min_Go[T Number](x []T) T { + min := x[0] + for _, v := range x[1:] { + if v < min { + min = v + } + } + return min +} + +func ArgMin_Go[T Number](x []T) int { + min := x[0] + idx := 0 + for i, v := range x[1:] { + if v < min { + min = v + idx = 1 + i + } + } + return idx +} + +func Minimum_Go[T Number](x, y []T) { + for i := 0; i < len(x); i++ { + if y[i] < x[i] { + x[i] = y[i] + } + } +} + +func MinimumNumber_Go[T Number](x []T, a T) { + for i := 0; i < len(x); i++ { + if a < x[i] { + x[i] = a + } + } +} diff --git a/series_float64.go b/series_float64.go index a715b9b6a2b05cec67fd0ac17477ef5a0893c945..ba7efe370f373ad6d569842debac544a9e3550aa 100644 --- a/series_float64.go +++ b/series_float64.go @@ -88,39 +88,39 @@ func (self *SeriesFloat64) assign(idx, size int, f float64) { } } -func (s *SeriesFloat64) Name() string { - return s.name +func (self *SeriesFloat64) Name() string { + return self.name } -func (s *SeriesFloat64) Rename(n string) { - s.lock.RLock() - defer s.lock.RUnlock() - s.name = n +func (self *SeriesFloat64) Rename(n string) { + self.lock.RLock() + defer self.lock.RUnlock() + self.name = n } // Type returns the type of data the series holds. -func (s *SeriesFloat64) Type() Type { +func (self *SeriesFloat64) Type() Type { return SERIES_TYPE_FLOAT } -func (s *SeriesFloat64) Len() int { - s.lock.RLock() - defer s.lock.RUnlock() - return len(s.Data) +func (self *SeriesFloat64) Len() int { + self.lock.RLock() + defer self.lock.RUnlock() + return len(self.Data) } -func (s *SeriesFloat64) Shift(periods int) *Series { +func (self *SeriesFloat64) Shift(periods int) *Series { var d Series - d = clone.Clone(s).(Series) + d = clone.Clone(self).(Series) return Shift[float64](&d, periods, func() float64 { return Nil2Float }) } // deprecated: 不推荐使用 -func (s *SeriesFloat64) oldShift(periods int) *Series { +func (self *SeriesFloat64) oldShift(periods int) *Series { var d Series - d = clone.Clone(s).(Series) + d = clone.Clone(self).(Series) if periods == 0 { return &d } @@ -150,66 +150,69 @@ func (s *SeriesFloat64) oldShift(periods int) *Series { } for i := range naVals { - naVals[i] = algorithms.NaN() + naVals[i] = NaN() } return &d } -func (s *SeriesFloat64) Values() any { - return s.Data +func (self *SeriesFloat64) Values() any { + return self.Data } -func (s *SeriesFloat64) Repeat(x any, repeats int) *Series { +func (self *SeriesFloat64) Repeat(x any, repeats int) *Series { a := AnyToFloat64(x) //data := avx2.Repeat(a, repeats) data := Repeat(a, repeats) var d Series - d = NewSeriesFloat64(s.name, data) + d = NewSeriesFloat64(self.name, data) return &d } // Empty returns an empty Series of the same type -func (s *SeriesFloat64) Empty() Series { - return NewSeriesFloat64(s.name, []float64{}) +func (self *SeriesFloat64) Empty() Series { + return NewSeriesFloat64(self.name, []float64{}) } // Records returns the elements of a Series as a []string -func (s *SeriesFloat64) Records() []string { - ret := make([]string, s.Len()) - for i := 0; i < s.Len(); i++ { - //e := s.elements.Elem(i) - e := s.Data[i] +func (self *SeriesFloat64) Records() []string { + ret := make([]string, self.Len()) + for i := 0; i < self.Len(); i++ { + //e := self.elements.Elem(i) + e := self.Data[i] ret[i] = float2String(e) } return ret } -func (s *SeriesFloat64) Subset(start, end int) *Series { +func (self *SeriesFloat64) Subset(start, end int) *Series { var d Series - d = NewSeriesFloat64(s.name, s.Data[start:end]) + d = NewSeriesFloat64(self.name, self.Data[start:end]) return &d } // Rolling creates new RollingWindow -func (s *SeriesFloat64) Rolling(window int) RollingWindow { +func (self *SeriesFloat64) Rolling(window int) RollingWindow { return RollingWindow{ window: window, - series: s, + series: self, } } // Mean calculates the average value of a series -func (s *SeriesFloat64) Mean() float64 { - if s.Len() < 1 { - return algorithms.NaN() +func (self *SeriesFloat64) Mean() float64 { + if self.Len() < 1 { + return NaN() } - stdDev := avx2.Mean(s.Data) + stdDev := avx2.Mean(self.Data) return stdDev } -func (s *SeriesFloat64) StdDev() float64 { - values := s.Values().([]float64) +func (self *SeriesFloat64) StdDev() float64 { + if self.Len() < 1 { + return NaN() + } + values := self.Values().([]float64) stdDev := stat.StdDev(values, nil) return stdDev } diff --git a/series_int64.go b/series_int64.go index 87e3f7202a805e73f8e5d9b4b7410d4f432d54f7..f1f80ea9e51b3a67cd8f80fc3a1c015fb1eef1a8 100644 --- a/series_int64.go +++ b/series_int64.go @@ -77,8 +77,8 @@ func NewSeriesInt64(name string, vals ...interface{}) *SeriesInt64 { } func (self *SeriesInt64) assign(idx, size int, n int64) { - //if StringIsNaN(s) { - // s = StringNaN + //if StringIsNaN(self) { + // self = StringNaN // self.nilCount++ //} if idx < size { @@ -88,45 +88,45 @@ func (self *SeriesInt64) assign(idx, size int, n int64) { } } -func (s *SeriesInt64) Name() string { - return s.name +func (self *SeriesInt64) Name() string { + return self.name } -func (s *SeriesInt64) Rename(n string) { - s.name = n +func (self *SeriesInt64) Rename(n string) { + self.name = n } -func (s *SeriesInt64) Type() Type { +func (self *SeriesInt64) Type() Type { return SERIES_TYPE_INT } -func (s *SeriesInt64) Shift(periods int) *Series { +func (self *SeriesInt64) Shift(periods int) *Series { var d Series - d = clone.Clone(s).(Series) + d = clone.Clone(self).(Series) return Shift[int64](&d, periods, func() int64 { return IntNaN }) } -func (s *SeriesInt64) Len() int { - s.lock.RLock() - defer s.lock.RUnlock() - return len(s.Data) +func (self *SeriesInt64) Len() int { + self.lock.RLock() + defer self.lock.RUnlock() + return len(self.Data) } -func (s *SeriesInt64) Values() any { - return s.Data +func (self *SeriesInt64) Values() any { + return self.Data } -func (s *SeriesInt64) Repeat(x any, repeats int) *Series { +func (self *SeriesInt64) Repeat(x any, repeats int) *Series { a := AnyToFloat64(x) data := Repeat(a, repeats) var d Series - d = NewSeriesInt64(s.name, data) + d = NewSeriesInt64(self.name, data) return &d } -func (s *SeriesInt64) Rolling(window int) RollingWindow { +func (self *SeriesInt64) Rolling(window int) RollingWindow { //TODO implement me panic("implement me") } @@ -136,28 +136,39 @@ func (self *SeriesInt64) Empty() Series { } // Records returns the elements of a Series as a []string -func (s *SeriesInt64) Records() []string { - ret := make([]string, s.Len()) - for i := 0; i < s.Len(); i++ { - e := s.Data[i] +func (self *SeriesInt64) Records() []string { + ret := make([]string, self.Len()) + for i := 0; i < self.Len(); i++ { + e := self.Data[i] ret[i] = int2String(e) } return ret } -func (s *SeriesInt64) Subset(start, end int) *Series { +func (self *SeriesInt64) Subset(start, end int) *Series { var d Series - d = NewSeriesInt64(s.name, s.Data[start:end]) + d = NewSeriesInt64(self.name, self.Data[start:end]) return &d } -func (s *SeriesInt64) Mean() float64 { - //TODO implement me - panic("implement me") +func (self *SeriesInt64) Mean() float64 { + if self.Len() < 1 { + return NaN() + } + stdDev := Mean(self.Data) + return stdDev } -func (s *SeriesInt64) StdDev() float64 { - values := s.Values().([]float64) - stdDev := stat.StdDev(values, nil) +func (self *SeriesInt64) StdDev() float64 { + if self.Len() < 1 { + return NaN() + } + // TODO: 每次都需要转换一次, 有没有什么好办法优化? + d := make([]float64, self.Len()) + for i := 0; i < len(d); i++ { + d[i] = float64(self.Data[i]) + } + //values := self.Values().([]int64) + stdDev := stat.StdDev(d, nil) return stdDev } diff --git a/series_number.go b/series_number.go new file mode 100644 index 0000000000000000000000000000000000000000..78e42f8f4eae54923f33a4b2b45aaa11f4871e61 --- /dev/null +++ b/series_number.go @@ -0,0 +1,9 @@ +package pandas + +import "gitee.com/quant1x/pandas/algorithms" + +// Mean gonum.org/v1/gonum/stat不支持整型, 每次都要转换有点难受啊 +func Mean[T algorithms.Number](x []T) float64 { + d := algorithms.Mean_Go(x) + return float64(d) +} diff --git a/series_xstring.go b/series_xstring.go index dbb98439f51075ec00024c8e9a370d911b8d04ac..e51c95901bf32ae60716a11d7fd764c5791c7e40 100644 --- a/series_xstring.go +++ b/series_xstring.go @@ -5,6 +5,7 @@ import ( "reflect" ) +// SeriesString 字符串类型序列 type SeriesString struct { SeriesFrame Data []string