func (f *oneVsAllFilter) Transform(old, to base.Attribute, seq []byte) []byte { if !old.Equals(f.classAttr) { return seq } val := base.UnpackBytesToU64(seq) if val == f.classAttrVal { return base.PackFloatToBytes(1.0) } return base.PackFloatToBytes(0.0) }
func (lr *LogisticRegression) Predict(X base.FixedDataGrid) base.FixedDataGrid { // Only support 1 class Attribute classAttrs := X.AllClassAttributes() if len(classAttrs) != 1 { panic(fmt.Sprintf("%d Wrong number of classes", len(classAttrs))) } // Generate return structure ret := base.GeneratePredictionVector(X) classAttrSpecs := base.ResolveAttributes(ret, classAttrs) // Retrieve numeric non-class Attributes numericAttrs := base.NonClassFloatAttributes(X) numericAttrSpecs := base.ResolveAttributes(X, numericAttrs) // Allocate row storage row := make([]float64, len(numericAttrSpecs)) X.MapOverRows(numericAttrSpecs, func(rowBytes [][]byte, rowNo int) (bool, error) { for i, r := range rowBytes { row[i] = base.UnpackBytesToFloat(r) } val := Predict(lr.model, row) vals := base.PackFloatToBytes(val) ret.Set(classAttrSpecs[0], rowNo, vals) return true, nil }) return ret }
func (lr *LinearRegression) Predict(X base.FixedDataGrid) (base.FixedDataGrid, error) { if !lr.fitted { return nil, NoTrainingDataError } ret := base.GeneratePredictionVector(X) attrSpecs := base.ResolveAttributes(X, lr.attrs) clsSpec, err := ret.GetAttribute(lr.cls) if err != nil { return nil, err } X.MapOverRows(attrSpecs, func(row [][]byte, i int) (bool, error) { var prediction float64 = lr.disturbance for j, r := range row { prediction += base.UnpackBytesToFloat(r) * lr.regressionCoefficients[j] } ret.Set(clsSpec, i, base.PackFloatToBytes(prediction)) return true, nil }) return ret, nil }
func (f *FloatConvertFilter) Transform(a base.Attribute, n base.Attribute, attrBytes []byte) []byte { ret := make([]byte, 8) // Check for CategoricalAttribute if _, ok := a.(*base.CategoricalAttribute); ok { // Unpack byte value val := base.UnpackBytesToU64(attrBytes) // If it's a two-valued one, check for non-zero if f.twoValuedCategoricalAttributes[a] { if val > 0 { ret = base.PackFloatToBytes(1.0) } else { ret = base.PackFloatToBytes(0.0) } } else if an, ok := f.nValuedCategoricalAttributeMap[a]; ok { // If it's an n-valued one, check the new Attribute maps onto // the unpacked value if af, ok := an[val]; ok { if af.Equals(n) { ret = base.PackFloatToBytes(1.0) } else { ret = base.PackFloatToBytes(0.0) } } else { panic("Categorical value not defined!") } } else { panic(fmt.Sprintf("Not a recognised Attribute %v", a)) } } else if _, ok := a.(*base.FloatAttribute); ok { // Binary: just return the original value ret = attrBytes } else if _, ok := a.(*base.BinaryAttribute); ok { // Float: check for non-zero if attrBytes[0] > 0 { ret = base.PackFloatToBytes(1.0) } else { ret = base.PackFloatToBytes(0.0) } } else { panic(fmt.Sprintf("Unrecognised Attribute: %v", a)) } return ret }
// Predict uses the underlying network to produce predictions for the // class variables of X. // // Can only predict one CategoricalAttribute at a time, or up to n // FloatAttributes. Set or unset ClassAttributes to work around this // limitation. func (m *MultiLayerNet) Predict(X base.FixedDataGrid) base.FixedDataGrid { // Create the return vector ret := base.GeneratePredictionVector(X) // Make sure everything's a FloatAttribute insts := m.convertToFloatInsts(X) // Get the input/output Attributes inputAttrs := base.NonClassAttributes(insts) outputAttrs := ret.AllClassAttributes() // Compute layers layers := 2 + len(m.layers) // Check that we're operating in a singular mode floatMode := 0 categoricalMode := 0 for _, a := range outputAttrs { if _, ok := a.(*base.CategoricalAttribute); ok { categoricalMode++ } else if _, ok := a.(*base.FloatAttribute); ok { floatMode++ } else { panic("Unsupported output Attribute type!") } } if floatMode > 0 && categoricalMode > 0 { panic("Can't predict a mix of float and categorical Attributes") } else if categoricalMode > 1 { panic("Can't predict more than one categorical class Attribute") } // Create the activation vector a := mat64.NewDense(m.network.size, 1, make([]float64, m.network.size)) // Resolve the input AttributeSpecs inputAs := base.ResolveAttributes(insts, inputAttrs) // Resolve the output Attributespecs outputAs := base.ResolveAttributes(ret, outputAttrs) // Map over each input row insts.MapOverRows(inputAs, func(row [][]byte, rc int) (bool, error) { // Clear the activation vector for i := 0; i < m.network.size; i++ { a.Set(i, 0, 0.0) } // Build the activation vector for i, vb := range row { if cIndex, ok := m.attrs[inputAs[i].GetAttribute()]; !ok { panic("Can't resolve the Attribute!") } else { a.Set(cIndex, 0, base.UnpackBytesToFloat(vb)) } } // Robots, activate! m.network.Activate(a, layers) // Decide which class to set if floatMode > 0 { for _, as := range outputAs { cIndex := m.attrs[as.GetAttribute()] ret.Set(as, rc, base.PackFloatToBytes(a.At(cIndex, 0))) } } else { maxIndex := 0 maxVal := 0.0 for i := m.classAttrOffset; i < m.classAttrOffset+m.classAttrCount; i++ { val := a.At(i, 0) if val > maxVal { maxIndex = i maxVal = val } } maxIndex -= m.classAttrOffset ret.Set(outputAs[0], rc, base.PackU64ToBytes(uint64(maxIndex))) } return true, nil }) return ret }
func TestFloatFilter(t *testing.T) { Convey("Given a contrived dataset...", t, func() { // Read the contrived dataset inst, err := base.ParseCSVToInstances("./binary_test.csv", true) So(err, ShouldEqual, nil) // Add Attributes to the filter bFilt := NewFloatConvertFilter() bAttrs := base.NonClassAttributes(inst) for _, a := range bAttrs { bFilt.AddAttribute(a) } bFilt.Train() // Construct a LazilyFilteredInstances to handle it instF := base.NewLazilyFilteredInstances(inst, bFilt) Convey("All the non-class Attributes should be floats...", func() { // Check that all the Attributes are the right type for _, a := range base.NonClassAttributes(instF) { _, ok := a.(*base.FloatAttribute) So(ok, ShouldEqual, true) } }) // Check that all the class Attributes made it Convey("All the class Attributes should have survived...", func() { origClassAttrs := inst.AllClassAttributes() newClassAttrs := instF.AllClassAttributes() intersectClassAttrs := base.AttributeIntersect(origClassAttrs, newClassAttrs) So(len(intersectClassAttrs), ShouldEqual, len(origClassAttrs)) }) // Check that the Attributes have the right names Convey("Attribute names should be correct...", func() { origNames := []string{"floatAttr", "shouldBe1Binary", "shouldBe3Binary_stoicism", "shouldBe3Binary_heroism", "shouldBe3Binary_romanticism", "arbitraryClass"} origMap := make(map[string]bool) for _, a := range origNames { origMap[a] = false } for _, a := range instF.AllAttributes() { name := a.GetName() _, ok := origMap[name] So(ok, ShouldBeTrue) origMap[name] = true } for a := range origMap { So(origMap[a], ShouldEqual, true) } }) Convey("All Attributes should be the correct type...", func() { for _, a := range instF.AllAttributes() { if a.GetName() == "arbitraryClass" { _, ok := a.(*base.CategoricalAttribute) So(ok, ShouldEqual, true) } else { _, ok := a.(*base.FloatAttribute) So(ok, ShouldEqual, true) } } }) // Check that the Attributes have been discretised correctly Convey("FloatConversion should have worked", func() { // Build Attribute map attrMap := make(map[string]base.Attribute) for _, a := range instF.AllAttributes() { attrMap[a.GetName()] = a } // For each attribute for name := range attrMap { So(name, ShouldBeIn, []string{ "floatAttr", "shouldBe1Binary", "shouldBe3Binary_stoicism", "shouldBe3Binary_heroism", "shouldBe3Binary_romanticism", "arbitraryClass", }) attr := attrMap[name] as, err := instF.GetAttribute(attr) So(err, ShouldEqual, nil) if name == "floatAttr" { So(instF.Get(as, 0), ShouldResemble, base.PackFloatToBytes(1.0)) So(instF.Get(as, 1), ShouldResemble, base.PackFloatToBytes(1.0)) So(instF.Get(as, 2), ShouldResemble, base.PackFloatToBytes(0.0)) } else if name == "shouldBe1Binary" { So(instF.Get(as, 0), ShouldResemble, base.PackFloatToBytes(0.0)) So(instF.Get(as, 1), ShouldResemble, base.PackFloatToBytes(1.0)) So(instF.Get(as, 2), ShouldResemble, base.PackFloatToBytes(1.0)) } else if name == "shouldBe3Binary_stoicism" { So(instF.Get(as, 0), ShouldResemble, base.PackFloatToBytes(1.0)) So(instF.Get(as, 1), ShouldResemble, base.PackFloatToBytes(0.0)) So(instF.Get(as, 2), ShouldResemble, base.PackFloatToBytes(0.0)) } else if name == "shouldBe3Binary_heroism" { So(instF.Get(as, 0), ShouldResemble, base.PackFloatToBytes(0.0)) So(instF.Get(as, 1), ShouldResemble, base.PackFloatToBytes(1.0)) So(instF.Get(as, 2), ShouldResemble, base.PackFloatToBytes(0.0)) } else if name == "shouldBe3Binary_romanticism" { So(instF.Get(as, 0), ShouldResemble, base.PackFloatToBytes(0.0)) So(instF.Get(as, 1), ShouldResemble, base.PackFloatToBytes(0.0)) So(instF.Get(as, 2), ShouldResemble, base.PackFloatToBytes(1.0)) } else if name == "arbitraryClass" { } } }) }) }