natural 7.0.2 → 7.0.5

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 (72) hide show
  1. package/.github/workflows/npm-publish.yml +2 -0
  2. package/.nycrc +9 -0
  3. package/lib/natural/analyzers/sentence_analyzer.js +115 -113
  4. package/lib/natural/spellcheck/spellcheck.js +63 -61
  5. package/lib/natural/util/bag.js +27 -25
  6. package/package.json +3 -4
  7. package/tsconfig.json +1 -1
  8. package/ts_spec/MaxEntClassifier_spec.ts +0 -130
  9. package/ts_spec/SentimentAnalyzer_spec.ts +0 -232
  10. package/ts_spec/WordPunctTokenizer_spec.ts +0 -57
  11. package/ts_spec/aggressive_tokenizer_de_spec.ts +0 -36
  12. package/ts_spec/aggressive_tokenizer_es_spec.ts +0 -39
  13. package/ts_spec/aggressive_tokenizer_fr_spec.ts +0 -111
  14. package/ts_spec/aggressive_tokenizer_hi_spec.ts +0 -70
  15. package/ts_spec/aggressive_tokenizer_nl_spec.ts +0 -39
  16. package/ts_spec/aggressive_tokenizer_pt_spec.ts +0 -48
  17. package/ts_spec/aggressive_tokenizer_spec.ts +0 -57
  18. package/ts_spec/aggressive_tokenizer_sv_spec.ts +0 -52
  19. package/ts_spec/aggressive_tokenizer_vi_spec.ts +0 -48
  20. package/ts_spec/bayes_classifier_spec.ts +0 -165
  21. package/ts_spec/brill_pos_tagger_spec.ts +0 -79
  22. package/ts_spec/brill_pos_trainer_spec.ts +0 -107
  23. package/ts_spec/carry_stemmer_fr_spec.ts +0 -97
  24. package/ts_spec/classifier_spec.ts +0 -104
  25. package/ts_spec/count_inflector_fr_spec.ts +0 -47
  26. package/ts_spec/count_inflector_spec.ts +0 -76
  27. package/ts_spec/damerau_levenshtein_spec.ts +0 -53
  28. package/ts_spec/dice_coefficient_spec.ts +0 -37
  29. package/ts_spec/double_metaphone_spec.ts +0 -739
  30. package/ts_spec/hamming_distance_spec.ts +0 -66
  31. package/ts_spec/jaro-winkler_spec.ts +0 -79
  32. package/ts_spec/lancaster_stemmer_spec.ts +0 -63
  33. package/ts_spec/levenshtein_spec.ts +0 -107
  34. package/ts_spec/logistic_regression_classifier_spec.ts +0 -93
  35. package/ts_spec/longest_path_tree_spec.ts +0 -111
  36. package/ts_spec/metaphone_spec.ts +0 -258
  37. package/ts_spec/ngram_spec.ts +0 -145
  38. package/ts_spec/ngram_zh_spec.ts +0 -124
  39. package/ts_spec/normalizer_ja_spec.ts +0 -165
  40. package/ts_spec/normalizer_no_spec.ts +0 -112
  41. package/ts_spec/normalizer_spec.ts +0 -141
  42. package/ts_spec/noun_inflector_fr_spec.ts +0 -472
  43. package/ts_spec/noun_inflector_ja_spec.ts +0 -116
  44. package/ts_spec/noun_inflector_spec.ts +0 -369
  45. package/ts_spec/orthography_tokenizer_spec.ts +0 -47
  46. package/ts_spec/porter_stemmer_de_spec.ts +0 -53
  47. package/ts_spec/porter_stemmer_es_spec.ts +0 -63
  48. package/ts_spec/porter_stemmer_fr_spec.ts +0 -103
  49. package/ts_spec/porter_stemmer_it_spec.ts +0 -56
  50. package/ts_spec/porter_stemmer_nl_spec.ts +0 -73
  51. package/ts_spec/porter_stemmer_no_spec.ts +0 -148
  52. package/ts_spec/porter_stemmer_pt_spec.ts +0 -50
  53. package/ts_spec/porter_stemmer_ru_spec.ts +0 -67
  54. package/ts_spec/porter_stemmer_spec.ts +0 -202
  55. package/ts_spec/porter_stemmer_sv_spec.ts +0 -41
  56. package/ts_spec/present_verb_inflector_spec.ts +0 -127
  57. package/ts_spec/remove_diacritics_spec.ts +0 -30
  58. package/ts_spec/sentence_analyzer_spec.ts +0 -293
  59. package/ts_spec/sentence_tokenizer_parser_spec.ts +0 -200
  60. package/ts_spec/sentence_tokenizer_spec.ts +0 -189
  61. package/ts_spec/shortest_path_tree_spec.ts +0 -141
  62. package/ts_spec/soundex_spec.ts +0 -162
  63. package/ts_spec/spellcheck_spec.ts +0 -112
  64. package/ts_spec/stemmer_id_spec.ts +0 -374
  65. package/ts_spec/stemmer_ja_spec.ts +0 -69
  66. package/ts_spec/stemmer_token_spec.ts +0 -163
  67. package/ts_spec/tfidf_spec.ts +0 -275
  68. package/ts_spec/tokenizer_case_spec.ts +0 -242
  69. package/ts_spec/tokenizer_ja_spec.ts +0 -63
  70. package/ts_spec/transliterator_ja_spec.ts +0 -105
  71. package/ts_spec/treebank_word_tokenizer_spec.ts +0 -38
  72. package/ts_spec/trie_spec.ts +0 -197
