natural 6.10.2 → 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.
- package/.github/workflows/node.js.yml +1 -1
- package/.github/workflows/npm-publish.yml +4 -4
- package/lib/natural/brill_pos_tagger/lib/Brill_POS_Tagger.js +33 -31
- package/lib/natural/brill_pos_tagger/lib/Brill_POS_Tester.js +33 -35
- package/lib/natural/brill_pos_tagger/lib/Brill_POS_Trainer.js +326 -324
- package/lib/natural/brill_pos_tagger/lib/Corpus.js +140 -138
- package/lib/natural/brill_pos_tagger/lib/Lexicon.js +78 -76
- package/lib/natural/brill_pos_tagger/lib/Predicate.js +19 -17
- package/lib/natural/brill_pos_tagger/lib/RuleSet.js +58 -56
- package/lib/natural/brill_pos_tagger/lib/RuleTemplate.js +11 -9
- package/lib/natural/brill_pos_tagger/lib/Sentence.js +21 -20
- package/lib/natural/brill_pos_tagger/lib/TransformationRule.js +58 -58
- package/lib/natural/classifiers/bayes_classifier.js +24 -29
- package/lib/natural/classifiers/classifier.js +136 -121
- package/lib/natural/classifiers/logistic_regression_classifier.js +33 -37
- package/lib/natural/classifiers/maxent/Classifier.js +81 -79
- package/lib/natural/classifiers/maxent/Context.js +11 -9
- package/lib/natural/classifiers/maxent/Distribution.js +107 -105
- package/lib/natural/classifiers/maxent/Element.js +12 -10
- package/lib/natural/classifiers/maxent/Feature.js +56 -54
- package/lib/natural/classifiers/maxent/FeatureSet.js +40 -38
- package/lib/natural/classifiers/maxent/GISScaler.js +110 -109
- package/lib/natural/classifiers/maxent/POS/ME_Corpus.js +26 -31
- package/lib/natural/classifiers/maxent/POS/ME_Sentence.js +37 -42
- package/lib/natural/classifiers/maxent/POS/POS_Element.js +119 -124
- package/lib/natural/classifiers/maxent/Sample.js +96 -94
- package/lib/natural/classifiers/maxent/SimpleExample/SE_Element.js +14 -20
- package/lib/natural/inflectors/fr/count_inflector.js +1 -1
- package/lib/natural/inflectors/fr/noun_inflector.js +179 -196
- package/lib/natural/inflectors/ja/noun_inflector.js +67 -84
- package/lib/natural/inflectors/noun_inflector.js +124 -139
- package/lib/natural/inflectors/present_verb_inflector.js +34 -48
- package/lib/natural/inflectors/singular_plural_inflector.js +62 -61
- package/lib/natural/tfidf/tfidf.js +118 -114
- package/lib/natural/trie/trie.js +161 -159
- package/lib/natural/util/directed_edge.js +49 -0
- package/lib/natural/util/edge_weighted_digraph.js +54 -74
- package/lib/natural/util/index.js +1 -0
- package/lib/natural/util/longest_path_tree.js +54 -52
- package/lib/natural/util/shortest_path_tree.js +56 -54
- package/lib/natural/util/topological.js +17 -15
- package/package.json +1 -1
|
@@ -16,16 +16,18 @@
|
|
|
16
16
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
class RuleTemplate {
|
|
20
|
+
constructor (templateName, metadata) {
|
|
21
|
+
this.predicateName = templateName
|
|
22
|
+
this.meta = metadata
|
|
23
|
+
}
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
windowFitsSite (sentence, i) {
|
|
26
|
+
return ((i + this.meta.window[0] >= 0) &&
|
|
27
|
+
(i + this.meta.window[0] < sentence.taggedWords.length) &&
|
|
28
|
+
(i + this.meta.window[1] >= 0) &&
|
|
29
|
+
(i + this.meta.window[1] < sentence.taggedWords.length))
|
|
30
|
+
}
|
|
29
31
|
}
|
|
30
32
|
|
|
31
33
|
module.exports = RuleTemplate
|
|
@@ -16,28 +16,29 @@
|
|
|
16
16
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
'
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
19
|
+
'use strict'
|
|
20
|
+
|
|
21
|
+
class Sentence {
|
|
22
|
+
constructor (data) {
|
|
23
|
+
this.taggedWords = []
|
|
24
|
+
if (data) {
|
|
25
|
+
this.taggedWords = data
|
|
26
|
+
}
|
|
25
27
|
}
|
|
26
|
-
}
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
29
|
+
addTaggedWord (token, tag) {
|
|
30
|
+
this.taggedWords.push({
|
|
31
|
+
token: token,
|
|
32
|
+
tag: tag
|
|
33
|
+
})
|
|
34
|
+
}
|
|
34
35
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
36
|
+
clone () {
|
|
37
|
+
const s = new Sentence()
|
|
38
|
+
this.taggedWords.forEach(function (wordObject) {
|
|
39
|
+
s.addTaggedWord(wordObject.token, wordObject.tag)
|
|
40
|
+
})
|
|
41
|
+
return s
|
|
42
|
+
}
|
|
41
43
|
}
|
|
42
|
-
|
|
43
44
|
module.exports = Sentence
|
|
@@ -20,80 +20,80 @@
|
|
|
20
20
|
|
|
21
21
|
const Predicate = require('./Predicate')
|
|
22
22
|
|
|
23
|
-
// logger.setLevel('INFO');
|
|
24
|
-
|
|
25
23
|
const categoryWildCard = '*'
|
|
26
24
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
25
|
+
class TransformationRule {
|
|
26
|
+
constructor (c1, c2, predicate, parameter1, parameter2) {
|
|
27
|
+
this.literal = [c1, c2, predicate, parameter1, parameter2]
|
|
28
|
+
this.predicate = new Predicate(predicate, parameter1, parameter2)
|
|
29
|
+
this.oldCategory = c1
|
|
30
|
+
this.newCategory = c2
|
|
31
|
+
// These members are for the learning algorithm
|
|
32
|
+
this.neutral = 0
|
|
33
|
+
this.negative = 0
|
|
34
|
+
this.positive = 0
|
|
35
|
+
this.hasBeenSelectedAsHighRuleBefore = false
|
|
36
|
+
}
|
|
38
37
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
38
|
+
key () {
|
|
39
|
+
return (this.literal.toString())
|
|
40
|
+
}
|
|
42
41
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
42
|
+
apply (sentence, position) {
|
|
43
|
+
if ((sentence.taggedWords[position].tag === this.oldCategory) ||
|
|
44
|
+
(this.oldCategory === categoryWildCard)) {
|
|
45
|
+
if (this.predicate.evaluate(sentence, position)) {
|
|
46
|
+
sentence.taggedWords[position].tag = this.newCategory
|
|
47
|
+
}
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
|
-
}
|
|
51
50
|
|
|
52
|
-
//
|
|
53
|
-
// Methods for processing sentences from a corpus that consist of an array of tokens
|
|
54
|
-
//
|
|
51
|
+
//
|
|
52
|
+
// Methods for processing sentences from a corpus that consist of an array of tokens
|
|
53
|
+
//
|
|
55
54
|
|
|
56
|
-
// Returns true if the rule applies at site. As a side effect it assigns the new
|
|
57
|
-
// category to newTag
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
55
|
+
// Returns true if the rule applies at site. As a side effect it assigns the new
|
|
56
|
+
// category to newTag
|
|
57
|
+
isApplicableAt (sentence, taggedSentence, i) {
|
|
58
|
+
const applies = (taggedSentence.taggedWords[i].tag === this.oldCategory) &&
|
|
59
|
+
this.predicate.evaluate(taggedSentence, i)
|
|
61
60
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
61
|
+
// Set newTag to let the trainer know what the new tag would become
|
|
62
|
+
if (applies) {
|
|
63
|
+
sentence.taggedWords[i].newTag = this.newCategory
|
|
64
|
+
}
|
|
65
|
+
return (applies)
|
|
65
66
|
}
|
|
66
|
-
return (applies)
|
|
67
|
-
}
|
|
68
67
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
68
|
+
prettyPrint () {
|
|
69
|
+
let result = ''
|
|
70
|
+
// Old category and new category
|
|
71
|
+
result += this.oldCategory + ' ' + this.newCategory
|
|
72
|
+
// Predicate name
|
|
73
|
+
result += ' ' + this.predicate.name
|
|
74
|
+
// Parameter 1 and 2
|
|
75
|
+
if (this.predicate.parameter1) {
|
|
76
|
+
result += ' ' + this.predicate.parameter1
|
|
77
|
+
if (this.predicate.parameter2) {
|
|
78
|
+
result += ' ' + this.predicate.parameter2
|
|
79
|
+
}
|
|
80
80
|
}
|
|
81
|
+
return result
|
|
81
82
|
}
|
|
82
|
-
return result
|
|
83
|
-
}
|
|
84
83
|
|
|
85
|
-
// Applies the rule the given location (if it applies)
|
|
86
|
-
|
|
87
|
-
|
|
84
|
+
// Applies the rule the given location (if it applies)
|
|
85
|
+
applyAt (sentence, i) {
|
|
86
|
+
const taggedSentence = sentence.clone()
|
|
88
87
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
}
|
|
88
|
+
this.apply(sentence, i)
|
|
89
|
+
// Assign the new tag to the corpus site
|
|
90
|
+
sentence.taggedWords[i].testTag = taggedSentence.taggedWords[i].tag
|
|
91
|
+
}
|
|
93
92
|
|
|
94
|
-
// Calculate the net score of this rule
|
|
95
|
-
|
|
96
|
-
|
|
93
|
+
// Calculate the net score of this rule
|
|
94
|
+
score () {
|
|
95
|
+
return (this.positive - this.negative)
|
|
96
|
+
}
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
module.exports = TransformationRule
|
|
@@ -22,41 +22,36 @@ THE SOFTWARE.
|
|
|
22
22
|
|
|
23
23
|
'use strict'
|
|
24
24
|
|
|
25
|
-
const util = require('util')
|
|
26
25
|
const Classifier = require('./classifier')
|
|
27
26
|
const ApparatusBayesClassifier = require('apparatus').BayesClassifier
|
|
28
27
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
class BayesClassifier extends Classifier {
|
|
29
|
+
constructor (stemmer, smoothing) {
|
|
30
|
+
let abc = new ApparatusBayesClassifier()
|
|
31
|
+
if (smoothing && isFinite(smoothing)) {
|
|
32
|
+
abc = new ApparatusBayesClassifier(smoothing)
|
|
33
|
+
}
|
|
34
|
+
super(abc, stemmer)
|
|
33
35
|
}
|
|
34
|
-
Classifier.call(this, abc, stemmer)
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
util.inherits(BayesClassifier, Classifier)
|
|
38
36
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
37
|
+
static restore (classifier, stemmer) {
|
|
38
|
+
classifier = Classifier.restore(classifier, stemmer)
|
|
39
|
+
// __proto__ is deprecated
|
|
40
|
+
// classifier.__proto__ = BayesClassifier.prototype
|
|
41
|
+
Object.setPrototypeOf(classifier, BayesClassifier.prototype)
|
|
42
|
+
classifier.classifier = ApparatusBayesClassifier.restore(classifier.classifier)
|
|
43
|
+
return classifier
|
|
44
|
+
}
|
|
48
45
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
46
|
+
load (filename, stemmer, callback) {
|
|
47
|
+
Classifier.load(filename, function (err, classifier) {
|
|
48
|
+
if (err) {
|
|
49
|
+
return callback(err)
|
|
50
|
+
} else {
|
|
51
|
+
callback(err, this.restore(classifier, stemmer))
|
|
52
|
+
}
|
|
53
|
+
})
|
|
54
|
+
}
|
|
57
55
|
}
|
|
58
56
|
|
|
59
|
-
BayesClassifier.restore = restore
|
|
60
|
-
BayesClassifier.load = load
|
|
61
|
-
|
|
62
57
|
module.exports = BayesClassifier
|
|
@@ -22,164 +22,179 @@ THE SOFTWARE.
|
|
|
22
22
|
|
|
23
23
|
'use strict'
|
|
24
24
|
|
|
25
|
-
const
|
|
26
|
-
const events = require('events')
|
|
25
|
+
const EventEmitter = require('events')
|
|
27
26
|
|
|
27
|
+
const PorterStemmer = require('../stemmers/porter_stemmer')
|
|
28
28
|
const parallelTrainer = require('./classifier_train_parallel')
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
30
|
+
class Classifier extends EventEmitter {
|
|
31
|
+
constructor (classifier, stemmer) {
|
|
32
|
+
super()
|
|
33
|
+
this.classifier = classifier
|
|
34
|
+
this.docs = []
|
|
35
|
+
this.features = {}
|
|
36
|
+
this.stemmer = stemmer || PorterStemmer
|
|
37
|
+
this.lastAdded = 0
|
|
38
|
+
}
|
|
38
39
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
addDocument (text, classification) {
|
|
41
|
+
// Ignore further processing if classification is undefined
|
|
42
|
+
if (typeof classification === 'undefined') return
|
|
42
43
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
// If classification is type of string then make sure it's dosen't have blank space at both end
|
|
45
|
+
if (typeof classification === 'string') {
|
|
46
|
+
classification = classification.trim()
|
|
47
|
+
}
|
|
47
48
|
|
|
48
|
-
|
|
49
|
+
if (typeof text === 'string') { text = this.stemmer.tokenizeAndStem(text, this.keepStops) }
|
|
49
50
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
51
|
+
if (text.length === 0) {
|
|
52
|
+
// ignore empty documents
|
|
53
|
+
return
|
|
54
|
+
}
|
|
54
55
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
this.docs.push({
|
|
57
|
+
label: classification,
|
|
58
|
+
text: text
|
|
59
|
+
})
|
|
59
60
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
61
|
+
for (let i = 0; i < text.length; i++) {
|
|
62
|
+
const token = text[i]
|
|
63
|
+
this.features[token] = (this.features[token] || 0) + 1
|
|
64
|
+
}
|
|
63
65
|
}
|
|
64
|
-
}
|
|
65
66
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
67
|
+
removeDocument (text, classification) {
|
|
68
|
+
const docs = this.docs
|
|
69
|
+
let doc
|
|
70
|
+
let pos
|
|
70
71
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
if (typeof text === 'string') {
|
|
73
|
+
text = this.stemmer.tokenizeAndStem(text, this.keepStops)
|
|
74
|
+
}
|
|
74
75
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
76
|
+
for (let i = 0, ii = docs.length; i < ii; i++) {
|
|
77
|
+
doc = docs[i]
|
|
78
|
+
if (doc.text.join(' ') === text.join(' ') &&
|
|
79
|
+
doc.label === classification) {
|
|
80
|
+
pos = i
|
|
81
|
+
}
|
|
80
82
|
}
|
|
81
|
-
}
|
|
82
83
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
84
|
+
// Remove if there's a match
|
|
85
|
+
if (!isNaN(pos)) {
|
|
86
|
+
this.docs.splice(pos, 1)
|
|
86
87
|
|
|
87
|
-
|
|
88
|
-
|
|
88
|
+
for (let i = 0, ii = text.length; i < ii; i++) {
|
|
89
|
+
delete this.features[text[i]]
|
|
90
|
+
}
|
|
89
91
|
}
|
|
90
92
|
}
|
|
91
|
-
}
|
|
92
93
|
|
|
93
|
-
|
|
94
|
-
|
|
94
|
+
textToFeatures (observation) {
|
|
95
|
+
const features = []
|
|
95
96
|
|
|
96
|
-
|
|
97
|
+
if (typeof observation === 'string') { observation = this.stemmer.tokenizeAndStem(observation, this.keepStops) }
|
|
98
|
+
|
|
99
|
+
for (const feature in this.features) {
|
|
100
|
+
if (observation.indexOf(feature) > -1) {
|
|
101
|
+
features.push(1)
|
|
102
|
+
} else {
|
|
103
|
+
features.push(0)
|
|
104
|
+
}
|
|
105
|
+
}
|
|
97
106
|
|
|
98
|
-
|
|
99
|
-
if (observation.indexOf(feature) > -1) { features.push(1) } else { features.push(0) }
|
|
107
|
+
return features
|
|
100
108
|
}
|
|
101
109
|
|
|
102
|
-
|
|
103
|
-
|
|
110
|
+
train () {
|
|
111
|
+
const totalDocs = this.docs.length
|
|
112
|
+
for (let i = this.lastAdded; i < totalDocs; i++) {
|
|
113
|
+
const features = this.textToFeatures(this.docs[i].text)
|
|
114
|
+
this.classifier.addExample(features, this.docs[i].label)
|
|
115
|
+
this.emit('trainedWithDocument', { index: i, total: totalDocs, doc: this.docs[i] })
|
|
116
|
+
this.lastAdded++
|
|
117
|
+
}
|
|
118
|
+
this.emit('doneTraining', true)
|
|
119
|
+
this.classifier.train()
|
|
120
|
+
}
|
|
104
121
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
this.classifier.addExample(features, this.docs[i].label)
|
|
110
|
-
this.events.emit('trainedWithDocument', { index: i, total: totalDocs, doc: this.docs[i] })
|
|
111
|
-
this.lastAdded++
|
|
122
|
+
retrain () {
|
|
123
|
+
this.classifier = new (this.classifier.constructor)()
|
|
124
|
+
this.lastAdded = 0
|
|
125
|
+
this.train()
|
|
112
126
|
}
|
|
113
|
-
this.events.emit('doneTraining', true)
|
|
114
|
-
this.classifier.train()
|
|
115
|
-
}
|
|
116
127
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
this.train()
|
|
121
|
-
}
|
|
128
|
+
getClassifications (observation) {
|
|
129
|
+
return this.classifier.getClassifications(this.textToFeatures(observation))
|
|
130
|
+
}
|
|
122
131
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
}
|
|
132
|
+
classify (observation) {
|
|
133
|
+
return this.classifier.classify(this.textToFeatures(observation))
|
|
134
|
+
}
|
|
126
135
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
136
|
+
static restore (classifier, stemmer) {
|
|
137
|
+
classifier.stemmer = stemmer || PorterStemmer
|
|
138
|
+
return classifier
|
|
139
|
+
}
|
|
130
140
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
141
|
+
save (filename, callback) {
|
|
142
|
+
const data = JSON.stringify(this)
|
|
143
|
+
const fs = require('fs')
|
|
144
|
+
const classifier = this
|
|
145
|
+
fs.writeFile(filename, data, 'utf8', function (err) {
|
|
146
|
+
if (callback) {
|
|
147
|
+
callback(err, err ? null : classifier)
|
|
148
|
+
}
|
|
149
|
+
})
|
|
150
|
+
}
|
|
136
151
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
const fs = require('fs')
|
|
140
|
-
const classifier = this
|
|
141
|
-
fs.writeFile(filename, data, 'utf8', function (err) {
|
|
142
|
-
if (callback) {
|
|
143
|
-
callback(err, err ? null : classifier)
|
|
144
|
-
}
|
|
145
|
-
})
|
|
146
|
-
}
|
|
152
|
+
static load (filename, callback) {
|
|
153
|
+
const fs = require('fs')
|
|
147
154
|
|
|
148
|
-
|
|
149
|
-
|
|
155
|
+
if (!callback) {
|
|
156
|
+
return
|
|
157
|
+
}
|
|
158
|
+
fs.readFile(filename, 'utf8', function (err, data) {
|
|
159
|
+
if (err) {
|
|
160
|
+
callback(err, null)
|
|
161
|
+
} else {
|
|
162
|
+
const classifier = JSON.parse(data)
|
|
163
|
+
callback(err, classifier)
|
|
164
|
+
}
|
|
165
|
+
})
|
|
166
|
+
}
|
|
150
167
|
|
|
151
|
-
|
|
152
|
-
|
|
168
|
+
setOptions (options) {
|
|
169
|
+
this.keepStops = !!(options.keepStops)
|
|
153
170
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
171
|
+
|
|
172
|
+
ClassifiertrainParallel (numThreads, callback) {
|
|
173
|
+
if (parallelTrainer.Threads) {
|
|
174
|
+
return parallelTrainer.trainParallel(numThreads, callback)
|
|
157
175
|
} else {
|
|
158
|
-
|
|
159
|
-
|
|
176
|
+
this.emit('No threads available')
|
|
177
|
+
return this.train()
|
|
160
178
|
}
|
|
161
|
-
}
|
|
162
|
-
}
|
|
179
|
+
}
|
|
163
180
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
181
|
+
trainParallelBatches (options) {
|
|
182
|
+
if (parallelTrainer.Threads) {
|
|
183
|
+
return parallelTrainer.trainParallelBatches(options)
|
|
184
|
+
} else {
|
|
185
|
+
this.emit('No threads available')
|
|
186
|
+
return this.train()
|
|
187
|
+
}
|
|
188
|
+
}
|
|
167
189
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
190
|
+
retrainParallel (numThreads, callback) {
|
|
191
|
+
if (parallelTrainer.Threads) {
|
|
192
|
+
return parallelTrainer.trainParallel(numThreads, callback)
|
|
193
|
+
} else {
|
|
194
|
+
this.emit('No threads available')
|
|
195
|
+
return this.retrain()
|
|
196
|
+
}
|
|
197
|
+
}
|
|
175
198
|
}
|
|
176
|
-
Classifier.prototype.retrain = retrain
|
|
177
|
-
Classifier.prototype.classify = classify
|
|
178
|
-
Classifier.prototype.textToFeatures = textToFeatures
|
|
179
|
-
Classifier.prototype.save = save
|
|
180
|
-
Classifier.prototype.getClassifications = getClassifications
|
|
181
|
-
Classifier.prototype.setOptions = setOptions
|
|
182
|
-
Classifier.restore = restore
|
|
183
|
-
Classifier.load = load
|
|
184
199
|
|
|
185
200
|
module.exports = Classifier
|
|
@@ -22,46 +22,42 @@ THE SOFTWARE.
|
|
|
22
22
|
|
|
23
23
|
'use strict'
|
|
24
24
|
|
|
25
|
-
const util = require('util')
|
|
26
25
|
const Classifier = require('./classifier')
|
|
27
26
|
const ApparatusLogisticRegressionClassifier = require('apparatus').LogisticRegressionClassifier
|
|
28
27
|
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
class LogisticRegressionClassifier extends Classifier {
|
|
29
|
+
constructor (stemmer) {
|
|
30
|
+
const abc = new ApparatusLogisticRegressionClassifier()
|
|
31
|
+
super(abc, stemmer)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
static restore (classifier, stemmer) {
|
|
35
|
+
classifier = Classifier.restore(classifier, stemmer)
|
|
36
|
+
// Using ___proto__ is deprecated
|
|
37
|
+
// classifier.__proto__ = LogisticRegressionClassifier.prototype
|
|
38
|
+
Object.setPrototypeOf(classifier, LogisticRegressionClassifier.prototype)
|
|
39
|
+
classifier.classifier = ApparatusLogisticRegressionClassifier.restore(classifier.classifier)
|
|
40
|
+
|
|
41
|
+
return classifier
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
static load (filename, stemmer, callback) {
|
|
45
|
+
Classifier.load(filename, function (err, classifier) {
|
|
46
|
+
if (err) {
|
|
47
|
+
callback(err)
|
|
48
|
+
} else {
|
|
49
|
+
callback(err, this.restore(classifier, stemmer))
|
|
50
|
+
}
|
|
51
|
+
})
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
train () {
|
|
55
|
+
// we need to reset the training state because logistic regression
|
|
56
|
+
// needs its matricies to have their widths synced, etc.
|
|
57
|
+
this.lastAdded = 0
|
|
58
|
+
this.classifier = new ApparatusLogisticRegressionClassifier()
|
|
59
|
+
Classifier.prototype.train.call(this)
|
|
60
|
+
}
|
|
31
61
|
}
|
|
32
62
|
|
|
33
|
-
util.inherits(LogisticRegressionClassifier, Classifier)
|
|
34
|
-
|
|
35
|
-
function restore (classifier, stemmer) {
|
|
36
|
-
classifier = Classifier.restore(classifier, stemmer)
|
|
37
|
-
// Using ___proto__ is deprecated
|
|
38
|
-
// classifier.__proto__ = LogisticRegressionClassifier.prototype
|
|
39
|
-
Object.setPrototypeOf(classifier, LogisticRegressionClassifier.prototype)
|
|
40
|
-
classifier.classifier = ApparatusLogisticRegressionClassifier.restore(classifier.classifier)
|
|
41
|
-
|
|
42
|
-
return classifier
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function load (filename, stemmer, callback) {
|
|
46
|
-
Classifier.load(filename, function (err, classifier) {
|
|
47
|
-
if (err) {
|
|
48
|
-
callback(err)
|
|
49
|
-
} else {
|
|
50
|
-
callback(err, restore(classifier, stemmer))
|
|
51
|
-
}
|
|
52
|
-
})
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function train () {
|
|
56
|
-
// we need to reset the traning state because logistic regression
|
|
57
|
-
// needs its matricies to have their widths synced, etc.
|
|
58
|
-
this.lastAdded = 0
|
|
59
|
-
this.classifier = new ApparatusLogisticRegressionClassifier()
|
|
60
|
-
Classifier.prototype.train.call(this)
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
LogisticRegressionClassifier.prototype.train = train
|
|
64
|
-
LogisticRegressionClassifier.restore = restore
|
|
65
|
-
LogisticRegressionClassifier.load = load
|
|
66
|
-
|
|
67
63
|
module.exports = LogisticRegressionClassifier
|