From 08bb92281db78dfb1d081c16256f4a00ede41c32 Mon Sep 17 00:00:00 2001 From: wangfeng Date: Thu, 9 Feb 2023 10:23:08 +0800 Subject: [PATCH 01/19] =?UTF-8?q?=E8=B0=83=E6=95=B4alpha=E5=B8=B8=E9=87=8F?= =?UTF-8?q?=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- generic_ewm.go | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/generic_ewm.go b/generic_ewm.go index 3ad3e36..7503b90 100644 --- a/generic_ewm.go +++ b/generic_ewm.go @@ -9,21 +9,21 @@ type AlphaType int // https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.ewm.html const ( - // AlphaNil Specify smoothing factor α directly, 0<α≤1. - AlphaNil AlphaType = iota + // AlphaAlpha Specify smoothing factor α directly, 0<α≤1. + AlphaAlpha AlphaType = iota // AlphaCom Specify decay in terms of center of mass, α=1/(1+com), for com ≥ 0. AlphaCom // AlphaSpan Specify decay in terms of span, α=2/(span+1), for span ≥ 1. AlphaSpan - // AlphaHalflife Specify decay in terms of half-life, α=1−exp(−ln(2)/halflife), for halflife > 0. - AlphaHalflife + // AlphaHalfLife Specify decay in terms of half-life, α=1−exp(−ln(2)/halflife), for halflife > 0. + AlphaHalfLife ) // EW (Factor) 指数加权(EW)计算Alpha 结构属性非0即为有效启动同名算法 type EW struct { Com stat.DType // 根据质心指定衰减 Span stat.DType // 根据跨度指定衰减 - Halflife stat.DType // 根据半衰期指定衰减 + HalfLife stat.DType // 根据半衰期指定衰减 Alpha stat.DType // 直接指定的平滑因子α Adjust bool // 除以期初的衰减调整系数以核算 相对权重的不平衡(将 EWMA 视为移动平均线) IgnoreNA bool // 计算权重时忽略缺失值 @@ -44,7 +44,7 @@ type ExponentialMovingWindow struct { // EWM provides exponential weighted calculations. func (s *NDFrame) EWM(alpha EW) ExponentialMovingWindow { - atype := AlphaNil + atype := AlphaAlpha param := 0.00 adjust := alpha.Adjust ignoreNA := alpha.IgnoreNA @@ -54,11 +54,11 @@ func (s *NDFrame) EWM(alpha EW) ExponentialMovingWindow { } else if alpha.Span != 0 { atype = AlphaSpan param = alpha.Span - } else if alpha.Halflife != 0 { - atype = AlphaHalflife - param = alpha.Halflife + } else if alpha.HalfLife != 0 { + atype = AlphaHalfLife + param = alpha.HalfLife } else { - atype = AlphaNil + atype = AlphaAlpha param = alpha.Alpha } @@ -77,7 +77,7 @@ func (w ExponentialMovingWindow) Mean() Series { var alpha stat.DType switch w.atype { - case AlphaNil: + case AlphaAlpha: if w.param <= 0 { panic("alpha param must be > 0") } @@ -95,7 +95,7 @@ func (w ExponentialMovingWindow) Mean() Series { } alpha = 2 / (w.param + 1) - case AlphaHalflife: + case AlphaHalfLife: if w.param <= 0 { panic("halflife param must be > 0") } -- Gitee From 03cc267f1335227af17d37ea7585ac13b8464fe8 Mon Sep 17 00:00:00 2001 From: wangfeng Date: Thu, 9 Feb 2023 10:50:53 +0800 Subject: [PATCH 02/19] =?UTF-8?q?=E5=A2=9E=E5=8A=A0string=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E7=9A=84=E5=A4=84=E7=90=86=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- stat/type_string.go | 97 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 stat/type_string.go diff --git a/stat/type_string.go b/stat/type_string.go new file mode 100644 index 0000000..c4d63b8 --- /dev/null +++ b/stat/type_string.go @@ -0,0 +1,97 @@ +package stat + +import ( + "github.com/mymmsc/gox/logger" + "strconv" + "strings" +) + +const ( + StringNaN = "NaN" // 字符串NaN + Nil2String = "NaN" // nil指针转string + True2String = "true" // true转string + False2String = "false" // false转string +) + +var ( + // PossibleNaOfString 有可能出现的NaN字符串的全部选项 + PossibleNaOfString = []string{"NA", "NaN", "nan", ""} +) + +// AnyToString any转string +func AnyToString(v any) string { + switch val := v.(type) { + case nil: + return Nil2String + case *bool: + if val == nil { + return Nil2String + } + if *val == true { + return True2String + } else { + return False2String + } + case bool: + if val == true { + return True2String + } else { + return False2String + } + case *string: + if val == nil { + return Nil2String + } + return []string{*val}[0] + case string: + return val + case *float64: + if val == nil { + return Nil2String + } + return strconv.FormatFloat(*val, 'G', -1, 64) + case float64: + return strconv.FormatFloat(val, 'G', -1, 64) + case *float32: + if val == nil { + return Nil2String + } + return strconv.FormatFloat(float64(*val), 'G', -1, 64) + case float32: + return strconv.FormatFloat(float64(val), 'G', -1, 64) + case *int64: + if val == nil { + return Nil2String + } + return strconv.FormatInt(*val, 10) + case int64: + return strconv.FormatInt(val, 10) + case *int: + if val == nil { + return Nil2String + } + return strconv.Itoa(*val) + case int: + return strconv.Itoa(val) + case *int32: + if val == nil { + return Nil2String + } + return strconv.FormatInt(int64(*val), 10) + case int32: + return strconv.FormatInt(int64(val), 10) + default: + logger.Errorf("%s, error=The type is not recognized\n", v) + _ = v.(string) // Intentionally panic + return Nil2String + } +} + +// StringIsNaN 判断字符串是否NaN +func StringIsNaN(s string) bool { + s = strings.TrimSpace(s) + if strings.ToLower(s) == "nan" { + return true + } + return false +} -- Gitee From e4de28d1d1d37271e5a569a27cae21645a0fb487 Mon Sep 17 00:00:00 2001 From: wangfeng Date: Thu, 9 Feb 2023 10:51:21 +0800 Subject: [PATCH 03/19] =?UTF-8?q?=E5=A2=9E=E5=8A=A0int64=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E7=9A=84=E5=A4=84=E7=90=86=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- stat/type_int64.go | 58 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/stat/type_int64.go b/stat/type_int64.go index 741fd8d..f23cfed 100644 --- a/stat/type_int64.go +++ b/stat/type_int64.go @@ -1,6 +1,11 @@ package stat -import "math" +import ( + "fmt" + "github.com/mymmsc/gox/logger" + "math" + "strconv" +) const ( MaxInt64 = int64(math.MaxInt64) @@ -13,3 +18,54 @@ const ( StringTrue2Int64 = int64(1) // 字符串true转int64 StringFalse2Int64 = int64(0) // 字符串false转int64 ) + +// ParseInt64 解析int字符串, 尝试解析10进制和16进制 +func ParseInt64(s string, v any) int64 { + defer func() { + // 解析失败以后输出日志, 以备检查 + if err := recover(); err != nil { + logger.Errorf("ParseInt64 %+v, error=%+v\n", v, err) + } + }() + if IsEmpty(s) { + return Nil2Int64 + } + if isTrue(s) { + return StringTrue2Int64 + } else if isFalse(s) { + return StringFalse2Int64 + } + i, err := strconv.ParseInt(s, 10, 64) + if err == nil { + return i + } + // 解析失败继续解析16进制 + i, err = strconv.ParseInt(s, 16, 64) + if err == nil { + return i + } + logger.Errorf("%s, error=%+v\n", s, err) + if IgnoreParseExceptions { + i = StringBad2Int64 + } else { + _ = v.(int64) // Intentionally panic + } + return i +} + +func int64ToString(v int64) string { + if Float64IsNaN(float64(v)) { + return StringNaN + } + return fmt.Sprint(v) +} + +// AnyToInt64 any转换int64 +func AnyToInt64(v any) int64 { + if vv, ok := extraceValueFromPointer(v); ok { + v = vv + } + + f := valueToNumber[int64](v, Nil2Int64, boolToInt64, ParseInt64) + return f +} -- Gitee From 76b734e96588aaa051254c5acd5ce79db49568be Mon Sep 17 00:00:00 2001 From: wangfeng Date: Thu, 9 Feb 2023 10:51:50 +0800 Subject: [PATCH 04/19] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=B3=9B=E5=9E=8B?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E7=9A=84=E6=8E=A5=E5=8F=A3=E5=AE=9A=E4=B9=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- stat/type.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/stat/type.go b/stat/type.go index da0d0e3..18870a8 100644 --- a/stat/type.go +++ b/stat/type.go @@ -6,6 +6,11 @@ import ( "reflect" ) +// GenericType Series支持的所有类型 +type GenericType interface { + ~bool | ~int32 | ~int64 | ~int | ~float32 | ~float64 | ~string +} + type Float interface { ~float32 | ~float64 } -- Gitee From ecf151deb29d6fe38d8524bbca65c2627e3387cf Mon Sep 17 00:00:00 2001 From: wangfeng Date: Thu, 9 Feb 2023 11:21:48 +0800 Subject: [PATCH 05/19] =?UTF-8?q?=E6=96=B0=E5=A2=9Efill=E5=87=BD=E6=95=B0,?= =?UTF-8?q?=20=E6=94=AF=E6=8C=81=E9=BB=98=E8=AE=A4=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- stat/fillna.go | 132 ++++++++++++++++++++++++++++++++++++++++++++ stat/fillna_test.go | 15 +++++ 2 files changed, 147 insertions(+) create mode 100644 stat/fillna.go create mode 100644 stat/fillna_test.go diff --git a/stat/fillna.go b/stat/fillna.go new file mode 100644 index 0000000..a020119 --- /dev/null +++ b/stat/fillna.go @@ -0,0 +1,132 @@ +package stat + +import "golang.org/x/exp/slices" + +// Fill 填充 +// +// Fill NA/NaN values using the specified method. +// Parameters +// ---------- +// value : scalar, dict, Series, or DataFrame +// Value to use to fill holes (e.g. 0), alternately a +// dict/Series/DataFrame of values specifying which value to use for +// each index (for a Series) or column (for a DataFrame). Values not +// in the dict/Series/DataFrame will not be filled. This value cannot +// be a list. +// method : {{'backfill', 'bfill', 'pad', 'ffill', None}}, default None +// Method to use for filling holes in reindexed Series +// pad / ffill: propagate last valid observation forward to next valid +// backfill / bfill: use next valid observation to fill gap. +// axis : {axes_single_arg} +// Axis along which to fill missing values. For `Series` +// this parameter is unused and defaults to 0. +// inplace : bool, default False [√] +// If True, fill in-place. Note: this will modify any +// other views on this object (e.g., a no-copy slice for a column in a +// DataFrame). +// limit : int, default None +// If method is specified, this is the maximum number of consecutive +// NaN values to forward/backward fill. In other words, if there is +// a gap with more than this number of consecutive NaNs, it will only +// be partially filled. If method is not specified, this is the +// maximum number of entries along the entire axis where NaNs will be +// filled. Must be greater than 0 if not None. +// downcast : dict, default is None +// A dict of item->dtype of what to downcast if possible, +// or the string 'infer' which will try to downcast to an appropriate +// equal type (e.g. float64 to int64 if possible). +// +// Returns +// ------- +// []T or None +func Fill[T StatType | ~string](v []T, d T, args ...any) (rows []T) { + // 默认不替换 + var __optInplace = false + if len(args) > 0 { + // 第一个参数为是否copy + if _cp, ok := args[0].(bool); ok { + __optInplace = _cp + } + } + var dest []T + if __optInplace { + dest = v + } else { + dest = slices.Clone(v) + } + var values any = dest + switch rows := values.(type) { + case []string: + ds := AnyToString(d) + for idx, iv := range rows { + if StringIsNaN(iv) { + rows[idx] = ds + } + } + case []float32: + df32 := AnyToFloat32(d) + for idx, iv := range rows { + if Float32IsNaN(iv) { + rows[idx] = df32 + } + } + case []float64: + df64 := AnyToFloat64(d) + for idx, iv := range rows { + if Float64IsNaN(iv) { + rows[idx] = df64 + } + } + default: + return dest + } + return dest +} + +// FillNa NaN填充默认值 +func FillNa[T StatType | ~string](v []T, args ...any) []T { + // 默认不copy + var __optInplace = false + if len(args) > 0 { + // 第一个参数为是否copy + if _cp, ok := args[0].(bool); ok { + __optInplace = _cp + } + } + var dest []T + if __optInplace { + dest = v + } else { + dest = slices.Clone(v) + } + var values any = dest + switch rows := values.(type) { + case []string: + for idx, iv := range rows { + if StringIsNaN(iv) { + rows[idx] = AnyToString(v) + } + } + case []int64: + for idx, iv := range rows { + if Float64IsNaN(float64(iv)) { + rows[idx] = AnyToInt64(v) + } + } + case []float32: + for idx, iv := range rows { + if Float32IsNaN(iv) { + rows[idx] = AnyToFloat32(v) + } + } + case []float64: + for idx, iv := range rows { + if Float64IsNaN(iv) { + rows[idx] = AnyToFloat64(v) + } + } + default: + return dest + } + return dest +} diff --git a/stat/fillna_test.go b/stat/fillna_test.go new file mode 100644 index 0000000..10b497d --- /dev/null +++ b/stat/fillna_test.go @@ -0,0 +1,15 @@ +package stat + +import ( + "fmt" + "testing" +) + +func TestFill(t *testing.T) { + s2 := []float64{1, 2, 3, 4, 3, 3, 2, 1, DTypeNaN, DTypeNaN, DTypeNaN, DTypeNaN} + fmt.Println(s2) + Fill(s2, 1.0) + fmt.Println(s2) + Fill(s2, 1.0, true) + fmt.Println(s2) +} -- Gitee From fe6db87bd82f70afc2cd64b41917a6d05b305026 Mon Sep 17 00:00:00 2001 From: wangfeng Date: Thu, 9 Feb 2023 11:31:15 +0800 Subject: [PATCH 06/19] =?UTF-8?q?fixed:=20=E4=BF=AE=E5=A4=8DSum=E4=B8=80?= =?UTF-8?q?=E5=A4=84bug,=20=E6=B3=9B=E5=9E=8B=E7=B1=BB=E5=9E=8B=E6=89=A9?= =?UTF-8?q?=E5=B1=95int32=E5=92=8Cint64,=20=E4=BC=9A=E5=87=BA=E7=8E=B0?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E8=BD=AC=E6=8D=A2=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- stat/sum.go | 13 ++++++------- stat/sum_test.go | 17 +++++++++++++++++ 2 files changed, 23 insertions(+), 7 deletions(-) create mode 100644 stat/sum_test.go diff --git a/stat/sum.go b/stat/sum.go index 7ab37ff..437c07e 100644 --- a/stat/sum.go +++ b/stat/sum.go @@ -3,7 +3,6 @@ package stat import ( "github.com/viterin/vek" "github.com/viterin/vek/vek32" - "unsafe" ) // Sum 计算累和 @@ -14,12 +13,12 @@ func Sum[T StatType](f []T) T { var d any var s any s = f - bitSize := unsafe.Sizeof(f[0]) - if bitSize == 4 { - d = vek32.Sum(s.([]float32)) - } else if bitSize == 8 { - d = vek.Sum(s.([]float64)) - } else { + switch fs := s.(type) { + case []float32: + d = vek32.Sum(fs) + case []float64: + d = vek.Sum(fs) + default: // 剩下的就是int32和int64, 循环吧 m := T(0) for _, v := range f { diff --git a/stat/sum_test.go b/stat/sum_test.go new file mode 100644 index 0000000..55e9015 --- /dev/null +++ b/stat/sum_test.go @@ -0,0 +1,17 @@ +package stat + +import ( + "fmt" + "testing" +) + +func TestSum(t *testing.T) { + d1 := []float32{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} + d2 := []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} + d3 := []int32{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} + d4 := []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} + fmt.Println(Sum(d1)) + fmt.Println(Sum(d2)) + fmt.Println(Sum(d3)) + fmt.Println(Sum(d4)) +} -- Gitee From 0715784e409d9d186b9616a654f7f61a779b3dcc Mon Sep 17 00:00:00 2001 From: wangfeng Date: Thu, 9 Feb 2023 11:39:11 +0800 Subject: [PATCH 07/19] =?UTF-8?q?fixed:=20=E4=BF=AE=E5=A4=8D=E6=B3=9B?= =?UTF-8?q?=E5=9E=8B=E7=B1=BB=E5=9E=8B=E6=89=A9=E5=B1=95int32=E5=92=8Cint6?= =?UTF-8?q?4,=20=E4=BC=9A=E5=87=BA=E7=8E=B0=E7=B1=BB=E5=9E=8B=E8=BD=AC?= =?UTF-8?q?=E6=8D=A2=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- stat/stddev.go | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/stat/stddev.go b/stat/stddev.go index 96cd569..9b5c1aa 100644 --- a/stat/stddev.go +++ b/stat/stddev.go @@ -6,7 +6,6 @@ import ( "golang.org/x/exp/slices" "gonum.org/v1/gonum/stat" "math" - "unsafe" ) // Std_TODO StdDev 这个版本有bug, gonum计算的std不对 @@ -18,12 +17,13 @@ func Std_TODO[T Float](f []T) T { var d any var s any s = f - bitSize := unsafe.Sizeof(f[0]) - if bitSize == 4 { - d = vek32.Max(s.([]float32)) - } else if bitSize == 8 { - d = stat.StdDev(s.([]float64), nil) - } else { + switch fs := s.(type) { + case []float32: + d = f32_std(fs) + case []float64: + // 这里计算不对 + d = stat.StdDev(fs, nil) + default: // 应该不会走到这里 d = T(0) } @@ -39,12 +39,12 @@ func Std[T Float](f []T) T { var d any var s any s = f - bitSize := unsafe.Sizeof(f[0]) - if bitSize == 4 { - d = f32_std(s.([]float32)) - } else if bitSize == 8 { - d = f64_std(s.([]float64)) - } else { + switch fs := s.(type) { + case []float32: + d = f32_std(fs) + case []float64: + d = f64_std(fs) + default: // 应该不会走到这里 d = T(0) } -- Gitee From 11992579d602d0072703650b09bfe5bbec499073 Mon Sep 17 00:00:00 2001 From: wangfeng Date: Thu, 9 Feb 2023 11:42:35 +0800 Subject: [PATCH 08/19] =?UTF-8?q?fixed:=20=E4=BF=AE=E5=A4=8D=E6=B3=9B?= =?UTF-8?q?=E5=9E=8B=E7=B1=BB=E5=9E=8B=E6=89=A9=E5=B1=95int32=E5=92=8Cint6?= =?UTF-8?q?4,=20=E4=BC=9A=E5=87=BA=E7=8E=B0=E7=B1=BB=E5=9E=8B=E8=BD=AC?= =?UTF-8?q?=E6=8D=A2=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- stat/repeat.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/stat/repeat.go b/stat/repeat.go index 35b5ec2..53c3922 100644 --- a/stat/repeat.go +++ b/stat/repeat.go @@ -3,18 +3,18 @@ package stat import ( "github.com/viterin/vek" "github.com/viterin/vek/vek32" - "unsafe" ) // Repeat repeat func Repeat[T StatType](f T, n int) []T { var d any - bitSize := unsafe.Sizeof(f) - if bitSize == 4 { - d = vek32.Repeat(float32(f), n) - } else if bitSize == 8 { - d = vek.Repeat(float64(f), n) - } else { + var s any = f + switch fs := s.(type) { + case float32: + d = vek32.Repeat(fs, n) + case float64: + d = vek.Repeat(fs, n) + default: // 应该不会走到这里 d = []T{} // 剩下的就是int32和int64, 循环吧 -- Gitee From 8419b28b352f5febf76f978edd0147c32b1f96e1 Mon Sep 17 00:00:00 2001 From: wangfeng Date: Thu, 9 Feb 2023 11:45:24 +0800 Subject: [PATCH 09/19] =?UTF-8?q?fixed:=20=E4=BF=AE=E5=A4=8D=E6=B3=9B?= =?UTF-8?q?=E5=9E=8B=E7=B1=BB=E5=9E=8B=E6=89=A9=E5=B1=95int32=E5=92=8Cint6?= =?UTF-8?q?4,=20=E4=BC=9A=E5=87=BA=E7=8E=B0=E7=B1=BB=E5=9E=8B=E8=BD=AC?= =?UTF-8?q?=E6=8D=A2=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- stat/median.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stat/median.go b/stat/median.go index 6be0964..91c956f 100644 --- a/stat/median.go +++ b/stat/median.go @@ -2,7 +2,7 @@ package stat // Median returns median value of series. // Linear interpolation is used for odd length. -// TODO:未加验证 +// TODO:未加验证, 未加速 func Median[T StatType](values []T) DType { if len(values) == 0 { return DTypeNaN -- Gitee From e0413044cdaa77457d1991bf49ec8b486a58dbb1 Mon Sep 17 00:00:00 2001 From: wangfeng Date: Thu, 9 Feb 2023 11:48:36 +0800 Subject: [PATCH 10/19] =?UTF-8?q?fixed:=20=E4=BF=AE=E5=A4=8D=E6=B3=9B?= =?UTF-8?q?=E5=9E=8B=E7=B1=BB=E5=9E=8B=E6=89=A9=E5=B1=95int32=E5=92=8Cint6?= =?UTF-8?q?4,=20=E4=BC=9A=E5=87=BA=E7=8E=B0=E7=B1=BB=E5=9E=8B=E8=BD=AC?= =?UTF-8?q?=E6=8D=A2=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- stat/cumsum.go | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/stat/cumsum.go b/stat/cumsum.go index 2879a2d..a1d43ea 100644 --- a/stat/cumsum.go +++ b/stat/cumsum.go @@ -4,7 +4,6 @@ import ( "github.com/viterin/vek" "github.com/viterin/vek/vek32" "golang.org/x/exp/slices" - "unsafe" ) // CumSum 计算累和 @@ -15,12 +14,12 @@ func CumSum[T StatType](f []T) []T { var d any var s any s = f - bitSize := unsafe.Sizeof(f[0]) - if bitSize == 4 { - d = vek32.CumSum(s.([]float32)) - } else if bitSize == 8 { - d = vek.CumSum(s.([]float64)) - } else { + switch fs := s.(type) { + case []float32: + d = vek32.CumSum(fs) + case []float64: + d = vek.CumSum(fs) + default: // 剩下的就是int32和int64, 循环吧 sum := T(0) x := slices.Clone(f) -- Gitee From 063cd9e2d4e5ead6190fb91bf351ca5621f38fc4 Mon Sep 17 00:00:00 2001 From: wangfeng Date: Thu, 9 Feb 2023 11:49:48 +0800 Subject: [PATCH 11/19] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- stat/sum.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stat/sum.go b/stat/sum.go index 437c07e..851ddfb 100644 --- a/stat/sum.go +++ b/stat/sum.go @@ -5,7 +5,7 @@ import ( "github.com/viterin/vek/vek32" ) -// Sum 计算累和 +// Sum 求和 func Sum[T StatType](f []T) T { if len(f) == 0 { return T(0) -- Gitee From 3b2eaf592f2fba71552fdf756adfb57ca0dacfc9 Mon Sep 17 00:00:00 2001 From: wangfeng Date: Thu, 9 Feb 2023 11:54:13 +0800 Subject: [PATCH 12/19] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=B3=9B=E5=9E=8B?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E6=89=A9=E5=B1=95int32=E5=92=8Cint64,=20?= =?UTF-8?q?=E4=BC=9A=E5=87=BA=E7=8E=B0=E7=B1=BB=E5=9E=8B=E8=BD=AC=E6=8D=A2?= =?UTF-8?q?=E5=BC=82=E5=B8=B8,=20=E6=96=B0=E5=A2=9E=E5=8A=A0=E4=B8=80?= =?UTF-8?q?=E4=B8=AA=E6=99=AE=E9=80=9A=E5=87=BD=E6=95=B0=E5=9C=A8=E8=BF=99?= =?UTF-8?q?=E9=87=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- stat/minimum.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/stat/minimum.go b/stat/minimum.go index 945cc17..d50dc40 100644 --- a/stat/minimum.go +++ b/stat/minimum.go @@ -85,3 +85,12 @@ func Minimum[T Float](f1, f2 []T) []T { } return d } + +// 暂时用不到, 先放在这里, 以后可能要扩展类型 +func __minimum[T Float](x, y []T) { + for i := 0; i < len(x); i++ { + if y[i] < x[i] { + x[i] = y[i] + } + } +} -- Gitee From b507da08f285582df584f5db2a67c6bc7208e4cf Mon Sep 17 00:00:00 2001 From: wangfeng Date: Thu, 9 Feb 2023 11:55:46 +0800 Subject: [PATCH 13/19] =?UTF-8?q?fixed:=20=E4=BF=AE=E5=A4=8D=E6=B3=9B?= =?UTF-8?q?=E5=9E=8B=E7=B1=BB=E5=9E=8B=E6=89=A9=E5=B1=95int32=E5=92=8Cint6?= =?UTF-8?q?4,=20=E4=BC=9A=E5=87=BA=E7=8E=B0=E7=B1=BB=E5=9E=8B=E8=BD=AC?= =?UTF-8?q?=E6=8D=A2=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- stat/min.go | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/stat/min.go b/stat/min.go index 264fd2a..ddd1bec 100644 --- a/stat/min.go +++ b/stat/min.go @@ -3,7 +3,6 @@ package stat import ( "github.com/viterin/vek" "github.com/viterin/vek/vek32" - "unsafe" ) // Min 计算最小值 @@ -14,12 +13,12 @@ func Min[T Float](f []T) T { var d any var s any s = f - bitSize := unsafe.Sizeof(f[0]) - if bitSize == 4 { - d = vek32.Min(s.([]float32)) - } else if bitSize == 8 { + switch fs := s.(type) { + case []float32: + d = vek32.Min(fs) + case []float64: d = vek.Min(s.([]float64)) - } else { + default: // 应该不会走到这里 d = T(0) } -- Gitee From b8ebf85e48fa530d2be341215afa7a829c2121d1 Mon Sep 17 00:00:00 2001 From: wangfeng Date: Thu, 9 Feb 2023 12:20:48 +0800 Subject: [PATCH 14/19] =?UTF-8?q?fixed:=20=E4=BF=AE=E5=A4=8D=E6=B3=9B?= =?UTF-8?q?=E5=9E=8B=E7=B1=BB=E5=9E=8B=E6=89=A9=E5=B1=95int32=E5=92=8Cint6?= =?UTF-8?q?4,=20=E4=BC=9A=E5=87=BA=E7=8E=B0=E7=B1=BB=E5=9E=8B=E8=BD=AC?= =?UTF-8?q?=E6=8D=A2=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- stat/maximum.go | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/stat/maximum.go b/stat/maximum.go index 83e0617..f35c086 100644 --- a/stat/maximum.go +++ b/stat/maximum.go @@ -3,7 +3,7 @@ package stat import ( "github.com/viterin/vek" "github.com/viterin/vek/vek32" - "unsafe" + "golang.org/x/exp/slices" ) // MaximumAvx2 两个序列横向比较最大值 @@ -34,14 +34,16 @@ func MaximumAvx2[T Float](f1, f2 []T) []T { var d any - bitSize := unsafe.Sizeof(f1[0]) - if bitSize == 4 { - d = vek32.Maximum(s1.([]float32), s2.([]float32)) - } else if bitSize == 8 { - d = vek.Maximum(s1.([]float64), s2.([]float64)) - } else { - // 应该不会走到这里 - panic("other types are not supported") + switch fs1 := s1.(type) { + case []float32: + d = vek32.Maximum(fs1, s2.([]float32)) + case []float64: + d = vek.Maximum(fs1, s2.([]float64)) + default: + // 目前暂时走不到这里 + f1 = slices.Clone(f1) + __maximum(f1, f2) + d = f1 } return d.([]T) } @@ -69,14 +71,18 @@ func Maximum[T Float](f1, f2 []T) []T { } // 初始化返回值 d := make([]T, maxLength) - bitSize := unsafe.Sizeof(f1[0]) for i := 0; i < maxLength; i++ { if Float64IsNaN(float64(f1[i])) || Float64IsNaN(float64(f2[i])) { - if bitSize == 4 { + var s1 any = f1[i] + switch s1.(type) { + case float32: d[i] = T(Nil2Float32) - } else { + case []float64: d[i] = T(Nil2Float64) + default: + panic(ErrUnsupportedType) } + continue } if f1[i] > f2[i] { d[i] = f1[i] @@ -86,3 +92,11 @@ func Maximum[T Float](f1, f2 []T) []T { } return d } + +func __maximum[T Float](x, y []T) { + for i := 0; i < len(x); i++ { + if y[i] > x[i] { + x[i] = y[i] + } + } +} -- Gitee From 73aabe5e75fdfa2f25985520e3fd72756bce743c Mon Sep 17 00:00:00 2001 From: wangfeng Date: Thu, 9 Feb 2023 12:27:48 +0800 Subject: [PATCH 15/19] =?UTF-8?q?fixed:=20=E4=BF=AE=E5=A4=8D=E6=B3=9B?= =?UTF-8?q?=E5=9E=8B=E7=B1=BB=E5=9E=8B=E6=89=A9=E5=B1=95int32=E5=92=8Cint6?= =?UTF-8?q?4,=20=E4=BC=9A=E5=87=BA=E7=8E=B0=E7=B1=BB=E5=9E=8B=E8=BD=AC?= =?UTF-8?q?=E6=8D=A2=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- stat/maximum.go | 3 +-- stat/minimum.go | 34 +++++++++++++++++++--------------- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/stat/maximum.go b/stat/maximum.go index f35c086..894bfc4 100644 --- a/stat/maximum.go +++ b/stat/maximum.go @@ -33,7 +33,6 @@ func MaximumAvx2[T Float](f1, f2 []T) []T { s2 = f2 var d any - switch fs1 := s1.(type) { case []float32: d = vek32.Maximum(fs1, s2.([]float32)) @@ -53,8 +52,8 @@ func MaximumAvx2[T Float](f1, f2 []T) []T { func Maximum[T Float](f1, f2 []T) []T { xlen := len(f1) ylen := len(f2) - // 第找出最大长度 + // 第找出最大长度 maxLength := xlen if maxLength < ylen { maxLength = ylen diff --git a/stat/minimum.go b/stat/minimum.go index d50dc40..4e40cff 100644 --- a/stat/minimum.go +++ b/stat/minimum.go @@ -3,15 +3,15 @@ package stat import ( "github.com/viterin/vek" "github.com/viterin/vek/vek32" - "unsafe" + "golang.org/x/exp/slices" ) // MinimumAvx2 两个序列横向比较最大值 func MinimumAvx2[T Float](f1, f2 []T) []T { xlen := len(f1) ylen := len(f2) - // 第找出最大长度 + // 第找出最大长度 maxLength := xlen if maxLength < ylen { maxLength = ylen @@ -32,15 +32,16 @@ func MinimumAvx2[T Float](f1, f2 []T) []T { s2 = f2 var d any - - bitSize := unsafe.Sizeof(f1[0]) - if bitSize == 4 { - d = vek32.Minimum(s1.([]float32), s2.([]float32)) - } else if bitSize == 8 { - d = vek.Minimum(s1.([]float64), s2.([]float64)) - } else { - // 应该不会走到这里 - panic("other types are not supported") + switch fs1 := s1.(type) { + case []float32: + d = vek32.Minimum(fs1, s2.([]float32)) + case []float64: + d = vek.Minimum(fs1, s2.([]float64)) + default: + // 目前暂时走不到这里 + f1 = slices.Clone(f1) + __minimum(f1, f2) + d = f1 } return d.([]T) } @@ -67,15 +68,18 @@ func Minimum[T Float](f1, f2 []T) []T { } // 初始化返回值 d := make([]T, maxLength) - bitSize := unsafe.Sizeof(f1[0]) for i := 0; i < maxLength; i++ { if Float64IsNaN(float64(f1[i])) || Float64IsNaN(float64(f2[i])) { - if bitSize == 4 { + var s1 any = f1[i] + switch s1.(type) { + case float32: d[i] = T(Nil2Float32) - } else { + case []float64: d[i] = T(Nil2Float64) + default: + panic(ErrUnsupportedType) } - + continue } if f1[i] < f2[i] { d[i] = f1[i] -- Gitee From e55c4c81be94104ec83fc66ea62ba3b8629eca46 Mon Sep 17 00:00:00 2001 From: wangfeng Date: Thu, 9 Feb 2023 12:28:41 +0800 Subject: [PATCH 16/19] =?UTF-8?q?=E4=BF=AE=E8=AE=A2=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- stat/maximum.go | 2 +- stat/minimum.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/stat/maximum.go b/stat/maximum.go index 894bfc4..0dd40e2 100644 --- a/stat/maximum.go +++ b/stat/maximum.go @@ -6,7 +6,7 @@ import ( "golang.org/x/exp/slices" ) -// MaximumAvx2 两个序列横向比较最大值 +// MaximumAvx2 AVX2版本, 两个序列横向比较最大值 // TODO:print(np.maximum(1.4, np.nan)) 输出nan func MaximumAvx2[T Float](f1, f2 []T) []T { xlen := len(f1) diff --git a/stat/minimum.go b/stat/minimum.go index 4e40cff..183efd2 100644 --- a/stat/minimum.go +++ b/stat/minimum.go @@ -6,7 +6,7 @@ import ( "golang.org/x/exp/slices" ) -// MinimumAvx2 两个序列横向比较最大值 +// MinimumAvx2 AVX2版本, 两个序列横向比较最大值 func MinimumAvx2[T Float](f1, f2 []T) []T { xlen := len(f1) ylen := len(f2) -- Gitee From e18bd36947f9cae8e1376bcd2d20f7f766221f02 Mon Sep 17 00:00:00 2001 From: wangfeng Date: Thu, 9 Feb 2023 12:33:01 +0800 Subject: [PATCH 17/19] =?UTF-8?q?=E4=BD=BF=E7=94=A8=E5=8A=A0=E9=80=9F?= =?UTF-8?q?=E7=89=88=E6=9C=AC,=20NaN=E7=BA=A6=E5=AE=9A=E5=BF=85=E9=A1=BB?= =?UTF-8?q?=E8=A6=81=E5=A4=84=E7=90=86,=20=E5=90=A6=E5=88=99=E5=8F=AF?= =?UTF-8?q?=E8=83=BD=E5=87=BA=E7=8E=B0=E6=97=A0=E6=B3=95=E9=A2=84=E7=9F=A5?= =?UTF-8?q?=E7=9A=84=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- stat/maximum.go | 9 ++++----- stat/maximum_test.go | 2 +- stat/minimum.go | 8 ++++---- stat/minimum_test.go | 2 +- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/stat/maximum.go b/stat/maximum.go index 0dd40e2..82315c4 100644 --- a/stat/maximum.go +++ b/stat/maximum.go @@ -6,9 +6,9 @@ import ( "golang.org/x/exp/slices" ) -// MaximumAvx2 AVX2版本, 两个序列横向比较最大值 +// Maximum AVX2版本, 两个序列横向比较最大值 // TODO:print(np.maximum(1.4, np.nan)) 输出nan -func MaximumAvx2[T Float](f1, f2 []T) []T { +func Maximum[T Float](f1, f2 []T) []T { xlen := len(f1) ylen := len(f2) // 第找出最大长度 @@ -47,9 +47,8 @@ func MaximumAvx2[T Float](f1, f2 []T) []T { return d.([]T) } -// Maximum 两个序列横向比较最大值 -// TODO:print(np.maximum(1.4, np.nan)) 输出nan -func Maximum[T Float](f1, f2 []T) []T { +// Maximum_GO go版本, 两个序列横向比较最大值 +func Maximum_GO[T Float](f1, f2 []T) []T { xlen := len(f1) ylen := len(f2) diff --git a/stat/maximum_test.go b/stat/maximum_test.go index 55bfdaf..1c94c1e 100644 --- a/stat/maximum_test.go +++ b/stat/maximum_test.go @@ -11,6 +11,6 @@ func TestMaxinum(t *testing.T) { fmt.Println(1.4 < math.NaN()) f1 := []float32{1.1, 2.2, 1.3, 1.4} f2 := []float32{1.2, 1.2, 3.3} - fmt.Println(MaximumAvx2(f1, f2)) fmt.Println(Maximum(f1, f2)) + fmt.Println(Maximum_GO(f1, f2)) } diff --git a/stat/minimum.go b/stat/minimum.go index 183efd2..238d433 100644 --- a/stat/minimum.go +++ b/stat/minimum.go @@ -6,8 +6,8 @@ import ( "golang.org/x/exp/slices" ) -// MinimumAvx2 AVX2版本, 两个序列横向比较最大值 -func MinimumAvx2[T Float](f1, f2 []T) []T { +// Minimum AVX2版本, 两个序列横向比较最大值 +func Minimum[T Float](f1, f2 []T) []T { xlen := len(f1) ylen := len(f2) @@ -46,8 +46,8 @@ func MinimumAvx2[T Float](f1, f2 []T) []T { return d.([]T) } -// Minimum 两个序列横向比较最大值 -func Minimum[T Float](f1, f2 []T) []T { +// Minimum_GO go版本 两个序列横向比较最大值 +func Minimum_GO[T Float](f1, f2 []T) []T { xlen := len(f1) ylen := len(f2) // 第找出最大长度 diff --git a/stat/minimum_test.go b/stat/minimum_test.go index 9f01efe..0355f49 100644 --- a/stat/minimum_test.go +++ b/stat/minimum_test.go @@ -8,6 +8,6 @@ import ( func TestMinimum(t *testing.T) { f1 := []float32{1.1, 2.2, 1.3, 1.4} f2 := []float32{1.2, 1.2, 3.3} - fmt.Println(MinimumAvx2(f1, f2)) fmt.Println(Minimum(f1, f2)) + fmt.Println(Minimum_GO(f1, f2)) } -- Gitee From a8aee9f59b42dc8e76f8c24bcf795c41a87aaadb Mon Sep 17 00:00:00 2001 From: wangfeng Date: Thu, 9 Feb 2023 12:41:20 +0800 Subject: [PATCH 18/19] =?UTF-8?q?=E5=A6=82=E6=9E=9C=E4=B8=8D=E5=9C=A8?= =?UTF-8?q?=E9=A2=84=E8=AE=A1=E8=8C=83=E5=9B=B4=E5=86=85=E7=9A=84=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B,=20=E6=8A=9B=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- stat/max.go | 18 +++++++++--------- stat/min.go | 4 ++-- stat/stddev.go | 4 ++-- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/stat/max.go b/stat/max.go index d0d5b56..62fb5d8 100644 --- a/stat/max.go +++ b/stat/max.go @@ -3,7 +3,6 @@ package stat import ( "github.com/viterin/vek" "github.com/viterin/vek/vek32" - "unsafe" ) // Max 计算最大值 @@ -11,17 +10,18 @@ func Max[T Float](f []T) T { if len(f) == 0 { return T(0) } + var d any var s any s = f - bitSize := unsafe.Sizeof(f[0]) - if bitSize == 4 { - d = vek32.Max(s.([]float32)) - } else if bitSize == 8 { - d = vek.Max(s.([]float64)) - } else { - // 应该不会走到这里 - d = T(0) + switch fs := s.(type) { + case []float32: + d = vek32.Max(fs) + case []float64: + d = vek.Max(fs) + default: + panic(ErrUnsupportedType) } + return d.(T) } diff --git a/stat/min.go b/stat/min.go index ddd1bec..116b264 100644 --- a/stat/min.go +++ b/stat/min.go @@ -17,10 +17,10 @@ func Min[T Float](f []T) T { case []float32: d = vek32.Min(fs) case []float64: - d = vek.Min(s.([]float64)) + d = vek.Min(fs) default: // 应该不会走到这里 - d = T(0) + panic(ErrUnsupportedType) } return d.(T) } diff --git a/stat/stddev.go b/stat/stddev.go index 9b5c1aa..bd9d033 100644 --- a/stat/stddev.go +++ b/stat/stddev.go @@ -25,7 +25,7 @@ func Std_TODO[T Float](f []T) T { d = stat.StdDev(fs, nil) default: // 应该不会走到这里 - d = T(0) + panic(ErrUnsupportedType) } return d.(T) @@ -46,7 +46,7 @@ func Std[T Float](f []T) T { d = f64_std(fs) default: // 应该不会走到这里 - d = T(0) + panic(ErrUnsupportedType) } return d.(T) -- Gitee From eb239e3ac819e93b700e9814b86bc78d5638207e Mon Sep 17 00:00:00 2001 From: wangfeng Date: Thu, 9 Feb 2023 12:43:41 +0800 Subject: [PATCH 19/19] =?UTF-8?q?#I6CYP2=20=E5=AE=9E=E7=8E=B0=E4=BA=86DMA?= =?UTF-8?q?=E5=87=BD=E6=95=B0,=20=E8=BF=99=E4=B8=AA=E5=87=BD=E6=95=B0?= =?UTF-8?q?=E6=B2=A1=E6=9C=89=E6=AD=A7=E4=B9=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- formula/dma.go | 53 +++++++++++++++++++++++++++++++++++++++++++++ formula/dma_test.go | 47 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 formula/dma.go create mode 100644 formula/dma_test.go diff --git a/formula/dma.go b/formula/dma.go new file mode 100644 index 0000000..7e561fc --- /dev/null +++ b/formula/dma.go @@ -0,0 +1,53 @@ +package formula + +import ( + "gitee.com/quant1x/pandas" + "gitee.com/quant1x/pandas/stat" +) + +// DMA 返回动态移动平均 +// +// 求S的动态移动平均, A作平滑因子,必须 0= 1.05 { + t = stat.DType(1) + } + x0[idx] = t + }) + n := BARSLAST(pandas.NewSeries(pandas.SERIES_TYPE_FLOAT32, "", x0)) + fmt.Println(n[len(n)-10:]) + x := DMA(CLOSE, pandas.NewSeries(pandas.SERIES_TYPE_DTYPE, "", n)) + + //x := EMA(CLOSE, 7) + sx := pandas.NewSeries(pandas.SERIES_TYPE_DTYPE, "x", x) + df = pandas.NewDataFrame(CLOSE, sx) + fmt.Println(df) +} -- Gitee