diff --git a/README.md b/README.md index c55a4f2..a27f7ed 100644 --- a/README.md +++ b/README.md @@ -17,13 +17,15 @@ All the functions can be seen in [examples/main.go](https://github.com/montanafl ```go // start with some source data to use -data := []float64{1, 2, 3, 4, 4, 5} +data := []float64{1.0, 2.1, 3.2, 4.823, 4.1, 5.8} -// you could also use different number types like this -// data := stats.LoadRawData([]interface{}{1.1, "2", 3.0, 4, "5"}) +// you could also use different types like this +// data := stats.LoadRawData([]int{1, 2, 3, 4, 5}) +// data := stats.LoadRawData([]interface{}{1.1, "2", 3}) +// etc... median, _ := stats.Median(data) -fmt.Println(median) // 3.5 +fmt.Println(median) // 3.65 roundedMedian, _ := stats.Round(median, 0) fmt.Println(roundedMedian) // 4 @@ -90,6 +92,8 @@ func PopulationVariance(input Float64Data) (pvar float64, err error) {} func Round(input float64, places int) (rounded float64, err error) {} func Sample(input Float64Data, takenum int, replacement bool) ([]float64, error) {} func SampleVariance(input Float64Data) (svar float64, err error) {} +func Sigmoid(input Float64Data) ([]float64, error) {} +func SoftMax(input Float64Data) ([]float64, error) {} func StandardDeviation(input Float64Data) (sdev float64, err error) {} func StandardDeviationPopulation(input Float64Data) (sdev float64, err error) {} func StandardDeviationSample(input Float64Data) (sdev float64, err error) {} diff --git a/examples/main.go b/examples/main.go index d4cd56f..e6044ef 100644 --- a/examples/main.go +++ b/examples/main.go @@ -8,7 +8,8 @@ import ( func main() { - d := stats.LoadRawData([]interface{}{1.1, "2", 3.0, 4, "5"}) + // d := stats.LoadRawData([]interface{}{1.1, "2", 3.0, 4, "5"}) + d := stats.LoadRawData([]int{1, 2, 3, 4, 5}) a, _ := stats.Min(d) fmt.Println(a) @@ -156,4 +157,12 @@ func main() { ac, _ := stats.AutoCorrelation([]float64{1, 2, 3, 4, 5}, 1) fmt.Println(ac) // Output: 0.4 + + sig, _ := stats.Sigmoid([]float64{3.0, 1.0, 0.2}) + fmt.Println(s) + // Output: [0.9525741268224334 0.7310585786300049 0.549833997312478] + + sm, _ := stats.SoftMax([]float64{3.0, 1.0, 0.2}) + fmt.Println(sm) + // Output: [0.8360188027814407 0.11314284146556013 0.05083835575299916] } diff --git a/sigmoid.go b/sigmoid.go new file mode 100644 index 0000000..5f2559d --- /dev/null +++ b/sigmoid.go @@ -0,0 +1,18 @@ +package stats + +import "math" + +// Sigmoid returns the input values in the range of -1 to 1 +// along the sigmoid or s-shaped curve, commonly used in +// machine learning while training neural networks as an +// activation function. +func Sigmoid(input Float64Data) ([]float64, error) { + if input.Len() == 0 { + return Float64Data{}, EmptyInput + } + s := make([]float64, len(input)) + for i, v := range input { + s[i] = 1 / (1 + math.Exp(-v)) + } + return s, nil +} diff --git a/sigmoid_test.go b/sigmoid_test.go new file mode 100644 index 0000000..bef9dbd --- /dev/null +++ b/sigmoid_test.go @@ -0,0 +1,41 @@ +package stats + +import ( + "fmt" + "testing" +) + +func ExampleSigmoid() { + s, _ := Sigmoid([]float64{3.0, 1.0, 0.2}) + fmt.Println(s) + // Output: [0.9525741268224334 0.7310585786300049 0.549833997312478] +} + +func TestSigmoidEmptyInput(t *testing.T) { + _, err := Sigmoid([]float64{}) + if err != EmptyInputErr { + t.Errorf("Should have returned empty input error") + } +} + +func TestSigmoid(t *testing.T) { + sm, err := Sigmoid([]float64{-0.54761371, 17.04850603, 4.86054302}) + if err != nil { + t.Error(err) + } + + a := 0.3664182235138545 + if sm[0] != a { + t.Errorf("%v != %v", sm[0], a) + } + + a = 0.9999999605608187 + if sm[1] != a { + t.Errorf("%v != %v", sm[1], a) + } + + a = 0.9923132671908277 + if sm[2] != a { + t.Errorf("%v != %v", sm[2], a) + } +} diff --git a/softmax.go b/softmax.go new file mode 100644 index 0000000..8507264 --- /dev/null +++ b/softmax.go @@ -0,0 +1,25 @@ +package stats + +import "math" + +// SoftMax returns the input values in the range of 0 to 1 +// with sum of all the probabilities being equal to one. It +// is commonly used in machine learning neural networks. +func SoftMax(input Float64Data) ([]float64, error) { + if input.Len() == 0 { + return Float64Data{}, EmptyInput + } + + s := 0.0 + c, _ := Max(input) + for _, e := range input { + s += math.Exp(e - c) + } + + sm := make([]float64, len(input)) + for i, v := range input { + sm[i] = math.Exp(v-c) / s + } + + return sm, nil +} diff --git a/softmax_test.go b/softmax_test.go new file mode 100644 index 0000000..9b08224 --- /dev/null +++ b/softmax_test.go @@ -0,0 +1,41 @@ +package stats + +import ( + "fmt" + "testing" +) + +func ExampleSoftMax() { + sm, _ := SoftMax([]float64{3.0, 1.0, 0.2}) + fmt.Println(sm) + // Output: [0.8360188027814407 0.11314284146556013 0.05083835575299916] +} + +func TestSoftMaxEmptyInput(t *testing.T) { + _, err := SoftMax([]float64{}) + if err != EmptyInputErr { + t.Errorf("Should have returned empty input error") + } +} + +func TestSoftMax(t *testing.T) { + sm, err := SoftMax([]float64{3.0, 1.0, 0.2}) + if err != nil { + t.Error(err) + } + + a := 0.8360188027814407 + if sm[0] != a { + t.Errorf("%v != %v", sm[0], a) + } + + a = 0.11314284146556013 + if sm[1] != a { + t.Errorf("%v != %v", sm[1], a) + } + + a = 0.05083835575299916 + if sm[2] != a { + t.Errorf("%v != %v", sm[1], a) + } +}