natural 0.5.6 → 0.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/.dockerignore +2 -0
  2. package/.idea/misc.xml +6 -0
  3. package/.idea/modules.xml +8 -0
  4. package/.idea/natural.iml +12 -0
  5. package/.idea/vcs.xml +6 -0
  6. package/.idea/workspace.xml +511 -0
  7. package/.travis.yml +8 -1
  8. package/README.md +331 -40
  9. package/bayes_classifier.json +1 -1
  10. package/classifier.json +418 -0
  11. package/lib/natural/brill_pos_tagger/lib/Brill_POS_Tagger.js +8 -9
  12. package/lib/natural/brill_pos_tagger/lib/Brill_POS_Tester.js +5 -5
  13. package/lib/natural/brill_pos_tagger/lib/Brill_POS_Trainer.js +10 -6
  14. package/lib/natural/brill_pos_tagger/lib/Corpus.js +21 -16
  15. package/lib/natural/brill_pos_tagger/lib/Lexicon.js +22 -13
  16. package/lib/natural/brill_pos_tagger/lib/Predicate.js +2 -2
  17. package/lib/natural/brill_pos_tagger/lib/RuleTemplate.js +2 -2
  18. package/lib/natural/brill_pos_tagger/lib/RuleTemplates.js +132 -146
  19. package/lib/natural/brill_pos_tagger/lib/Sentence.js +41 -0
  20. package/lib/natural/brill_pos_tagger/lib/TransformationRule.js +10 -11
  21. package/lib/natural/classifiers/classifier.js +5 -3
  22. package/lib/natural/classifiers/maxent/Classifier.js +125 -0
  23. package/lib/natural/classifiers/maxent/Context.js +33 -0
  24. package/lib/natural/classifiers/maxent/Distribution.js +145 -0
  25. package/lib/natural/classifiers/maxent/Element.js +34 -0
  26. package/lib/natural/classifiers/maxent/Feature.js +88 -0
  27. package/lib/natural/classifiers/maxent/FeatureSet.js +67 -0
  28. package/lib/natural/classifiers/maxent/GISScaler.js +148 -0
  29. package/lib/natural/classifiers/maxent/POS/ME_Corpus.js +56 -0
  30. package/lib/natural/classifiers/maxent/POS/ME_Sentence.js +73 -0
  31. package/lib/natural/classifiers/maxent/POS/POS_Element.js +172 -0
  32. package/lib/natural/classifiers/maxent/Sample.js +141 -0
  33. package/lib/natural/classifiers/maxent/SimpleExample/SE_Element.js +49 -0
  34. package/lib/natural/distance/hamming_distance.js +52 -0
  35. package/lib/natural/distance/jaro-winkler_distance.js +16 -6
  36. package/lib/natural/distance/levenshtein_distance.js +2 -2
  37. package/lib/natural/index.js +21 -2
  38. package/lib/natural/inflectors/noun_inflector.js +5 -3
  39. package/lib/natural/ngrams/ngrams.js +83 -25
  40. package/lib/natural/sentiment/Basque/senticon_eu.json +21557 -0
  41. package/lib/natural/sentiment/Catalan/senticon_ca.json +36352 -0
  42. package/lib/natural/sentiment/Dutch/negations_du.json +3 -0
  43. package/lib/natural/sentiment/Dutch/pattern-sentiment-nl.json +39650 -0
  44. package/lib/natural/sentiment/English/negations_en.json +3 -0
  45. package/lib/natural/sentiment/English/pattern-sentiment-en.json +16024 -0
  46. package/lib/natural/sentiment/English/senticon_en.json +124197 -0
  47. package/lib/natural/sentiment/French/pattern-sentiment-fr.json +40906 -0
  48. package/lib/natural/sentiment/Galician/senticon_gl.json +24427 -0
  49. package/lib/natural/sentiment/Italian/pattern-sentiment-it.json +24522 -0
  50. package/lib/natural/sentiment/SentimentAnalyzer.js +116 -0
  51. package/lib/natural/sentiment/Spanish/afinnShortSortedSpanish.json +1655 -0
  52. package/lib/natural/sentiment/Spanish/negations_es.json +3 -0
  53. package/lib/natural/sentiment/Spanish/senticon_es.json +56722 -0
  54. package/lib/natural/sentiment/tools/README.md +31 -0
  55. package/lib/natural/sentiment/tools/XmlParser4PatternData.js +31 -0
  56. package/lib/natural/sentiment/tools/sentimentXmlParser.js +30 -0
  57. package/lib/natural/stemmers/indonesian/data/kata-dasar.json +29935 -0
  58. package/lib/natural/stemmers/indonesian/prefix_rules.js +10 -9
  59. package/lib/natural/stemmers/indonesian/stemmer_id.js +16 -15
  60. package/lib/natural/stemmers/indonesian/suffix_rules.js +2 -2
  61. package/lib/natural/stemmers/porter_stemmer_es.js +265 -199
  62. package/lib/natural/stemmers/porter_stemmer_fr.js +1 -1
  63. package/lib/natural/stemmers/porter_stemmer_nl.js +362 -0
  64. package/lib/natural/stemmers/stemmer_es.js +18 -12
  65. package/lib/natural/stemmers/stemmer_nl.js +64 -0
  66. package/lib/natural/tfidf/tfidf.js +27 -4
  67. package/lib/natural/tokenizers/aggressive_tokenizer_sv.js +1 -1
  68. package/lib/natural/tokenizers/aggressive_tokenizer_vi.js +37 -0
  69. package/lib/natural/tokenizers/orthography_matchers.js +33 -0
  70. package/lib/natural/tokenizers/regexp_tokenizer.js +24 -4
  71. package/lib/natural/tokenizers/sentence_tokenizer.js +1 -1
  72. package/lib/natural/wordnet/wordnet_file.js +7 -1
  73. package/lr_classifier.json +1 -1
  74. package/package.json +35 -23
  75. package/.npmignore +0 -4
  76. package/.vscode/temp.sql +0 -0
  77. package/Makefile +0 -38
  78. package/data/kata-dasar.txt +0 -29933
  79. package/package-lock.json +0 -79
  80. package/tests/stemmer_id_test.js +0 -361
