using BotSharp.Algorithm.Bayesian; using Microsoft.VisualStudio.TestTools.UnitTesting; using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace BotSharp.Algorithm.UnitTest { [TestClass] public class BayesianTest { /// /// The training set /// private ITrainingSet _trainingSet; /// /// The classifier /// private IClassifier _classifier; /// /// The spam class /// private static IClass _spamClass; /// /// The ham class /// private static IClass _hamClass; /// /// Sets up. /// public void SetUp() { _trainingSet = BuildTrainingSet(); _classifier = BuildClassifier(_trainingSet); } /// /// Builds the classifier. /// /// Classifier<StringClass, StringToken>. private IClassifier BuildClassifier(ITrainingSetAccessor trainingSet) { var classifier = new NaiveClassifier(trainingSet) { // disable smoothing for exact probabilities SmoothingAlpha = 0.0D }; return classifier; } /// /// Builds the training set. /// /// ITrainingSet<StringClass, StringToken>. private static ITrainingSet BuildTrainingSet() { var trainingSet = new TrainingSet(); // build data sets var spamSet = BuildSpamDataSet(); var hamSet = BuildHamDataSet(); // monkey test //spamSet.SetSize.Should() //.Be(hamSet.SetSize, "because this test relies on identical set sizes for exact probability testing"); // register classes _spamClass = spamSet.Class; _hamClass = hamSet.Class; // add the sets and return trainingSet.Add(spamSet, hamSet); return trainingSet; } /// /// Builds the spam data set. /// /// IDataSet<StringClass, StringToken>. private static IDataSet BuildSpamDataSet() { return BuildDataSet("spam", 0.5D, "rolex", "watches", "viagra", "prince", "money", "send", "xyzzy"); } /// /// Builds the spam data set. /// /// IDataSet<StringClass, StringToken>. private static IDataSet BuildHamDataSet() { return BuildDataSet("ham", 0.5D, "love", "flowers", "unicorn", "friendship", "money", "send", "send"); } /// /// Builds the data set. /// /// Name of the class. /// The class probability. /// The token. /// The additional tokens. /// IDataSet<StringClass, StringToken>. private static IDataSet BuildDataSet(string className, double classProbability, string token, params string[] additionalTokens) { var @class = new StringClass(className, classProbability); var dataSet = new DataSet(@class); dataSet.AddToken(new StringToken(token)); dataSet.AddToken(additionalTokens.Select(t => new StringToken(t))); return dataSet; } [TestMethod] public void CalculateProbabilityReturnsOneHundredPercentForAKnownSpamWord() { var token = new StringToken("rolex"); var probability = _classifier.CalculateProbability(_spamClass, token); //probability.Should().BeApproximately(1.0D, 0.0001D, "because the word is known the be a spam word"); } [TestMethod] public void CalculateProbabilityReturnsOneHundredPercentForAKnownHamWord() { var token = new StringToken("unicorn"); var probability = _classifier.CalculateProbability(_hamClass, token); //probability.Should().BeApproximately(1.0D, 0.0001D, "because the word is known the be a ham word"); } [TestMethod] public void CalculateProbabilitiesWithHamWordReturnsProbabilitiesForAllClasses() { var token = new StringToken("unicorn"); var probabilities = _classifier.CalculateProbabilities(token).ToList(); /*probabilities.Single(p => p.Class.Equals(_spamClass)) .Probability.Should() .BeApproximately(0D, 0.000001D, "because the token is known to be a ham word"); probabilities.Single(p => p.Class.Equals(_hamClass)) .Probability.Should() .BeApproximately(1D, 0.000001D, "because the token is known to be a ham word");*/ } [TestMethod] public void CalculateProbabilitiesWithMixedWordReturnsProbabilitiesForAllClasses() { var token = new StringToken("money"); var probabilities = _classifier.CalculateProbabilities(token).ToList(); /*probabilities.Single(p => p.Class.Equals(_spamClass)) .Probability.Should() .BeApproximately(0.5D, 0.000001D, "because the token is known to be a ham and spam word"); probabilities.Single(p => p.Class.Equals(_hamClass)) .Probability.Should() .BeApproximately(0.5D, 0.000001D, "because the token is known to be a ham and spam word");*/ } [TestMethod] public void CalculateProbabilitiesWithMixedWordThatIsMoreLikelyHamThanSpamReturnsProbabilitiesForAllClasses() { var token = new StringToken("send"); var probabilities = _classifier.CalculateProbabilities(token).ToList(); /*probabilities.Single(p => p.Class.Equals(_spamClass)) .Probability.Should() .BeApproximately(1 / 3D, 0.000001D, "because the token is more likely to be a ham than spam word"); probabilities.Single(p => p.Class.Equals(_hamClass)) .Probability.Should() .BeApproximately(2 / 3D, 0.000001D, "because the token is more likely to be a ham than spam word");*/ } [TestMethod] public void CalculateProbabilitiesWithRareTokensAndSmoothingAlphaIsUnambiguous() { var token1 = new StringToken("rolex"); var token2 = new StringToken("unicorn"); var token3 = new StringToken("send"); const double smoothingAlpha = 1.0D; var probabilities = _classifier.CalculateProbabilities(new IToken[] { token1, token2, token3 }, smoothingAlpha).ToList(); /*probabilities.Single(p => p.Class.Equals(_spamClass)) .Probability.Should() .BeLessThan(0.5D, "because we used more ham than spam tokens"); probabilities.Single(p => p.Class.Equals(_hamClass)) .Probability.Should() .BeGreaterThan(0.5D, "because we used more ham than spam tokens");*/ } } }