natural 6.10.0 → 6.10.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 (63) hide show
  1. package/.github/workflows/node.js.yml +1 -1
  2. package/.github/workflows/npm-publish.yml +4 -4
  3. package/lib/natural/brill_pos_tagger/lib/Brill_POS_Tagger.js +33 -31
  4. package/lib/natural/brill_pos_tagger/lib/Brill_POS_Tester.js +33 -35
  5. package/lib/natural/brill_pos_tagger/lib/Brill_POS_Trainer.js +326 -324
  6. package/lib/natural/brill_pos_tagger/lib/Corpus.js +140 -138
  7. package/lib/natural/brill_pos_tagger/lib/Lexicon.js +78 -76
  8. package/lib/natural/brill_pos_tagger/lib/Predicate.js +19 -17
  9. package/lib/natural/brill_pos_tagger/lib/RuleSet.js +58 -56
  10. package/lib/natural/brill_pos_tagger/lib/RuleTemplate.js +11 -9
  11. package/lib/natural/brill_pos_tagger/lib/Sentence.js +21 -20
  12. package/lib/natural/brill_pos_tagger/lib/TransformationRule.js +58 -58
  13. package/lib/natural/classifiers/bayes_classifier.js +24 -29
  14. package/lib/natural/classifiers/classifier.js +136 -121
  15. package/lib/natural/classifiers/logistic_regression_classifier.js +33 -37
  16. package/lib/natural/classifiers/maxent/Classifier.js +81 -79
  17. package/lib/natural/classifiers/maxent/Context.js +11 -9
  18. package/lib/natural/classifiers/maxent/Distribution.js +107 -105
  19. package/lib/natural/classifiers/maxent/Element.js +12 -10
  20. package/lib/natural/classifiers/maxent/Feature.js +56 -54
  21. package/lib/natural/classifiers/maxent/FeatureSet.js +40 -38
  22. package/lib/natural/classifiers/maxent/GISScaler.js +110 -109
  23. package/lib/natural/classifiers/maxent/POS/ME_Corpus.js +26 -31
  24. package/lib/natural/classifiers/maxent/POS/ME_Sentence.js +37 -42
  25. package/lib/natural/classifiers/maxent/POS/POS_Element.js +119 -124
  26. package/lib/natural/classifiers/maxent/Sample.js +96 -94
  27. package/lib/natural/classifiers/maxent/SimpleExample/SE_Element.js +14 -20
  28. package/lib/natural/inflectors/fr/count_inflector.js +1 -1
  29. package/lib/natural/inflectors/fr/noun_inflector.js +179 -196
  30. package/lib/natural/inflectors/ja/noun_inflector.js +67 -84
  31. package/lib/natural/inflectors/noun_inflector.js +124 -139
  32. package/lib/natural/inflectors/present_verb_inflector.js +34 -48
  33. package/lib/natural/inflectors/singular_plural_inflector.js +62 -61
  34. package/lib/natural/sentiment/SentimentAnalyzer.js +1 -1
  35. package/lib/natural/tfidf/tfidf.js +118 -114
  36. package/lib/natural/tokenizers/aggressive_tokenizer.js +11 -15
  37. package/lib/natural/tokenizers/aggressive_tokenizer_es.js +5 -9
  38. package/lib/natural/tokenizers/aggressive_tokenizer_fa.js +16 -20
  39. package/lib/natural/tokenizers/aggressive_tokenizer_fr.js +5 -9
  40. package/lib/natural/tokenizers/aggressive_tokenizer_hi.js +5 -10
  41. package/lib/natural/tokenizers/aggressive_tokenizer_id.js +13 -17
  42. package/lib/natural/tokenizers/aggressive_tokenizer_it.js +5 -9
  43. package/lib/natural/tokenizers/aggressive_tokenizer_nl.js +5 -9
  44. package/lib/natural/tokenizers/aggressive_tokenizer_no.js +7 -11
  45. package/lib/natural/tokenizers/aggressive_tokenizer_pl.js +12 -17
  46. package/lib/natural/tokenizers/aggressive_tokenizer_pt.js +9 -13
  47. package/lib/natural/tokenizers/aggressive_tokenizer_ru.js +12 -17
  48. package/lib/natural/tokenizers/aggressive_tokenizer_sv.js +8 -12
  49. package/lib/natural/tokenizers/aggressive_tokenizer_uk.js +35 -17
  50. package/lib/natural/tokenizers/aggressive_tokenizer_vi.js +5 -10
  51. package/lib/natural/tokenizers/regexp_tokenizer.js +50 -41
  52. package/lib/natural/tokenizers/sentence_tokenizer.js +15 -18
  53. package/lib/natural/tokenizers/sentence_tokenizer_parser.js +4 -9
  54. package/lib/natural/tokenizers/tokenizer.js +5 -24
  55. package/lib/natural/tokenizers/tokenizer_case.js +16 -31
  56. package/lib/natural/trie/trie.js +161 -159
  57. package/lib/natural/util/directed_edge.js +49 -0
  58. package/lib/natural/util/edge_weighted_digraph.js +54 -74
  59. package/lib/natural/util/index.js +1 -0
  60. package/lib/natural/util/longest_path_tree.js +54 -52
  61. package/lib/natural/util/shortest_path_tree.js +56 -54
  62. package/lib/natural/util/topological.js +17 -15
  63. package/package.json +2 -2
