template class BinaryClassifierLogisticRegression : public BinaryClassifier { public: void Train(const Dataset &Examples, UINT Class0Index, UINT Class1Index) { Console::WriteLine(String("Training logistic regression classifier, ") + String(Examples.Entries().Length()) + String(" examples")); Console::AdvanceLine(); _Thetas.Allocate(Examples.Entries()[0].Input.Length() + 1); _Thetas.Clear(0.0); _Class0Index = Class0Index; _Class1Index = Class1Index; TrainBatchGradientDescent(Examples); } void Evaluate(const LearnerInput &Input, UINT &Class, double &ProbabilityClass0) const { double Sum = 0.0; for(UINT ElementIndex = 0; ElementIndex < Input.Length(); ElementIndex++) { Sum += Input[ElementIndex] * _Thetas[ElementIndex]; } Sum += _Thetas.Last(); ProbabilityClass0 = 1.0 - Sigmoid(Sum); if(ProbabilityClass0 > 0.5) { Class = _Class0Index; } else { Class = _Class1Index; } } UINT Class0Index() const { return _Class0Index; } UINT Class1Index() const { return _Class1Index; } private: double Sigmoid(double x) const { return 1.0 / (1.0 + exp(-x)); } double ComputeHypothesis(const LearnerInput &Input) { double Sum = 0.0; for(UINT ElementIndex = 0; ElementIndex < Input.Length(); ElementIndex++) { Sum += Input[ElementIndex] * _Thetas[ElementIndex]; } Sum += _Thetas.Last(); return Sigmoid(Sum); } void TrainBatchGradientDescent(const Dataset &Examples) { const UINT FeatureCount = _Thetas.Length(); const UINT EntryCount = Examples.Entries().Length(); Vector Gradients(FeatureCount); bool Converged = false; UINT PassIndex = 0; double Alpha = 0.1; while(!Converged) { Gradients.Clear(0.0); PassIndex++; for(UINT SampleIndex = 0; SampleIndex < EntryCount; SampleIndex++) { const ClassifierExample &CurEntry = Examples.Entries()[SampleIndex]; double Delta = double(CurEntry.ZeroOneClass(_Class0Index)) - ComputeHypothesis(CurEntry.Input); for(UINT FeatureIndex = 0; FeatureIndex < FeatureCount - 1; FeatureIndex++) { Gradients[FeatureIndex] += Delta * CurEntry.Input[FeatureIndex]; } Gradients[FeatureCount - 1] += Delta; } double Change = 0.0; for(UINT FeatureIndex = 0; FeatureIndex < FeatureCount; FeatureIndex++) { double DeltaTheta = Alpha * Gradients[FeatureIndex]; _Thetas[FeatureIndex] += DeltaTheta; Change += Math::Abs(DeltaTheta); } Alpha *= 0.995; if(Change < 1e-10) { Converged = true; } if(PassIndex % 1000 == 0 || Converged) { Console::OverwriteLine(String("Pass ") + String(PassIndex) + String(", Change=") + String(Change)); } } } // // The last entry in _Thetas is the x=1 term // Vector _Thetas; UINT _Class0Index, _Class1Index; }; template class BinaryClassifierFactoryLogisticRegression : public BinaryClassifierFactory { public: BinaryClassifierFactoryLogisticRegression() { } BinaryClassifier* MakeClassifier() const { BinaryClassifierLogisticRegression *Result = new BinaryClassifierLogisticRegression; return Result; } };