@@ -20,6 +20,7 @@
20
20
  //var logger = log4js.getLogger();
21
21
 
22
22
  var Predicate = require("./Predicate");
23
+ var Sentence = require('./Sentence');
23
24
 
24
25
  //logger.setLevel('INFO');
25
26
 
@@ -42,11 +43,11 @@ TransformationRule.prototype.key = function() {
42
43
  return(this.literal.toString());
43
44
  };
44
45
 
45
- TransformationRule.prototype.apply = function(tagged_sentence, position) {
46
- if ((tagged_sentence[position][1] === this.old_category) ||
46
+ TransformationRule.prototype.apply = function(sentence, position) {
47
+ if ((sentence.taggedWords[position].tag === this.old_category) ||
47
48
  (this.old_category === category_wild_card)) {
48
- if (this.predicate.evaluate(tagged_sentence, position)) {
49
- tagged_sentence[position][1] = this.new_category;
49
+ if (this.predicate.evaluate(sentence, position)) {
50
+ sentence.taggedWords[position].tag = this.new_category;
50
51
  //logger.debug('TransformationRule.apply: changed category ' +
51
52
  //this.old_category + ' to ' + this.new_category +
52
53
  //' at position ' + position);
@@ -62,13 +63,13 @@ TransformationRule.prototype.apply = function(tagged_sentence, position) {
62
63
  // category to newTag
63
64
  TransformationRule.prototype.isApplicableAt = function(sentence, taggedSentence, i) {
64
65
  //logger.debug("TransformationRule.prototype.isApplicableAt: " + taggedSentence);
65
- var applies = (taggedSentence[i][1] === this.old_category) &&
66
+ var applies = (taggedSentence.taggedWords[i].tag === this.old_category) &&
66
67
  this.predicate.evaluate(taggedSentence, i);
67
68
  //logger.debug("TransformationRule.prototype.isApplicableAt: " + applies);
68
69
 
69
70
  // Set newTag to let the trainer know what the new tag would become
70
71
  if (applies) {
71
- sentence[i].newTag = this.new_category;
72
+ sentence.taggedWords[i].newTag = this.new_category;
72
73
  }
73
74
  return(applies);
74
75
  };
@@ -92,16 +93,14 @@ TransformationRule.prototype.prettyPrint = function() {
92
93
 
93
94
  // Applies the rule the given location (if it applies)
94
95
  TransformationRule.prototype.applyAt = function(sentence, i) {
95
- var taggedSentence = sentence.map(function(token) {
96
- return [token.token, token.tag];
97
- });
96
+ var taggedSentence = sentence.clone();
98
97
 
99
98
  //logger.debug("TransformationRule.prototype.applyAt: input sentence length: " + sentence.length);
100
99
  //logger.debug("TransformationRule.prototype.applyAt: tagged sentence length: " + taggedSentence.length);
101
100
 
102
- this.apply(taggedSentence, i);
101
+ this.apply(sentence, i);
103
102
  // Assign the new tag to the corpus site
104
- sentence[i].testTag = taggedSentence[i][1];
103
+ sentence.taggedWords[i].testTag = taggedSentence.taggedWords[i].tag;
105
104
  };
106
105
 
107
106
  // Calculate the net score of this rule
@@ -444,10 +444,12 @@ function setOptions(options){
444
444
  Classifier.prototype.addDocument = addDocument;
445
445
  Classifier.prototype.removeDocument = removeDocument;
446
446
  Classifier.prototype.train = train;
447
- Classifier.prototype.trainParallel = trainParallel;
448
- Classifier.prototype.trainParallelBatches = trainParallelBatches;
447
+ if (Threads) {
448
+ Classifier.prototype.trainParallel = trainParallel;
449
+ Classifier.prototype.trainParallelBatches = trainParallelBatches;
450
+ Classifier.prototype.retrainParallel = retrainParallel;
451
+ }
449
452
  Classifier.prototype.retrain = retrain;
450
- Classifier.prototype.retrainParallel = retrainParallel;
451
453
  Classifier.prototype.classify = classify;
452
454
  Classifier.prototype.textToFeatures = textToFeatures;
453
455
  Classifier.prototype.save = save;
@@ -0,0 +1,125 @@
1
+ /*
2
+ Classifier class that provides functionality for training and
3
+ classification
4
+ Copyright (C) 2017 Hugo W.L. ter Doest
5
+
6
+ This program is free software: you can redistribute it and/or modify
7
+ it under the terms of the GNU General Public License as published by
8
+ the Free Software Foundation, either version 3 of the License, or
9
+ (at your option) any later version.
10
+
11
+ This program is distributed in the hope that it will be useful,
12
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ GNU General Public License for more details.
15
+
16
+ You should have received a copy of the GNU General Public License
17
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
18
+ */
19
+
20
+ var fs = require('fs');
21
+
22
+ var Context = require('./Context');
23
+ var Element = require('./Element');
24
+ var Sample = require('./Sample');
25
+ var Scaler = require('./GISScaler');
26
+ var FeatureSet = require('./FeatureSet');
27
+
28
+ function Classifier(features, sample) {
29
+ if (features) {
30
+ this.features = features;
31
+ }
32
+ else {
33
+ this.features = new featureSet();
34
+ }
35
+ this.features = features;
36
+ if (sample) {
37
+ this.sample = sample;
38
+ }
39
+ else {
40
+ this.sample = new Sample();
41
+ }
42
+ }
43
+
44
+ // Loads a classifier from file.
45
+ // Caveat: feature functions are generated from the sample elements. You need
46
+ // to create your own specialisation of the Element class that can generate
47
+ // your own specific feature functions
48
+ Classifier.prototype.load = function(filename, elementClass, callback) {
49
+ fs.readFile(filename, 'utf8', function(err, data) {
50
+
51
+ if(!err) {
52
+ classifierData = JSON.parse(data);
53
+ var sample = new Sample();
54
+ classifierData.sample.elements.forEach(function(elementData) {
55
+ var elt = new elementClass(elementData.a, new Context(elementData.b.data));
56
+ sample.addElement(elt);
57
+ });
58
+ var featureSet = new FeatureSet();
59
+ sample.generateFeatures(featureSet);
60
+ var classifier = new Classifier(featureSet, sample);
61
+ callback(err, classifier);
62
+ }
63
+ else {
64
+ if(callback) {
65
+ callback(err);
66
+ }
67
+ }
68
+ });
69
+ };
70
+
71
+ Classifier.prototype.save = function(filename, callback) {
72
+ var data = JSON.stringify(this, null, 2);
73
+ var classifier = this;
74
+ fs.writeFile(filename, data, 'utf8', function(err) {
75
+ if(callback) {
76
+ callback(err, err ? null : classifier);
77
+ }
78
+ });
79
+ };
80
+
81
+ Classifier.prototype.addElement = function(x) {
82
+ this.sample.addElement(x);
83
+ };
84
+
85
+ Classifier.prototype.addDocument = function(context, classification, elementClass) {
86
+ Classifier.prototype.addElement(new elementClass(classification, context));
87
+ };
88
+
89
+ Classifier.prototype.train = function(maxIterations, minImprovement, approxExpectation) {
90
+ this.scaler = new Scaler(this.features, this.sample);
91
+ this.p = this.scaler.run(maxIterations, minImprovement, approxExpectation);
92
+ };
93
+
94
+ Classifier.prototype.getClassifications = function(b) {
95
+ var scores = [];
96
+ var that = this;
97
+ this.sample.getClasses().forEach(function(a) {
98
+ var x = new Element(a, b);
99
+ scores.push({
100
+ "label": a,
101
+ "value": that.p.calculateAPriori(x)
102
+ });
103
+ });
104
+ return scores;
105
+ };
106
+
107
+ Classifier.prototype.classify = function(b) {
108
+ var scores = this.getClassifications(b);
109
+ // Sort the scores in an array
110
+ scores.sort(function(a, b) {
111
+ return b.value - a.value;
112
+ });
113
+ // Check if the classifier discriminates
114
+ var min = scores[scores.length - 1].value;
115
+ var max = scores[0].value;
116
+ if (min === max) {
117
+ return "";
118
+ }
119
+ else {
120
+ // Return the highest scoring classes
121
+ return scores[0].label;
122
+ }
123
+ };
124
+
125
+ module.exports = Classifier;
@@ -0,0 +1,33 @@
1
+ /*
2
+ Context class
3
+ Copyright (C) 2017 Hugo W.L. ter Doest
4
+
5
+ This program is free software: you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License as published by
7
+ the Free Software Foundation, either version 3 of the License, or
8
+ (at your option) any later version.
9
+
10
+ This program is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU General Public License for more details.
14
+
15
+ You should have received a copy of the GNU General Public License
16
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+ */
18
+
19
+ var stringify = require('json-stable-stringify');
20
+
21
+ function Context(data) {
22
+ this.data = data;
23
+ }
24
+
25
+ // Create a predictable key string for looking up in a hash
26
+ Context.prototype.toString = function() {
27
+ if (!this.key) {
28
+ this.key = stringify(this.data);
29
+ }
30
+ return this.key;
31
+ };
32
+
33
+ module.exports = Context;
@@ -0,0 +1,145 @@
1
+ /*
2
+ Distribution class for probability distributions
3
+ Copyright (C) 2017 Hugo W.L. ter Doest
4
+
5
+ This program is free software: you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License as published by
7
+ the Free Software Foundation, either version 3 of the License, or
8
+ (at your option) any later version.
9
+
10
+ This program is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU General Public License for more details.
14
+
15
+ You should have received a copy of the GNU General Public License
16
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+ */
18
+
19
+ var Element = require('./Element');
20
+
21
+ function Distribution(alpha, featureSet, sample) {
22
+ this.alpha = alpha;
23
+ this.featureSet = featureSet;
24
+ this.sample = sample;
25
+ }
26
+
27
+ // Returns the distribution as a string that can be stored for later usage
28
+ Distribution.prototype.toString = function() {
29
+
30
+ }
31
+
32
+ Distribution.prototype.weight = function(x) {
33
+ var product = 1;
34
+ var that = this;
35
+
36
+ this.alpha.forEach(function(alpha_j, j) {
37
+ product *= Math.pow(alpha_j, that.featureSet.getFeatures()[j].apply(x));
38
+ });
39
+ return product;
40
+ };
41
+
42
+ Distribution.prototype.calculateAPriori = function(x) {
43
+ if (!this.aPriorisBeforeNormalisation[x.toString()]) {
44
+ this.aPriorisBeforeNormalisation[x.toString()] = this.weight(x);
45
+ }
46
+ return this.aPriorisBeforeNormalisation[x.toString()];// / this.aPrioriNormalisationConstant;
47
+ };
48
+
49
+ // Memoize a priori probabilities of sample elements
50
+ Distribution.prototype.prepareWeights = function() {
51
+ this.aPriorisBeforeNormalisation = {};
52
+ this.aPrioriNormalisationConstant = 0;
53
+ var sum = 0;
54
+ var that = this;
55
+ this.sample.elements.forEach(function(x) {
56
+ that.aPriorisBeforeNormalisation[x.toString()] = that.weight(x);
57
+ sum += that.aPriorisBeforeNormalisation[x.toString()];
58
+ });
59
+ this.aPrioriNormalisationConstant = sum;
60
+ };
61
+
62
+ Distribution.prototype.calculateAPosteriori = function(x) {
63
+ if (!this.aPriorisBeforeNormalisation[x.toString()]) {
64
+ this.aPriorisBeforeNormalisation[x.toString()] = this.weight(x);
65
+ }
66
+ if (!this.aPosterioriNormalisationConstants[x.b.toString()]) {
67
+ this.aPosterioriNormalisationConstants[x.b.toString()] = this.aPosterioriNormalisation(x.b);
68
+ }
69
+ return this.aPriorisBeforeNormalisation[x] / this.aPosterioriNormalisationConstants[x.b.toString()];
70
+ };
71
+
72
+ Distribution.prototype.aPosterioriNormalisation = function(b) {
73
+ var sum = 0;
74
+
75
+ var that = this;
76
+ this.sample.getClasses().forEach(function(a) {
77
+ sum += that.weight(new Element(a, b));
78
+ });
79
+
80
+ return(sum);
81
+ };
82
+
83
+ // Memoize a posteriori probabilities of sample elements
84
+ Distribution.prototype.prepareAPosterioris = function() {
85
+ this.aPosterioriNormalisationConstants = {};
86
+
87
+ var contextSeen = {};
88
+ var that = this;
89
+ this.sample.elements.forEach(function(sampleElement) {
90
+ var context = sampleElement.b;
91
+ if (!contextSeen[context]) {
92
+ contextSeen[context] = true;
93
+ that.aPosterioriNormalisationConstants[context] =
94
+ that.aPosterioriNormalisation(context);
95
+ }
96
+ });
97
+ };
98
+
99
+ // Memoize all probabilities of sample elements
100
+ Distribution.prototype.prepare = function() {
101
+ this.prepareWeights();
102
+ //console.log("Weights prepared");
103
+ this.prepareAPosterioris();
104
+ };
105
+
106
+ // Relative entropy between observered distribution and derived distribution
107
+ Distribution.prototype.KullbackLieblerDistance = function() {
108
+ var sum = 0;
109
+ var that = this;
110
+ this.sample.elements.forEach(function(x) {
111
+ sum += that.sample.observedProbability(x) * Math.log(that.sample.observedProbability(x) / that.calculateAPriori(x));
112
+ });
113
+ return sum;
114
+ };
115
+
116
+ Distribution.prototype.logLikelihood = function() {
117
+ var sum = 0;
118
+ var that = this;
119
+ this.sample.elements.forEach(function(x) {
120
+ sum += that.sample.observedProbability(x) * Math.log(that.calculateAPriori(x));
121
+ });
122
+ return sum;
123
+ };
124
+
125
+ Distribution.prototype.entropy = function() {
126
+ var sum = 0;
127
+ var that = this;
128
+ this.sample.elements.forEach(function(x) {
129
+ var p = that.calculateAPriori(x);
130
+ sum += p * Math.log(p);
131
+ });
132
+ return sum;
133
+ };
134
+
135
+ Distribution.prototype.checkSum = function() {
136
+ var sum = 0;
137
+ var that = this;
138
+ this.sample.elements.forEach(function(x) {
139
+ sum += that.calculateAPriori(x);
140
+ });
141
+ //console.log("Distribution.checkSum is " + sum);
142
+ return sum;
143
+ }
144
+
145
+ module.exports = Distribution;
@@ -0,0 +1,34 @@
1
+ /*
2
+ Element class for elements in the event space
3
+ Copyright (C) 2017 Hugo W.L. ter Doest
4
+
5
+ This program is free software: you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License as published by
7
+ the Free Software Foundation, either version 3 of the License, or
8
+ (at your option) any later version.
9
+
10
+ This program is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU General Public License for more details.
14
+
15
+ You should have received a copy of the GNU General Public License
16
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+ */
18
+
19
+ var Feature = require('./Feature');
20
+
21
+ // a is class and b is context
22
+ function Element(a, b) {
23
+ this.a = a;
24
+ this.b = b;
25
+ }
26
+
27
+ Element.prototype.toString = function() {
28
+ if (!this.key) {
29
+ this.key = this.a + this.b.toString();
30
+ }
31
+ return this.key;
32
+ };
33
+
34
+ module.exports = Element;
@@ -0,0 +1,88 @@
1
+ /*
2
+ Feature class for features that fire (or don't) on combinations of context
3
+ and class
4
+ Copyright (C) 2017 Hugo W.L. ter Doest
5
+
6
+ This program is free software: you can redistribute it and/or modify
7
+ it under the terms of the GNU General Public License as published by
8
+ the Free Software Foundation, either version 3 of the License, or
9
+ (at your option) any later version.
10
+
11
+ This program is distributed in the hope that it will be useful,
12
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ GNU General Public License for more details.
15
+
16
+ You should have received a copy of the GNU General Public License
17
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
18
+ */
19
+
20
+
21
+ function Feature(f, name, parameters) {
22
+ this.evaluate = f;
23
+ this.name = name;
24
+ this.parameters = parameters;
25
+
26
+ var tmp = "";
27
+ parameters.forEach(function(par) {
28
+ tmp += par + "|";
29
+ });
30
+ this.parametersKey = tmp.substr(0, tmp.length - 1);
31
+ }
32
+
33
+ Feature.prototype.apply = function(x) {
34
+ return this.evaluate(x);
35
+ };
36
+
37
+ Feature.prototype.expectationApprox = function(p, sample) {
38
+ var totalSum = 0;
39
+ var that = this;
40
+ var sum = 0;
41
+ var seen = {};
42
+ var A = sample.getClasses();
43
+ sample.elements.forEach(function(sampleElement) {
44
+ var b_i = sampleElement.b;
45
+
46
+ if (!seen[b_i.toString()]) {
47
+ seen[b_i.toString()] = true;
48
+ var Element = require('./Element');
49
+
50
+ A.forEach(function(a) {
51
+ var x = new Element(a, b_i);
52
+ sum += sample.observedProbabilityOfContext(b_i) * p.calculateAPosteriori(x) * that.apply(x);
53
+ });
54
+ }
55
+ });
56
+ return sum;
57
+ };
58
+
59
+ // Diect calculation of expected value of this feature according to distribution p
60
+ // In real-life applications with a lot of features this is not tractable
61
+ Feature.prototype.expectation = function(p, A, B) {
62
+ var sum = 0;
63
+ var that = this;
64
+ A.forEach(function(a) {
65
+ B.forEach(function(b) {
66
+ var x = new Element(a, b);
67
+ sum += (p.calculateAPriori(x) * that.apply(x));
68
+ });
69
+ });
70
+ return sum;
71
+ };
72
+
73
+ // Observed expectation of this feature in the sample
74
+ Feature.prototype.observedExpectation = function(sample) {
75
+ if (this.observedExpect) {
76
+ return this.observedExpect;
77
+ }
78
+ var N = sample.size();
79
+ var sum = 0;
80
+ var that = this;
81
+ sample.elements.forEach(function(x) {
82
+ sum += that.apply(x);
83
+ });
84
+ this.observedExpect = sum / N;
85
+ return this.observedExpect;
86
+ };
87
+
88
+ module.exports = Feature;
@@ -0,0 +1,67 @@
1
+ /*
2
+ Feature set class for administrating a set of unique feature
3
+ Copyright (C) 2017 Hugo W.L. ter Doest
4
+
5
+ This program is free software: you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License as published by
7
+ the Free Software Foundation, either version 3 of the License, or
8
+ (at your option) any later version.
9
+
10
+ This program is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU General Public License for more details.
14
+
15
+ You should have received a copy of the GNU General Public License
16
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+ */
18
+
19
+
20
+ function FeatureSet() {
21
+ this.features = [];
22
+ this.map = {};
23
+ }
24
+
25
+ // Returns true if the feature did not exist and was added
26
+ FeatureSet.prototype.addFeature = function(feature) {
27
+ if (!this.featureExists(feature)) {
28
+ this.map[feature.name +" | " + feature.parametersKey] = true;
29
+ this.features.push(feature);
30
+ //console.log("FeatureSet.addFeature: feature added: " + feature.name + " - " + feature.parametersKey);
31
+ return true;
32
+ }
33
+ else {
34
+ return false;
35
+ }
36
+ };
37
+
38
+ FeatureSet.prototype.featureExists = function(feature) {
39
+ if (this.map[feature.name +" | " + feature.parametersKey]) {
40
+ //console.log("FeatureSet.featureExists: feature already exists: " +
41
+ // feature.name + " - " + feature.parameters);
42
+ return true;
43
+ }
44
+ else {
45
+ return false;
46
+ }
47
+ };
48
+
49
+ // Returns an array of features
50
+ // If the available array this.features is up to date it is returned immediately
51
+ FeatureSet.prototype.getFeatures = function() {
52
+ return this.features;
53
+ };
54
+
55
+ FeatureSet.prototype.size = function() {
56
+ return this.features.length;
57
+ };
58
+
59
+ FeatureSet.prototype.prettyPrint = function() {
60
+ var s = "";
61
+ Object.keys(this.map).forEach(function(key) {
62
+ s += key + "\n";
63
+ });
64
+ return s;
65
+ };
66
+
67
+ module.exports = FeatureSet;