@@ -16,6 +16,8 @@ jobs:
16
16
  with:
17
17
  node-version: 20
18
18
  - run: npm ci
19
+ - name: Build
20
+ run: npm run build
19
21
  - run: npm test
20
22
 
21
23
  publish-npm:
package/.nycrc ADDED
@@ -0,0 +1,9 @@
1
+ {
2
+ "include": [
3
+ "io_spec/**/*_spec.js",
4
+ "dist/**/*_spec.js",
5
+ "lib/natural/**/*.js",
6
+ "lib/natural/**/*.ts"
7
+ ],
8
+ "reporter": "lcov"
9
+ }
@@ -25,7 +25,7 @@ THE SOFTWARE.
25
25
  const _ = require('underscore')
26
26
 
27
27
  /*
28
- Sentences Analizer Class
28
+ Sentences Analyzer Class
29
29
  From http://www.writingcentre.uottawa.ca/hypergrammar/sntpurps.html
30
30
 
31
31
  Take a POS input and analyse it for
@@ -44,148 +44,150 @@ const _ = require('underscore')
44
44
  - Show Preposition Phrases
45
45
  */
46
46
 
47
- const Sentences = function (pos, callbackFunction) {
48
- this.posObj = pos
49
- this.senType = null
50
- callbackFunction(this)
51
- }
47
+ class SentenceAnalyzer {
48
+ constructor (pos, callbackFunction) {
49
+ this.posObj = pos
50
+ this.senType = null
51
+ callbackFunction(this)
52
+ }
52
53
 
53
- Sentences.prototype.part = function (callbackFunction) {
54
- const subject = []
55
- const predicat = []
56
- let verbFound = false
54
+ part (callbackFunction) {
55
+ const subject = []
56
+ const predicat = []
57
+ let verbFound = false
57
58
 
58
- this.prepositionPhrases()
59
+ this.prepositionPhrases()
59
60
 
60
- for (let i = 0; i < this.posObj.tags.length; i++) {
61
- if (this.posObj.tags[i].pos === 'VB') {
62
- if (i === 0) {
63
- verbFound = true
64
- } else {
65
- // We need to Test for any EX before the VB
66
- if (this.posObj.tags[i - 1].pos !== 'EX') {
61
+ for (let i = 0; i < this.posObj.tags.length; i++) {
62
+ if (this.posObj.tags[i].pos === 'VB') {
63
+ if (i === 0) {
67
64
  verbFound = true
68
65
  } else {
69
- predicat.push(this.posObj.tags[i].token)
66
+ // We need to Test for any EX before the VB
67
+ if (this.posObj.tags[i - 1].pos !== 'EX') {
68
+ verbFound = true
69
+ } else {
70
+ predicat.push(this.posObj.tags[i].token)
71
+ }
70
72
  }
71
73
  }
72
- }
73
74
 
74
- // Add Pronoun Phrase (pp) Or Subject Phrase (sp)
75
- if (!verbFound) {
76
- if (this.posObj.tags[i].pp !== true) { this.posObj.tags[i].spos = 'SP' }
75
+ // Add Pronoun Phrase (pp) Or Subject Phrase (sp)
76
+ if (!verbFound) {
77
+ if (this.posObj.tags[i].pp !== true) { this.posObj.tags[i].spos = 'SP' }
77
78
 
78
- subject.push(this.posObj.tags[i].token)
79
- } else {
80
- if (this.posObj.tags[i].pp !== true) { this.posObj.tags[i].spos = 'PP' }
79
+ subject.push(this.posObj.tags[i].token)
80
+ } else {
81
+ if (this.posObj.tags[i].pp !== true) { this.posObj.tags[i].spos = 'PP' }
81
82
 
82
- predicat.push(this.posObj.tags[i].token)
83
+ predicat.push(this.posObj.tags[i].token)
84
+ }
83
85
  }
84
- }
85
86
 
86
- if (subject.length === 0) {
87
- this.posObj.tags.push({ token: 'You', spos: 'SP', pos: 'PRP', added: true })
88
- }
87
+ if (subject.length === 0) {
88
+ this.posObj.tags.push({ token: 'You', spos: 'SP', pos: 'PRP', added: true })
89
+ }
89
90
 
90
- callbackFunction(this)
91
- }
91
+ callbackFunction(this)
92
+ }
92
93
 
93
- // Takes POS and removes IN to NN or NNS
94
- // Adds a PP for each prepositionPhrases
95
- Sentences.prototype.prepositionPhrases = function () {
96
- let remove = false
94
+ // Takes POS and removes IN to NN or NNS
95
+ // Adds a PP for each prepositionPhrases
96
+ prepositionPhrases () {
97
+ let remove = false
97
98
 
98
- for (let i = 0; i < this.posObj.tags.length; i++) {
99
- if (this.posObj.tags[i].pos.match('IN')) {
100
- remove = true
101
- }
99
+ for (let i = 0; i < this.posObj.tags.length; i++) {
100
+ if (this.posObj.tags[i].pos.match('IN')) {
101
+ remove = true
102
+ }
102
103
 
103
- if (remove) {
104
- this.posObj.tags[i].pp = true
105
- }
104
+ if (remove) {
105
+ this.posObj.tags[i].pp = true
106
+ }
106
107
 
107
- if (this.posObj.tags[i].pos.match('NN')) {
108
- remove = false
108
+ if (this.posObj.tags[i].pos.match('NN')) {
109
+ remove = false
110
+ }
109
111
  }
110
112
  }
111
- }
112
113
 
113
- Sentences.prototype.subjectToString = function () {
114
- return this.posObj.tags.map(function (t) {
115
- if (t.spos === 'SP' || t.spos === 'S') {
116
- return t.token
117
- } else return null
118
- }).join(' ')
119
- }
114
+ subjectToString () {
115
+ return this.posObj.tags.map(function (t) {
116
+ if (t.spos === 'SP' || t.spos === 'S') {
117
+ return t.token
118
+ } else return null
119
+ }).join(' ')
120
+ }
120
121
 
121
- Sentences.prototype.predicateToString = function () {
122
- return this.posObj.tags.map(function (t) {
123
- if (t.spos === 'PP' || t.spos === 'P') {
124
- return t.token
125
- } else return null
126
- }).join(' ')
127
- }
122
+ predicateToString () {
123
+ return this.posObj.tags.map(function (t) {
124
+ if (t.spos === 'PP' || t.spos === 'P') {
125
+ return t.token
126
+ } else return null
127
+ }).join(' ')
128
+ }
128
129
 
129
- Sentences.prototype.implicitYou = function () {
130
- for (let i = 0; i < this.posObj.tags.length; i++) {
131
- if (this.posObj.tags[i].added) {
132
- return true
130
+ implicitYou () {
131
+ for (let i = 0; i < this.posObj.tags.length; i++) {
132
+ if (this.posObj.tags[i].added) {
133
+ return true
134
+ }
133
135
  }
136
+
137
+ return false
134
138
  }
135
139
 
136
- return false
137
- }
140
+ toString () {
141
+ return this.posObj.tags.map(function (t) { return t.token }).join(' ')
142
+ }
138
143
 
139
- Sentences.prototype.toString = function () {
140
- return this.posObj.tags.map(function (t) { return t.token }).join(' ')
141
- }
144
+ // This is quick and incomplete.
145
+ type (cbf) {
146
+ const callbackFunction = cbf || false
142
147
 
143
- // This is quick and incomplete.
144
- Sentences.prototype.type = function (cbf) {
145
- const callbackFunction = cbf || false
146
-
147
- // Check for implicit you before popping a tag.
148
- const implicitYou = this.implicitYou()
149
-
150
- // FIXME - punct seems useless
151
- let lastElement = this.posObj.punct()
152
- // console.log(lastElement)
153
- lastElement = (lastElement.length !== 0) ? lastElement.pop() : this.posObj.tags.pop()
154
- // console.log(lastElement)
155
-
156
- if (lastElement.pos !== '.') {
157
- if (implicitYou) {
158
- this.senType = 'COMMAND'
159
- } else if (_.contains(['WDT', 'WP', 'WP$', 'WRB'], this.posObj.tags[0].pos)) {
160
- // Sentences that start with: who, what where when why and how, then they are questions
161
- this.senType = 'INTERROGATIVE'
162
- } else if (_.contains(['PRP'], lastElement.pos)) {
163
- // Sentences that end in a Personal pronoun are most likely questions
164
- // eg. We should run away, should we [?]
165
- // eg. You want to see that again, do you [?]
166
- this.senType = 'INTERROGATIVE'
167
- } else {
168
- this.senType = 'UNKNOWN'
169
- }
170
- } else {
171
- switch (lastElement.token) {
172
- case '?':
148
+ // Check for implicit you before popping a tag.
149
+ const implicitYou = this.implicitYou()
150
+
151
+ // FIXME - punct seems useless
152
+ let lastElement = this.posObj.punct()
153
+ // console.log(lastElement)
154
+ lastElement = (lastElement.length !== 0) ? lastElement.pop() : this.posObj.tags.pop()
155
+ // console.log(lastElement)
156
+
157
+ if (lastElement.pos !== '.') {
158
+ if (implicitYou) {
159
+ this.senType = 'COMMAND'
160
+ } else if (_.contains(['WDT', 'WP', 'WP$', 'WRB'], this.posObj.tags[0].pos)) {
161
+ // Sentences that start with: who, what where when why and how, then they are questions
162
+ this.senType = 'INTERROGATIVE'
163
+ } else if (_.contains(['PRP'], lastElement.pos)) {
164
+ // Sentences that end in a Personal pronoun are most likely questions
165
+ // eg. We should run away, should we [?]
166
+ // eg. You want to see that again, do you [?]
173
167
  this.senType = 'INTERROGATIVE'
174
- break
175
- case '!':
176
- this.senType = (implicitYou) ? 'COMMAND' : 'EXCLAMATORY'
177
- break
178
- case '.':
179
- this.senType = (implicitYou) ? 'COMMAND' : 'DECLARATIVE'
180
- break
168
+ } else {
169
+ this.senType = 'UNKNOWN'
170
+ }
171
+ } else {
172
+ switch (lastElement.token) {
173
+ case '?':
174
+ this.senType = 'INTERROGATIVE'
175
+ break
176
+ case '!':
177
+ this.senType = (implicitYou) ? 'COMMAND' : 'EXCLAMATORY'
178
+ break
179
+ case '.':
180
+ this.senType = (implicitYou) ? 'COMMAND' : 'DECLARATIVE'
181
+ break
182
+ }
181
183
  }
182
- }
183
184
 
184
- if (callbackFunction && _.isFunction(callbackFunction)) {
185
- callbackFunction(this)
186
- } else {
187
- return this.senType
185
+ if (callbackFunction && _.isFunction(callbackFunction)) {
186
+ callbackFunction(this)
187
+ } else {
188
+ return this.senType
189
+ }
188
190
  }
189
191
  }
190
192
 
191
- module.exports = Sentences
193
+ module.exports = SentenceAnalyzer
@@ -27,79 +27,81 @@ const Trie = require('../trie/trie')
27
27
  // Words that are an edit distance of n away from the mispelled word are considered infinitely more probable than words that are of an edit distance >n
28
28
 
29
29
  // wordlist is a corpus (an array) from which word probabilities are calculated (so something like /usr/share/dict/words (on OSX) will work okay, but real world text will work better)
30
- function Spellcheck (wordlist) {
31
- this.trie = new Trie()
32
- this.trie.addStrings(wordlist)
33
- this.word2frequency = {}
34
- for (const i in wordlist) {
35
- if (!this.word2frequency[wordlist[i]]) {
36
- this.word2frequency[wordlist[i]] = 0
30
+ class Spellcheck {
31
+ constructor (wordlist) {
32
+ this.trie = new Trie()
33
+ this.trie.addStrings(wordlist)
34
+ this.word2frequency = {}
35
+ for (const i in wordlist) {
36
+ if (!this.word2frequency[wordlist[i]]) {
37
+ this.word2frequency[wordlist[i]] = 0
38
+ }
39
+ this.word2frequency[wordlist[i]]++
37
40
  }
38
- this.word2frequency[wordlist[i]]++
39
41
  }
40
- }
41
42
 
42
- Spellcheck.prototype.isCorrect = function (word) {
43
- return this.trie.contains(word)
44
- }
43
+ isCorrect (word) {
44
+ return this.trie.contains(word)
45
+ }
45
46
 
46
- // Returns a list of suggested corrections, from highest to lowest probability
47
- // maxDistance is the maximum edit distance
48
- // According to Norvig, literature suggests that 80% to 95% of spelling errors are an edit distance of 1 away from the correct word. This is good, because there are roughly 54n+25 strings 1 edit distance away from any given string of length n. So after maxDistance = 2, this becomes very slow.
49
- Spellcheck.prototype.getCorrections = function (word, maxDistance) {
50
- const self = this
51
- if (!maxDistance) maxDistance = 1
52
- let edits = this.editsWithMaxDistance(word, maxDistance)
53
- edits = edits.slice(1, edits.length)
54
- edits = edits.map(function (editList) {
55
- return editList.filter(function (word) { return self.isCorrect(word) })
56
- .map(function (word) { return [word, self.word2frequency[word]] })
57
- .sort(function (a, b) { return a[1] > b[1] ? -1 : 1 })
58
- .map(function (wordscore) { return wordscore[0] })
59
- })
60
- let flattened = []
61
- for (const i in edits) {
62
- if (edits[i].length) {
63
- flattened = flattened.concat(edits[i])
47
+ // Returns a list of suggested corrections, from highest to lowest probability
48
+ // maxDistance is the maximum edit distance
49
+ // According to Norvig, literature suggests that 80% to 95% of spelling errors are an edit distance of 1 away from the correct word. This is good, because there are roughly 54n+25 strings 1 edit distance away from any given string of length n. So after maxDistance = 2, this becomes very slow.
50
+ getCorrections (word, maxDistance) {
51
+ const self = this
52
+ if (!maxDistance) maxDistance = 1
53
+ let edits = this.editsWithMaxDistance(word, maxDistance)
54
+ edits = edits.slice(1, edits.length)
55
+ edits = edits.map(function (editList) {
56
+ return editList.filter(function (word) { return self.isCorrect(word) })
57
+ .map(function (word) { return [word, self.word2frequency[word]] })
58
+ .sort(function (a, b) { return a[1] > b[1] ? -1 : 1 })
59
+ .map(function (wordscore) { return wordscore[0] })
60
+ })
61
+ let flattened = []
62
+ for (const i in edits) {
63
+ if (edits[i].length) {
64
+ flattened = flattened.concat(edits[i])
65
+ }
64
66
  }
67
+ return flattened.filter(function (v, i, a) {
68
+ return a.indexOf(v) === i
69
+ })
65
70
  }
66
- return flattened.filter(function (v, i, a) {
67
- return a.indexOf(v) === i
68
- })
69
- }
70
71
 
71
- // Returns all edits that are 1 edit-distance away from the input word
72
- Spellcheck.prototype.edits = function (word) {
73
- const alphabet = 'abcdefghijklmnopqrstuvwxyz'
74
- let edits = []
75
- for (let i = 0; i < word.length + 1; i++) {
76
- if (i > 0) edits.push(word.slice(0, i - 1) + word.slice(i, word.length)) // deletes
77
- if (i > 0 && i < word.length + 1) edits.push(word.slice(0, i - 1) + word.slice(i, i + 1) + word.slice(i - 1, i) + word.slice(i + 1, word.length)) // transposes
78
- for (let k = 0; k < alphabet.length; k++) {
79
- if (i > 0) edits.push(word.slice(0, i - 1) + alphabet[k] + word.slice(i, word.length)) // replaces
80
- edits.push(word.slice(0, i) + alphabet[k] + word.slice(i, word.length)) // inserts
72
+ // Returns all edits that are 1 edit-distance away from the input word
73
+ edits (word) {
74
+ const alphabet = 'abcdefghijklmnopqrstuvwxyz'
75
+ let edits = []
76
+ for (let i = 0; i < word.length + 1; i++) {
77
+ if (i > 0) edits.push(word.slice(0, i - 1) + word.slice(i, word.length)) // deletes
78
+ if (i > 0 && i < word.length + 1) edits.push(word.slice(0, i - 1) + word.slice(i, i + 1) + word.slice(i - 1, i) + word.slice(i + 1, word.length)) // transposes
79
+ for (let k = 0; k < alphabet.length; k++) {
80
+ if (i > 0) edits.push(word.slice(0, i - 1) + alphabet[k] + word.slice(i, word.length)) // replaces
81
+ edits.push(word.slice(0, i) + alphabet[k] + word.slice(i, word.length)) // inserts
82
+ }
81
83
  }
84
+ // Deduplicate edits
85
+ edits = edits.filter(function (v, i, a) { return a.indexOf(v) === i })
86
+ return edits
82
87
  }
83
- // Deduplicate edits
84
- edits = edits.filter(function (v, i, a) { return a.indexOf(v) === i })
85
- return edits
86
- }
87
88
 
88
- // Returns all edits that are up to "distance" edit distance away from the input word
89
- Spellcheck.prototype.editsWithMaxDistance = function (word, distance) {
90
- return this.editsWithMaxDistanceHelper(distance, [[word]])
91
- }
89
+ // Returns all edits that are up to "distance" edit distance away from the input word
90
+ editsWithMaxDistance (word, distance) {
91
+ return this.editsWithMaxDistanceHelper(distance, [[word]])
92
+ }
92
93
 
93
- Spellcheck.prototype.editsWithMaxDistanceHelper = function (distanceCounter, distance2edits) {
94
- if (distanceCounter === 0) return distance2edits
95
- const currentDepth = distance2edits.length - 1
96
- const words = distance2edits[currentDepth]
97
- // const edits = this.edits(words[0])
98
- distance2edits[currentDepth + 1] = []
99
- for (const i in words) {
100
- distance2edits[currentDepth + 1] = distance2edits[currentDepth + 1].concat(this.edits(words[i]))
94
+ editsWithMaxDistanceHelper (distanceCounter, distance2edits) {
95
+ if (distanceCounter === 0) return distance2edits
96
+ const currentDepth = distance2edits.length - 1
97
+ const words = distance2edits[currentDepth]
98
+ // const edits = this.edits(words[0])
99
+ distance2edits[currentDepth + 1] = []
100
+ for (const i in words) {
101
+ distance2edits[currentDepth + 1] = distance2edits[currentDepth + 1].concat(this.edits(words[i]))
102
+ }
103
+ return this.editsWithMaxDistanceHelper(distanceCounter - 1, distance2edits)
101
104
  }
102
- return this.editsWithMaxDistanceHelper(distanceCounter - 1, distance2edits)
103
105
  }
104
106
 
105
107
  module.exports = Spellcheck
@@ -22,31 +22,33 @@ THE SOFTWARE.
22
22
 
23
23
  'use strict'
24
24
 
25
- function Bag () {
26
- this.dictionary = []
27
- this.nElement = 0
28
- };
29
-
30
- Bag.prototype.add = function (element) {
31
- this.dictionary.push(element)
32
- this.nElement++
33
- return this
34
- }
35
-
36
- Bag.prototype.isEmpty = function () {
37
- return this.nElement > 0
38
- }
39
-
40
- Bag.prototype.contains = function (item) {
41
- return this.dictionary.indexOf(item) >= 0
42
- }
43
-
44
- /**
45
- * unpack the bag , and get all items
46
- */
47
- Bag.prototype.unpack = function () {
48
- // return a copy is better than original
49
- return this.dictionary.slice()
25
+ class Bag {
26
+ constructor () {
27
+ this.dictionary = []
28
+ this.nElement = 0
29
+ }
30
+
31
+ add (element) {
32
+ this.dictionary.push(element)
33
+ this.nElement++
34
+ return this
35
+ }
36
+
37
+ isEmpty () {
38
+ return this.nElement > 0
39
+ }
40
+
41
+ contains (item) {
42
+ return this.dictionary.indexOf(item) >= 0
43
+ }
44
+
45
+ /**
46
+ * unpack the bag , and get all items
47
+ */
48
+ unpack () {
49
+ // return a copy is better than original
50
+ return this.dictionary.slice()
51
+ }
50
52
  }
51
53
 
52
54
  module.exports = Bag
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "natural",
3
3
  "description": "General natural language (tokenizing, stemming (English, Russian, Spanish), part-of-speech tagging, sentiment analysis, classification, inflection, phonetics, tfidf, WordNet, jaro-winkler, Levenshtein distance, Dice's Coefficient) facilities for node.",
4
- "version": "7.0.2",
4
+ "version": "7.0.5",
5
5
  "homepage": "https://github.com/NaturalNode/natural",
6
6
  "repository": {
7
7
  "type": "git",
@@ -77,10 +77,9 @@
77
77
  "benchmark": "node benchmarks",
78
78
  "build": "tsc && ncp spec/test_data dist",
79
79
  "clean": "rimraf *~ #* *classifier.json dist io_spec/tmp/*.json coverage",
80
- "test": "cross-env NODE_PATH=. jasmine --random=false spec/*_spec.js",
81
80
  "test_io": "jasmine --random=false io_spec/*_spec.js",
82
- "test_ts": "cross-env NODE_PATH=.:./dist jasmine --random=false dist/ts_spec/*_spec.js",
83
- "coverage": "nyc --reporter=lcov npm run test && nyc --reporter=lcov npm run test_io && nyc --reporter=lcov npm run test_ts",
81
+ "test": "cross-env NODE_PATH=.:./dist jasmine --random=false dist/spec/*_spec.js",
82
+ "coverage": "nyc --no-clean npm run test && nyc --no-clean npm run test_io",
84
83
  "test_browser": "cross-env NODE_PATH=. node ./node_modules/gulp/bin/gulp.js",
85
84
  "lint": "eslint . --ext .ts"
86
85
  },
package/tsconfig.json CHANGED
@@ -17,7 +17,7 @@
17
17
  },
18
18
  "include": [
19
19
  "lib/natural/**/*.ts",
20
- "ts_spec/*.ts",
20
+ "spec/*.ts",
21
21
  "io_spec/*.ts"
22
22
  , "lib/natural/analyzers/SenType.ts" ],
23
23
  "exclude": [
@@ -1,130 +0,0 @@
1
- /*
2
- Unit test of Classifier
3
- Copyright (C) 2018 Hugo W.L. ter Doest
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in
13
- all copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
- THE SOFTWARE.
22
- */
23
-
24
- 'use strict'
25
-
26
- import {
27
- Context,
28
- FeatureSet,
29
- Sample,
30
- MaxEntClassifier as Classifier,
31
- SEElement
32
- } from 'lib/natural'
33
-
34
- import type { Element } from 'lib/natural'
35
-
36
- const classifierFilename = 'classifier.json'
37
- const minImprovement = 0.01
38
- const nrIterations = 20
39
-
40
- let sample: Sample
41
- let featureSet: FeatureSet
42
- let classifier: Classifier
43
-
44
- const DEBUG = false
45
-
46
- describe('The MaxEnt module', function () {
47
- it('The Sample class creates a sample', function () {
48
- sample = new Sample()
49
- sample.addElement(new SEElement('x', new Context('0')))
50
- sample.addElement(new SEElement('x', new Context('0')))
51
- sample.addElement(new SEElement('x', new Context('0')))
52
- sample.addElement(new SEElement('y', new Context('0')))
53
- sample.addElement(new SEElement('y', new Context('0')))
54
- sample.addElement(new SEElement('y', new Context('0')))
55
-
56
- sample.addElement(new SEElement('x', new Context('1')))
57
- sample.addElement(new SEElement('y', new Context('1')))
58
- sample.addElement(new SEElement('y', new Context('1')))
59
- sample.addElement(new SEElement('y', new Context('1')))
60
-
61
- expect(sample.size()).toBe(10)
62
- })
63
-
64
- it('The FeatureSet class creates a feature set', function () {
65
- featureSet = new FeatureSet()
66
- sample.generateFeatures(featureSet)
67
-
68
- expect(featureSet.size()).toBe(2)
69
- })
70
-
71
- it('The Classifier class creates a classifier', function () {
72
- // Create a classifier
73
- classifier = new Classifier(featureSet, sample)
74
-
75
- expect(classifier).toBeDefined()
76
- })
77
-
78
- it('Classifier does not need a correction feature', function () {
79
-
80
- })
81
-
82
- it('The classifier stops training after a specified number or iterations ' +
83
- 'or when the minimum improvement in likelihood is reached', function () {
84
- classifier.train(nrIterations, minImprovement)
85
-
86
- expect(classifier.scaler.iteration).toBeLessThan(nrIterations + 1)
87
- if (classifier.scaler.iteration < nrIterations) {
88
- expect(classifier.scaler.improvement).toBeLessThan(minImprovement)
89
- }
90
- })
91
-
92
- it('Save classifer to a file', function (done) {
93
- classifier.save(classifierFilename, function (err, c) {
94
- if (err !== null) {
95
- console.log(err)
96
- } else {
97
- DEBUG && console.log('Classifier saved to ' + classifierFilename)
98
- }
99
- done()
100
- })
101
- })
102
-
103
- let newClassifier: Classifier
104
- it('Load classifer', function (done) {
105
- classifier.load(classifierFilename, SEElement as unknown as Element, function (err, c) {
106
- if (err !== null) {
107
- console.log(err)
108
- } else if (c !== undefined) {
109
- DEBUG && console.log('Classifier loaded from ' + classifierFilename)
110
- newClassifier = c
111
- }
112
- done()
113
- })
114
- if (newClassifier !== undefined) {
115
- classifier = newClassifier
116
- }
117
- })
118
-
119
- it('The classifier classifies events', function () {
120
- let context = new Context('0')
121
- DEBUG && console.log('Classes plus scores ' + JSON.stringify(classifier.getClassifications(context)))
122
- let classification = classifier.classify(context)
123
- expect(classification).toBe('x')
124
-
125
- context = new Context('1')
126
- DEBUG && console.log('Classes plus scores ' + JSON.stringify(classifier.getClassifications(context)))
127
- classification = classifier.classify(context)
128
- expect(classification).toBe('y')
129
- })
130
- })