@@ -30,401 +30,403 @@ const Sentence = require('./Sentence')
30
30
  // Training continues as long as there are rules with a positive score
31
31
  // that have not been selected before
32
32
  const minScore = 0
33
-
34
33
  // After training rules with a score below scoreThreshold are pruned
35
- function BrillPOSTrainer (ruleScoreThreshold) {
36
- if (ruleScoreThreshold) {
37
- this.ruleScoreThreshold = ruleScoreThreshold
38
- } else {
39
- this.ruleScoreThreshold = 1
34
+
35
+ class BrillPOSTrainer {
36
+ constructor (ruleScoreThreshold) {
37
+ if (ruleScoreThreshold) {
38
+ this.ruleScoreThreshold = ruleScoreThreshold
39
+ } else {
40
+ this.ruleScoreThreshold = 1
41
+ }
40
42
  }
41
- }
42
43
 
43
- // Return the highest scoring rule from the rule set
44
- BrillPOSTrainer.prototype.selectHighRule = function () {
45
- let highestRule = null
44
+ // Return the highest scoring rule from the rule set
45
+ selectHighRule () {
46
+ let highestRule = null
46
47
 
47
- // Walk through the map and find the rule with highest score
48
- this.positiveRules.getRules().forEach(function (rule) {
49
- if (highestRule === null) {
50
- if (!rule.hasBeenSelectedAsHighRuleBefore) {
51
- highestRule = rule
52
- }
53
- } else {
54
- if ((rule.score() > highestRule.score()) &&
55
- !rule.hasBeenSelectedAsHighRuleBefore) {
56
- highestRule = rule
48
+ // Walk through the map and find the rule with highest score
49
+ this.positiveRules.getRules().forEach(function (rule) {
50
+ if (highestRule === null) {
51
+ if (!rule.hasBeenSelectedAsHighRuleBefore) {
52
+ highestRule = rule
53
+ }
54
+ } else {
55
+ if ((rule.score() > highestRule.score()) &&
56
+ !rule.hasBeenSelectedAsHighRuleBefore) {
57
+ highestRule = rule
58
+ }
57
59
  }
58
- }
59
- })
60
+ })
60
61
 
61
- if (highestRule !== null) {
62
- highestRule.hasBeenSelectedAsHighRuleBefore = true
62
+ if (highestRule !== null) {
63
+ highestRule.hasBeenSelectedAsHighRuleBefore = true
64
+ }
65
+ // Return the rule with the highest score
66
+ return highestRule
63
67
  }
64
- // Return the rule with the highest score
65
- return highestRule
66
- }
67
68
 
68
- BrillPOSTrainer.prototype.mapRuleToSite = function (rule, i, j) {
69
- if (!this.mapRuleToSites[rule.key()]) {
70
- this.mapRuleToSites[rule.key()] = {}
71
- }
72
- if (!this.mapRuleToSites[rule.key()][i]) {
73
- this.mapRuleToSites[rule.key()][i] = {}
69
+ mapRuleToSite (rule, i, j) {
70
+ if (!this.mapRuleToSites[rule.key()]) {
71
+ this.mapRuleToSites[rule.key()] = {}
72
+ }
73
+ if (!this.mapRuleToSites[rule.key()][i]) {
74
+ this.mapRuleToSites[rule.key()][i] = {}
75
+ }
76
+ this.mapRuleToSites[rule.key()][i][j] = true
74
77
  }
75
- this.mapRuleToSites[rule.key()][i][j] = true
76
- }
77
78
 
78
- BrillPOSTrainer.prototype.mapSiteToRule = function (i, j, rule) {
79
- if (!this.mapSiteToRules[i]) {
80
- this.mapSiteToRules[i] = {}
81
- }
82
- if (!this.mapSiteToRules[i][j]) {
83
- this.mapSiteToRules[i][j] = {}
79
+ mapSiteToRule (i, j, rule) {
80
+ if (!this.mapSiteToRules[i]) {
81
+ this.mapSiteToRules[i] = {}
82
+ }
83
+ if (!this.mapSiteToRules[i][j]) {
84
+ this.mapSiteToRules[i][j] = {}
85
+ }
86
+ this.mapSiteToRules[i][j][rule.key()] = rule
84
87
  }
85
- this.mapSiteToRules[i][j][rule.key()] = rule
86
- }
87
88
 
88
- BrillPOSTrainer.prototype.associateSiteWithRule = function (i, j, rule) {
89
- this.mapRuleToSite(rule, i, j)
90
- this.mapSiteToRule(i, j, rule)
91
- }
89
+ associateSiteWithRule (i, j, rule) {
90
+ this.mapRuleToSite(rule, i, j)
91
+ this.mapSiteToRule(i, j, rule)
92
+ }
92
93
 
93
- BrillPOSTrainer.prototype.siteIsAssociatedWithRule = function (i, j, rule) {
94
- if (this.mapSiteToRules[i]) {
95
- if (this.mapSiteToRules[i][j]) {
96
- if (this.mapSiteToRules[i][j][rule.key()]) {
97
- return true
94
+ siteIsAssociatedWithRule (i, j, rule) {
95
+ if (this.mapSiteToRules[i]) {
96
+ if (this.mapSiteToRules[i][j]) {
97
+ if (this.mapSiteToRules[i][j][rule.key()]) {
98
+ return true
99
+ }
98
100
  }
99
101
  }
102
+ return false
100
103
  }
101
- return false
102
- }
103
104
 
104
- // Returns an array of all sites associated with rule
105
- BrillPOSTrainer.prototype.getSites = function (rule) {
106
- const that = this
107
- const result = []
108
- Object.keys(this.mapRuleToSites[rule.key()]).forEach(function (i) {
109
- Object.keys(that.mapRuleToSites[rule.key()][i]).forEach(function (j) {
110
- // Unary plus the convert hash keys i and j to integer
111
- result.push([+i, +j])
105
+ // Returns an array of all sites associated with rule
106
+ getSites (rule) {
107
+ const that = this
108
+ const result = []
109
+ Object.keys(this.mapRuleToSites[rule.key()]).forEach(function (i) {
110
+ Object.keys(that.mapRuleToSites[rule.key()][i]).forEach(function (j) {
111
+ // Unary plus the convert hash keys i and j to integer
112
+ result.push([+i, +j])
113
+ })
112
114
  })
113
- })
114
- // logger.debug("BrillPOSTrainer.prototype.getSites: sites " + JSON.stringify(result));
115
- return (result)
116
- }
115
+ // logger.debug("BrillPOSTrainer.prototype.getSites: sites " + JSON.stringify(result));
116
+ return (result)
117
+ }
117
118
 
118
- // Returns an array of all rules associated with the site
119
- BrillPOSTrainer.prototype.getRules = function (i, j) {
120
- let result = []
121
- const that = this
119
+ // Returns an array of all rules associated with the site
120
+ getRules (i, j) {
121
+ let result = []
122
+ const that = this
122
123
 
123
- if (this.mapSiteToRules[i]) {
124
- if (this.mapSiteToRules[i][j]) {
125
- result = Object.keys(this.mapSiteToRules[i][j]).map(function (key) {
126
- return that.mapSiteToRules[i][j][key]
127
- })
124
+ if (this.mapSiteToRules[i]) {
125
+ if (this.mapSiteToRules[i][j]) {
126
+ result = Object.keys(this.mapSiteToRules[i][j]).map(function (key) {
127
+ return that.mapSiteToRules[i][j][key]
128
+ })
129
+ }
128
130
  }
131
+ return result
129
132
  }
130
- return result
131
- }
132
133
 
133
- BrillPOSTrainer.prototype.disconnectSiteFromRule = function (i, j, rule) {
134
- // mapRuleToSites
135
- if (this.mapRuleToSites[rule.key()]) {
136
- if (this.mapRuleToSites[rule.key()][i]) {
137
- if (this.mapRuleToSites[rule.key()][i][j]) {
138
- delete this.mapRuleToSites[rule.key()][i][j]
134
+ disconnectSiteFromRule (i, j, rule) {
135
+ // mapRuleToSites
136
+ if (this.mapRuleToSites[rule.key()]) {
137
+ if (this.mapRuleToSites[rule.key()][i]) {
138
+ if (this.mapRuleToSites[rule.key()][i][j]) {
139
+ delete this.mapRuleToSites[rule.key()][i][j]
140
+ }
139
141
  }
140
142
  }
141
- }
142
143
 
143
- // mapSiteToRules
144
- if (this.mapSiteToRules[i]) {
145
- if (this.mapSiteToRules[i][j]) {
146
- if (this.mapSiteToRules[i][j][rule.key()]) {
147
- delete this.mapSiteToRules[i][j][rule.key()]
144
+ // mapSiteToRules
145
+ if (this.mapSiteToRules[i]) {
146
+ if (this.mapSiteToRules[i][j]) {
147
+ if (this.mapSiteToRules[i][j][rule.key()]) {
148
+ delete this.mapSiteToRules[i][j][rule.key()]
149
+ }
148
150
  }
149
151
  }
150
152
  }
151
- }
152
153
 
153
- // Adjusts the score of the rule at position i, j of the corpus
154
- BrillPOSTrainer.prototype.scoreRule = function (rule, i, j) {
155
- // logger.debug("BrillPOSTrainer.prototype.scoreRule: entry");
156
- const token = this.corpus.sentences[i].taggedWords[j]
157
- const rightTag = token.tag
158
- const oldTag = token.testTag
159
- const newTag = token.newTag
160
- if (rightTag !== oldTag) {
161
- // Old tag is wrong
162
- if (newTag === rightTag) {
163
- // New tag is right
164
- rule.positive++
165
- // If the score changes, it may be selected again as highest scoring rule
166
- rule.hasBeenSelectedAsHighRuleBefore = false
167
- // logger.debug("BrillPOSTrainer.prototype.scoreRule: positive: " + rule.key() + "\t score: " + rule.positive);
168
- } else {
169
- // New tag is wrong as well --> neutral
170
- rule.neutral++
171
- // logger.debug("BrillPOSTrainer.prototype.scoreRule: neutral: " + rule.key() + "\t score: " + rule.neutral);
172
- }
173
- } else {
174
- // Old tag is right
175
- if (newTag === rightTag) {
176
- // New tag is right --> neutral
177
- rule.neutral++
178
- // logger.debug("BrillPOSTrainer.prototype.scoreRule: neutral: " + rule.key() + "\t score: " + rule.neutral);
154
+ // Adjusts the score of the rule at position i, j of the corpus
155
+ scoreRule (rule, i, j) {
156
+ // logger.debug("BrillPOSTrainer.prototype.scoreRule: entry");
157
+ const token = this.corpus.sentences[i].taggedWords[j]
158
+ const rightTag = token.tag
159
+ const oldTag = token.testTag
160
+ const newTag = token.newTag
161
+ if (rightTag !== oldTag) {
162
+ // Old tag is wrong
163
+ if (newTag === rightTag) {
164
+ // New tag is right
165
+ rule.positive++
166
+ // If the score changes, it may be selected again as highest scoring rule
167
+ rule.hasBeenSelectedAsHighRuleBefore = false
168
+ // logger.debug("BrillPOSTrainer.prototype.scoreRule: positive: " + rule.key() + "\t score: " + rule.positive);
169
+ } else {
170
+ // New tag is wrong as well --> neutral
171
+ rule.neutral++
172
+ // logger.debug("BrillPOSTrainer.prototype.scoreRule: neutral: " + rule.key() + "\t score: " + rule.neutral);
173
+ }
179
174
  } else {
180
- // New tag is false
181
- rule.negative++
182
- // If the score changes, it may be selected again as highest scoring rule
183
- rule.hasBeenSelectedAsHighRuleBefore = false
184
- // logger.debug("BrillPOSTrainer.prototype.scoreRule: negative: " + rule.key() + "\t score: " + rule.negative);
175
+ // Old tag is right
176
+ if (newTag === rightTag) {
177
+ // New tag is right --> neutral
178
+ rule.neutral++
179
+ // logger.debug("BrillPOSTrainer.prototype.scoreRule: neutral: " + rule.key() + "\t score: " + rule.neutral);
180
+ } else {
181
+ // New tag is false
182
+ rule.negative++
183
+ // If the score changes, it may be selected again as highest scoring rule
184
+ rule.hasBeenSelectedAsHighRuleBefore = false
185
+ // logger.debug("BrillPOSTrainer.prototype.scoreRule: negative: " + rule.key() + "\t score: " + rule.negative);
186
+ }
185
187
  }
188
+ // logger.debug("BrillPOSTrainer.prototype.scoreRule: exit");
186
189
  }
187
- // logger.debug("BrillPOSTrainer.prototype.scoreRule: exit");
188
- }
189
190
 
190
- // Generate positive rules for this given site using templates
191
- BrillPOSTrainer.prototype.generatePositiveRules = function (i, j) {
192
- const sentence = this.corpus.sentences[i]
193
- const token = sentence.taggedWords[j]
194
- // A positive rule should trigger on the currently assigned testTag
195
- const oldTag = token.testTag
196
- // logger.debug("BrillPOSTrainer.prototype.generatePositiveRules: oldTag " + oldTag);
197
- // It should assign the right tag as given by the corpus
198
- const newTag = token.tag
199
- // logger.debug("BrillPOSTrainer.prototype.generatePositiveRules: newTag " + newTag);
200
-
201
- const newRules = new RuleSet()
202
- // Exit if testTag already is the right tag --> will not result in positive rules
203
- if (oldTag === newTag) {
204
- return newRules
205
- }
191
+ // Generate positive rules for this given site using templates
192
+ generatePositiveRules (i, j) {
193
+ const sentence = this.corpus.sentences[i]
194
+ const token = sentence.taggedWords[j]
195
+ // A positive rule should trigger on the currently assigned testTag
196
+ const oldTag = token.testTag
197
+ // logger.debug("BrillPOSTrainer.prototype.generatePositiveRules: oldTag " + oldTag);
198
+ // It should assign the right tag as given by the corpus
199
+ const newTag = token.tag
200
+ // logger.debug("BrillPOSTrainer.prototype.generatePositiveRules: newTag " + newTag);
201
+
202
+ const newRules = new RuleSet()
203
+ // Exit if testTag already is the right tag --> will not result in positive rules
204
+ if (oldTag === newTag) {
205
+ return newRules
206
+ }
206
207
 
207
- this.templates.forEach(function (template) {
208
- if (template.windowFitsSite(sentence, j)) {
209
- if (template.meta.nrParameters === 1) {
210
- template.meta.parameter1Values(sentence, j).forEach(function (value) {
211
- newRules.addRule(new TransformationRule(oldTag, newTag, template.predicateName, value))
212
- })
213
- } else {
214
- if (template.meta.nrParameters === 2) {
215
- template.meta.parameter1Values(sentence, j).forEach(function (value1) {
216
- template.meta.parameter2Values(sentence, j).forEach(function (value2) {
217
- newRules.addRule(new TransformationRule(oldTag, newTag, template.predicateName, value1, value2))
218
- })
208
+ this.templates.forEach(function (template) {
209
+ if (template.windowFitsSite(sentence, j)) {
210
+ if (template.meta.nrParameters === 1) {
211
+ template.meta.parameter1Values(sentence, j).forEach(function (value) {
212
+ newRules.addRule(new TransformationRule(oldTag, newTag, template.predicateName, value))
219
213
  })
220
214
  } else {
221
- // 0 paramaters
222
- newRules.addRule(new TransformationRule(oldTag, newTag, template.predicateName))
215
+ if (template.meta.nrParameters === 2) {
216
+ template.meta.parameter1Values(sentence, j).forEach(function (value1) {
217
+ template.meta.parameter2Values(sentence, j).forEach(function (value2) {
218
+ newRules.addRule(new TransformationRule(oldTag, newTag, template.predicateName, value1, value2))
219
+ })
220
+ })
221
+ } else {
222
+ // 0 paramaters
223
+ newRules.addRule(new TransformationRule(oldTag, newTag, template.predicateName))
224
+ }
223
225
  }
224
226
  }
225
- }
226
- })
227
- return newRules
228
- }
227
+ })
228
+ return newRules
229
+ }
229
230
 
230
- // Finds all rules that are applicable at some site
231
- BrillPOSTrainer.prototype.scanForPositiveRules = function () {
232
- // logger.debug("BrillPOSTrainer.prototype.scanForPositiveRules: entry");
233
- const that = this
234
- this.corpus.sentences.forEach(function (sentence, i) {
235
- sentence.taggedWords.forEach(function (token, j) {
236
- // logger.debug("BrillPOSTrainer.prototype.scanForPositiveRules: sentence no " + i);
237
- const newRules = that.generatePositiveRules(i, j)
238
- newRules.getRules().forEach(function (rule) {
239
- that.positiveRules.addRule(rule)
240
- // logger.debug("BrillPOSTrainer.prototype.scanForPositiveRules: nrRules " + that.positiveRules.nrRules());
231
+ // Finds all rules that are applicable at some site
232
+ scanForPositiveRules () {
233
+ // logger.debug("BrillPOSTrainer.prototype.scanForPositiveRules: entry");
234
+ const that = this
235
+ this.corpus.sentences.forEach(function (sentence, i) {
236
+ sentence.taggedWords.forEach(function (token, j) {
237
+ // logger.debug("BrillPOSTrainer.prototype.scanForPositiveRules: sentence no " + i);
238
+ const newRules = that.generatePositiveRules(i, j)
239
+ newRules.getRules().forEach(function (rule) {
240
+ that.positiveRules.addRule(rule)
241
+ // logger.debug("BrillPOSTrainer.prototype.scanForPositiveRules: nrRules " + that.positiveRules.nrRules());
242
+ })
241
243
  })
242
244
  })
243
- })
244
- // logger.debug("BrillPOSTrainer.prototype.scanForPositiveRules: exit, number of rules: " + this.positiveRules.nrRules());
245
- }
245
+ // logger.debug("BrillPOSTrainer.prototype.scanForPositiveRules: exit, number of rules: " + this.positiveRules.nrRules());
246
+ }
246
247
 
247
- // Find all sites where the rules can be applied, register these sites and
248
- // update the scores
249
- BrillPOSTrainer.prototype.scanForSites = function () {
250
- // logger.debug("BrillPOSTrainer.prototype.scanForSites: entry");
251
- const that = this
248
+ // Find all sites where the rules can be applied, register these sites and
249
+ // update the scores
250
+ scanForSites () {
251
+ // logger.debug("BrillPOSTrainer.prototype.scanForSites: entry");
252
+ const that = this
252
253
 
253
- // Scan the corpus
254
- this.corpus.sentences.forEach(function (sentence, i) {
255
- if (i % 100 === 0) {
256
- // logger.info("BrillPOSTrainer.prototype.scanForSites: sentence " + i);
257
- }
254
+ // Scan the corpus
255
+ this.corpus.sentences.forEach(function (sentence, i) {
256
+ if (i % 100 === 0) {
257
+ // logger.info("BrillPOSTrainer.prototype.scanForSites: sentence " + i);
258
+ }
258
259
 
259
- const taggedSentence = new Sentence()
260
- sentence.taggedWords.forEach(function (wordObject) {
261
- taggedSentence.addTaggedWord(wordObject.token, wordObject.testTag)
262
- })
260
+ const taggedSentence = new Sentence()
261
+ sentence.taggedWords.forEach(function (wordObject) {
262
+ taggedSentence.addTaggedWord(wordObject.token, wordObject.testTag)
263
+ })
263
264
 
264
- sentence.taggedWords.forEach(function (token, j) {
265
- that.positiveRules.getRules().forEach(function (rule) {
266
- if (rule.isApplicableAt(sentence, taggedSentence, j)) {
267
- that.associateSiteWithRule(i, j, rule)
268
- that.scoreRule(rule, i, j)
269
- // logger.debug("BrillPOSTrainer.prototype.scanForSites: (sentence, token, rule): (" + i + ", " + j + ", " + rule.prettyPrint() + ")");
270
- }
265
+ sentence.taggedWords.forEach(function (token, j) {
266
+ that.positiveRules.getRules().forEach(function (rule) {
267
+ if (rule.isApplicableAt(sentence, taggedSentence, j)) {
268
+ that.associateSiteWithRule(i, j, rule)
269
+ that.scoreRule(rule, i, j)
270
+ // logger.debug("BrillPOSTrainer.prototype.scanForSites: (sentence, token, rule): (" + i + ", " + j + ", " + rule.prettyPrint() + ")");
271
+ }
272
+ })
271
273
  })
272
274
  })
273
- })
274
275
 
275
- // logger.debug("BrillPOSTrainer.prototype.scanForSites: exit");
276
- }
277
-
278
- // Returns a list of sites that may have been touched by a changing tag
279
- BrillPOSTrainer.prototype.neighbourhood = function (i, j) {
280
- const sentenceLength = this.corpus.sentences[i].length
281
- const list = []
282
-
283
- if (this.index > 2) {
284
- list.push([i, j - 3])
285
- }
286
- if (this.index > 1) {
287
- list.push([i, j - 2])
276
+ // logger.debug("BrillPOSTrainer.prototype.scanForSites: exit");
288
277
  }
289
- if (this.index > 0) {
290
- list.push([i, j - 1])
291
- }
292
- if (this.index < sentenceLength - 1) {
293
- list.push([i, j + 1])
294
- }
295
- if (this.index < sentenceLength - 2) {
296
- list.push([i, j + 2])
297
- }
298
- if (this.index > sentenceLength - 3) {
299
- list.push([i, j + 3])
300
- }
301
- return list
302
- }
303
278
 
304
- // corpus: an array of token arrays
305
- // templates: an array of rule templates
306
- // lexicon: lexicon that provides method tagWord(word)
307
- BrillPOSTrainer.prototype.train = function (corpus, templates, lexicon) {
308
- this.corpus = corpus
309
- this.templates = templates
310
- this.positiveRules = new RuleSet()
311
- this.mapRuleToSites = {}
312
- this.mapSiteToRules = {}
313
-
314
- // logger.debug("BrillPOSTrainer.prototype.train: entry");
315
- this.corpus.tag(lexicon)
316
- this.scanForPositiveRules()
317
- // logger.info("BrillPOSTrainer.prototype.train: initial number of rules: " + this.positiveRules.nrRules());
318
- this.scanForSites()
319
-
320
- let highRule = this.selectHighRule()
321
- let iterationNumber = 0
322
- const that = this
323
- while ((highRule !== null) && (highRule.score() > minScore)) {
324
- if ((iterationNumber % 5) === 0) {
325
- // logger.info("BrillPOSTrainer.prototype.train: training iteration: " + iterationNumber);
279
+ // Returns a list of sites that may have been touched by a changing tag
280
+ neighbourhood (i, j) {
281
+ const sentenceLength = this.corpus.sentences[i].length
282
+ const list = []
283
+
284
+ if (this.index > 2) {
285
+ list.push([i, j - 3])
326
286
  }
327
- // logger.debug("BrillPOSTrainer.prototype.train: highRule selected: " + highRule.key());
328
- // logger.debug("BrillPOSTrainer.prototype.train: number of rules: " + this.positiveRules.nrRules());
329
- // logger.debug("BrillPOSTrainer.prototype.train: score of highRule: " + highRule.score());
330
-
331
- // Apply the high rule to each change site on its site list
332
- this.getSites(highRule).forEach(function (site) {
333
- // logger.debug("BrillPOSTrainer.prototype.train: apply highRule to: " + site);
334
- // logger.debug("BrillPOSTrainer.prototype.train: sentence length: " + that.corpus.sentences[site[0]].length);
335
- highRule.applyAt(that.corpus.sentences[site[0]], site[1])
336
- })
287
+ if (this.index > 1) {
288
+ list.push([i, j - 2])
289
+ }
290
+ if (this.index > 0) {
291
+ list.push([i, j - 1])
292
+ }
293
+ if (this.index < sentenceLength - 1) {
294
+ list.push([i, j + 1])
295
+ }
296
+ if (this.index < sentenceLength - 2) {
297
+ list.push([i, j + 2])
298
+ }
299
+ if (this.index > sentenceLength - 3) {
300
+ list.push([i, j + 3])
301
+ }
302
+ return list
303
+ }
337
304
 
338
- const unseenRules = new RuleSet()
339
- this.getSites(highRule).forEach(function (site) {
340
- that.neighbourhood(site[0], site[1]).forEach(function (testSite) {
341
- // Generate positive rules for testSite
342
- const newRules = that.generatePositiveRules(testSite[0], testSite[1])
343
-
344
- // Disconnect test site from its rules
345
- // because highrule has been applied
346
- that.getRules(testSite[0], testSite[1]).forEach(function (rule) {
347
- if (!newRules.hasRule(rule)) {
348
- that.disconnectSiteFromRule(testSite[0], testSite[1], rule)
349
- }
350
- })
305
+ // corpus: an array of token arrays
306
+ // templates: an array of rule templates
307
+ // lexicon: lexicon that provides method tagWord(word)
308
+ train (corpus, templates, lexicon) {
309
+ this.corpus = corpus
310
+ this.templates = templates
311
+ this.positiveRules = new RuleSet()
312
+ this.mapRuleToSites = {}
313
+ this.mapSiteToRules = {}
314
+
315
+ // logger.debug("BrillPOSTrainer.prototype.train: entry");
316
+ this.corpus.tag(lexicon)
317
+ this.scanForPositiveRules()
318
+ // logger.info("BrillPOSTrainer.prototype.train: initial number of rules: " + this.positiveRules.nrRules());
319
+ this.scanForSites()
320
+
321
+ let highRule = this.selectHighRule()
322
+ let iterationNumber = 0
323
+ const that = this
324
+ while ((highRule !== null) && (highRule.score() > minScore)) {
325
+ if ((iterationNumber % 5) === 0) {
326
+ // logger.info("BrillPOSTrainer.prototype.train: training iteration: " + iterationNumber);
327
+ }
328
+ // logger.debug("BrillPOSTrainer.prototype.train: highRule selected: " + highRule.key());
329
+ // logger.debug("BrillPOSTrainer.prototype.train: number of rules: " + this.positiveRules.nrRules());
330
+ // logger.debug("BrillPOSTrainer.prototype.train: score of highRule: " + highRule.score());
331
+
332
+ // Apply the high rule to each change site on its site list
333
+ this.getSites(highRule).forEach(function (site) {
334
+ // logger.debug("BrillPOSTrainer.prototype.train: apply highRule to: " + site);
335
+ // logger.debug("BrillPOSTrainer.prototype.train: sentence length: " + that.corpus.sentences[site[0]].length);
336
+ highRule.applyAt(that.corpus.sentences[site[0]], site[1])
337
+ })
351
338
 
352
- // Connect new rules not already connected to the test site
353
- newRules.getRules().forEach(function (rule) {
354
- if (!that.siteIsAssociatedWithRule(testSite[0].testSite[1], rule)) {
355
- if (that.positiveRules.hasRule(rule)) {
356
- that.associateSiteWithRule(testSite[0], testSite[1], rule)
357
- } else {
358
- unseenRules.addRule(rule)
339
+ const unseenRules = new RuleSet()
340
+ this.getSites(highRule).forEach(function (site) {
341
+ that.neighbourhood(site[0], site[1]).forEach(function (testSite) {
342
+ // Generate positive rules for testSite
343
+ const newRules = that.generatePositiveRules(testSite[0], testSite[1])
344
+
345
+ // Disconnect test site from its rules
346
+ // because highrule has been applied
347
+ that.getRules(testSite[0], testSite[1]).forEach(function (rule) {
348
+ if (!newRules.hasRule(rule)) {
349
+ that.disconnectSiteFromRule(testSite[0], testSite[1], rule)
359
350
  }
360
- }
361
- })
351
+ })
362
352
 
363
- // Process unseen rules
364
- if (unseenRules.nrRules() > 0) {
365
- unseenRules.getRules().forEach(function (rule) {
366
- that.positiveRules.addRule(rule)
353
+ // Connect new rules not already connected to the test site
354
+ newRules.getRules().forEach(function (rule) {
355
+ if (!that.siteIsAssociatedWithRule(testSite[0].testSite[1], rule)) {
356
+ if (that.positiveRules.hasRule(rule)) {
357
+ that.associateSiteWithRule(testSite[0], testSite[1], rule)
358
+ } else {
359
+ unseenRules.addRule(rule)
360
+ }
361
+ }
367
362
  })
368
- that.corpus.sentences.forEach(function (sentence, i) {
369
- const taggedSentence = sentence.map(function (token) {
370
- return [token.token, token.testTag]
363
+
364
+ // Process unseen rules
365
+ if (unseenRules.nrRules() > 0) {
366
+ unseenRules.getRules().forEach(function (rule) {
367
+ that.positiveRules.addRule(rule)
371
368
  })
372
- sentence.forEach(function (token, j) {
373
- unseenRules.getRules().forEach(function (rule) {
374
- if (rule.isApplicableAt(sentence, taggedSentence, j)) {
375
- that.associateSiteWithRule(i, j, rule)
376
- that.scoreRule(rule, i, j)
377
- }
369
+ that.corpus.sentences.forEach(function (sentence, i) {
370
+ const taggedSentence = sentence.map(function (token) {
371
+ return [token.token, token.testTag]
372
+ })
373
+ sentence.forEach(function (token, j) {
374
+ unseenRules.getRules().forEach(function (rule) {
375
+ if (rule.isApplicableAt(sentence, taggedSentence, j)) {
376
+ that.associateSiteWithRule(i, j, rule)
377
+ that.scoreRule(rule, i, j)
378
+ }
379
+ })
378
380
  })
379
381
  })
380
- })
381
- }
382
+ }
383
+ })
382
384
  })
383
- })
384
-
385
- // Select next highest scoring rule
386
- highRule = this.selectHighRule()
387
- iterationNumber++
388
- }
389
- // logger.info("BrillPOSTrainer.prototype.train: number of iterations: " + iterationNumber);
390
- // logger.info("BrillPOSTrainer.prototype.train: number of rules: " + this.positiveRules.nrRules());
391
385
 
392
- // Remove rules having a non-positive score
393
- this.positiveRules.getRules().forEach(function (rule) {
394
- if (rule.score() < that.ruleScoreThreshold) {
395
- that.positiveRules.removeRule(rule)
386
+ // Select next highest scoring rule
387
+ highRule = this.selectHighRule()
388
+ iterationNumber++
396
389
  }
397
- })
390
+ // logger.info("BrillPOSTrainer.prototype.train: number of iterations: " + iterationNumber);
391
+ // logger.info("BrillPOSTrainer.prototype.train: number of rules: " + this.positiveRules.nrRules());
398
392
 
399
- // logger.info("BrillPOSTrainer.prototype.train: number of rules after pruning: " + this.positiveRules.nrRules());
400
- // logger.debug("BrillPOSTrainer.prototype.train: exit");
401
- return this.positiveRules
402
- }
393
+ // Remove rules having a non-positive score
394
+ this.positiveRules.getRules().forEach(function (rule) {
395
+ if (rule.score() < that.ruleScoreThreshold) {
396
+ that.positiveRules.removeRule(rule)
397
+ }
398
+ })
399
+
400
+ // logger.info("BrillPOSTrainer.prototype.train: number of rules after pruning: " + this.positiveRules.nrRules());
401
+ // logger.debug("BrillPOSTrainer.prototype.train: exit");
402
+ return this.positiveRules
403
+ }
403
404
 
404
- BrillPOSTrainer.prototype.printRulesWithScores = function () {
405
- let result = ''
405
+ printRulesWithScores () {
406
+ let result = ''
406
407
 
407
- function compareRules (a, b) {
408
- if (a.score() > b.score()) {
409
- return -1
410
- } else {
411
- if (a.score() < b.score()) {
412
- return 1
408
+ function compareRules (a, b) {
409
+ if (a.score() > b.score()) {
410
+ return -1
413
411
  } else {
414
- return 0
412
+ if (a.score() < b.score()) {
413
+ return 1
414
+ } else {
415
+ return 0
416
+ }
415
417
  }
416
418
  }
417
- }
418
419
 
419
- const rules = this.positiveRules.getRules()
420
- const sortedRules = rules.sort(compareRules)
420
+ const rules = this.positiveRules.getRules()
421
+ const sortedRules = rules.sort(compareRules)
421
422
 
422
- sortedRules.forEach(function (rule) {
423
- // if (rule.score() > 0) {
424
- result += rule.score() + '\t' + rule.positive + '\t' + rule.negative + '\t' + rule.neutral + '\t' + rule.prettyPrint() + '\n'
425
- // }
426
- })
427
- return result
423
+ sortedRules.forEach(function (rule) {
424
+ // if (rule.score() > 0) {
425
+ result += rule.score() + '\t' + rule.positive + '\t' + rule.negative + '\t' + rule.neutral + '\t' + rule.prettyPrint() + '\n'
426
+ // }
427
+ })
428
+ return result
429
+ }
428
430
  }
429
431
 
430
432
  module.exports = BrillPOSTrainer