natural 0.5.4 → 0.6.1
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/.dockerignore +2 -0
- package/.npmignore +1 -0
- package/.travis.yml +1 -1
- package/README.md +412 -89
- package/bayes_classifier.json +1 -1
- package/classifier.json +418 -0
- package/data/kata-dasar.txt +29933 -0
- package/lib/natural/brill_pos_tagger/lib/Brill_POS_Tagger.js +8 -9
- package/lib/natural/brill_pos_tagger/lib/Brill_POS_Tester.js +5 -5
- package/lib/natural/brill_pos_tagger/lib/Brill_POS_Trainer.js +10 -6
- package/lib/natural/brill_pos_tagger/lib/Corpus.js +21 -16
- package/lib/natural/brill_pos_tagger/lib/Lexicon.js +22 -13
- package/lib/natural/brill_pos_tagger/lib/Predicate.js +2 -2
- package/lib/natural/brill_pos_tagger/lib/RuleTemplate.js +2 -2
- package/lib/natural/brill_pos_tagger/lib/RuleTemplates.js +132 -146
- package/lib/natural/brill_pos_tagger/lib/Sentence.js +41 -0
- package/lib/natural/brill_pos_tagger/lib/TF_Parser.js +83 -76
- package/lib/natural/brill_pos_tagger/lib/TF_Parser.pegjs +19 -4
- package/lib/natural/brill_pos_tagger/lib/TransformationRule.js +10 -11
- package/lib/natural/classifiers/classifier.js +15 -8
- package/lib/natural/classifiers/maxent/Classifier.js +125 -0
- package/lib/natural/classifiers/maxent/Context.js +33 -0
- package/lib/natural/classifiers/maxent/Distribution.js +145 -0
- package/lib/natural/classifiers/maxent/Element.js +34 -0
- package/lib/natural/classifiers/maxent/Feature.js +88 -0
- package/lib/natural/classifiers/maxent/FeatureSet.js +67 -0
- package/lib/natural/classifiers/maxent/GISScaler.js +148 -0
- package/lib/natural/classifiers/maxent/POS/ME_Corpus.js +56 -0
- package/lib/natural/classifiers/maxent/POS/ME_Sentence.js +73 -0
- package/lib/natural/classifiers/maxent/POS/POS_Element.js +172 -0
- package/lib/natural/classifiers/maxent/Sample.js +141 -0
- package/lib/natural/classifiers/maxent/SimpleExample/SE_Element.js +49 -0
- package/lib/natural/distance/hamming_distance.js +52 -0
- package/lib/natural/distance/jaro-winkler_distance.js +16 -6
- package/lib/natural/distance/levenshtein_distance.js +164 -11
- package/lib/natural/index.js +26 -5
- package/lib/natural/inflectors/noun_inflector.js +15 -13
- package/lib/natural/ngrams/ngrams.js +83 -25
- package/lib/natural/normalizers/normalizer_sv.js +41 -0
- package/lib/natural/sentiment/Basque/senticon_eu.json +21557 -0
- package/lib/natural/sentiment/Catalan/senticon_ca.json +36352 -0
- package/lib/natural/sentiment/Dutch/negations_du.json +3 -0
- package/lib/natural/sentiment/Dutch/pattern-sentiment-nl.json +39650 -0
- package/lib/natural/sentiment/English/negations_en.json +3 -0
- package/lib/natural/sentiment/English/pattern-sentiment-en.json +16024 -0
- package/lib/natural/sentiment/English/senticon_en.json +124197 -0
- package/lib/natural/sentiment/French/pattern-sentiment-fr.json +40906 -0
- package/lib/natural/sentiment/Galician/senticon_gl.json +24427 -0
- package/lib/natural/sentiment/Italian/pattern-sentiment-it.json +24522 -0
- package/lib/natural/sentiment/SentimentAnalyzer.js +116 -0
- package/lib/natural/sentiment/Spanish/afinnShortSortedSpanish.json +1655 -0
- package/lib/natural/sentiment/Spanish/negations_es.json +3 -0
- package/lib/natural/sentiment/Spanish/senticon_es.json +56722 -0
- package/lib/natural/sentiment/tools/README.md +31 -0
- package/lib/natural/sentiment/tools/XmlParser4PatternData.js +31 -0
- package/lib/natural/sentiment/tools/sentimentXmlParser.js +30 -0
- package/lib/natural/stemmers/indonesian/base_stemmer_id.js +86 -0
- package/lib/natural/stemmers/indonesian/prefix_rules.js +1027 -0
- package/lib/natural/stemmers/indonesian/removal.js +49 -0
- package/lib/natural/stemmers/indonesian/stemmer_id.js +307 -0
- package/lib/natural/stemmers/indonesian/suffix_rules.js +75 -0
- package/lib/natural/stemmers/porter_stemmer_es.js +265 -199
- package/lib/natural/stemmers/porter_stemmer_fr.js +1 -1
- package/lib/natural/stemmers/porter_stemmer_nl.js +362 -0
- package/lib/natural/stemmers/porter_stemmer_sv.js +99 -0
- package/lib/natural/stemmers/stemmer_es.js +18 -12
- package/lib/natural/stemmers/stemmer_nl.js +64 -0
- package/lib/natural/stemmers/stemmer_sv.js +61 -0
- package/lib/natural/tfidf/tfidf.js +27 -4
- package/lib/natural/tokenizers/aggressive_tokenizer_id.js +44 -0
- package/lib/natural/tokenizers/aggressive_tokenizer_sv.js +40 -0
- package/lib/natural/tokenizers/aggressive_tokenizer_vi.js +37 -0
- package/lib/natural/tokenizers/orthography_matchers.js +33 -0
- package/lib/natural/tokenizers/regexp_tokenizer.js +23 -3
- package/lib/natural/tokenizers/sentence_tokenizer.js +1 -1
- package/lib/natural/util/stopwords_id.js +119 -0
- package/lib/natural/util/stopwords_no.js +1 -1
- package/lib/natural/util/stopwords_sv.js +70 -0
- package/lib/natural/wordnet/wordnet_file.js +7 -1
- package/lr_classifier.json +1 -1
- package/package-lock.json +378 -0
- package/package.json +29 -21
package/README.md
CHANGED
|
@@ -3,6 +3,7 @@ natural
|
|
|
3
3
|
|
|
4
4
|
[](https://www.npmjs.com/package/natural)
|
|
5
5
|
[](https://travis-ci.org/NaturalNode/natural)
|
|
6
|
+
[](https://slack.bri.im)
|
|
6
7
|
|
|
7
8
|
"Natural" is a general natural language facility for nodejs. Tokenizing,
|
|
8
9
|
stemming, classification, phonetics, tf-idf, WordNet, string similarity,
|
|
@@ -14,8 +15,7 @@ contributions and the like.
|
|
|
14
15
|
Note that many algorithms from Rob Ellis's [node-nltools](https://github.com/NaturalNode/node-nltools) are
|
|
15
16
|
being merged into this project and will be maintained from here onward.
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
will be in order. Thanks to Polyakov Vladimir, Russian stemming has been added!, Thanks to David Przybilla, Spanish stemming has been added!.
|
|
18
|
+
While most of the algorithms are English-specific, contributors have implemented support for other languages. Thanks to Polyakov Vladimir, Russian stemming has been added! Thanks to David Przybilla, Spanish stemming has been added! Thanks to [even more contributors](https://github.com/NaturalNode/natural/graphs/contributors), stemming and tokenizing in more languages have been added.
|
|
19
19
|
|
|
20
20
|
Aside from this README, the only documentation is [this DZone article](http://www.dzone.com/links/r/using_natural_a_nlp_module_for_nodejs.html), [this free course on Egghead.io](https://egghead.io/courses/natural-language-processing-in-javascript-with-natural), and [here on my blog](http://www.chrisumbel.com/article/node_js_natural_language_porter_stemmer_lancaster_bayes_naive_metaphone_soundex), which is a bit older.
|
|
21
21
|
|
|
@@ -24,8 +24,12 @@ Aside from this README, the only documentation is [this DZone article](http://ww
|
|
|
24
24
|
* [Installation](#installation)
|
|
25
25
|
* [Tokenizers](#tokenizers)
|
|
26
26
|
* [String Distance](#string-distance)
|
|
27
|
+
* [Approximate String Matching](#approximate-string-matching)
|
|
27
28
|
* [Stemmers](#stemmers)
|
|
28
29
|
* [Classifiers](#classifiers)
|
|
30
|
+
* [Bayesian and logistic regression](#bayesian-and-logistic-regression)
|
|
31
|
+
* [Maximum Entropy Classifier](#maximum-entropy-classifier)
|
|
32
|
+
* [Sentiment Analysis](#sentiment-analysis)
|
|
29
33
|
* [Phonetics](#phonetics)
|
|
30
34
|
* [Inflectors](#inflectors)
|
|
31
35
|
* [N-Grams](#n-grams)
|
|
@@ -37,7 +41,6 @@ Aside from this README, the only documentation is [this DZone article](http://ww
|
|
|
37
41
|
* [WordNet](#wordnet)
|
|
38
42
|
* [Spellcheck](#spellcheck)
|
|
39
43
|
* [POS Tagger](#pos-tagger)
|
|
40
|
-
* [Acknowledgements/references](#acknowledgements-and-references)
|
|
41
44
|
* [Development](#development)
|
|
42
45
|
* [License](#license)
|
|
43
46
|
|
|
@@ -78,16 +81,64 @@ console.log(tokenizer.tokenize("flea-dog"));
|
|
|
78
81
|
tokenizer = new natural.WordPunctTokenizer();
|
|
79
82
|
console.log(tokenizer.tokenize("my dog hasn't any fleas."));
|
|
80
83
|
// [ 'my', 'dog', 'hasn', '\'', 't', 'any', 'fleas', '.' ]
|
|
81
|
-
|
|
84
|
+
|
|
85
|
+
tokenizer = new natural.OrthographyTokenizer({language: "fi"});
|
|
86
|
+
console.log(tokenizer.tokenize("Mikä sinun nimesi on?"));
|
|
87
|
+
// [ 'Mikä', 'sinun', 'nimesi', 'on' ]
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Overview of available tokenizers:
|
|
91
|
+
|
|
92
|
+
| Tokenizer | Language | Explanation |
|
|
93
|
+
|:-----------------------|:------------|:------------------------------------------------------------------------|
|
|
94
|
+
| WordTokenizer | Any | Splits on anything except alphabetic characters, digits and underscore |
|
|
95
|
+
| WordPunctTokenizer | Any | Splits on anything except alphabetic characters, digits, punctuation and underscore |
|
|
96
|
+
| SentenceTokenizer | Any | Break string up in to parts based on punctation and quotation marks |
|
|
97
|
+
| CaseTokenizer | Any? | If lower and upper case are the same, the character is assumed to be whitespace or something else (punctuation) |
|
|
98
|
+
| RegexpTokenizer | Any | Splits on a regular expression that either defines sequences of word characters or gap characters |
|
|
99
|
+
| OrthographyTokenizer | Finnish | Splits on anything except alpabetic characters, digits and underscore |
|
|
100
|
+
| TreebankWordTokenizer | Any | |
|
|
101
|
+
| AggressiveTokenizer | English | |
|
|
102
|
+
| AggressiveTokenizerFa | Farsi | |
|
|
103
|
+
| AggressiveTokenizerFr | French | |
|
|
104
|
+
| AggressiveTokenizerRu | Russian | |
|
|
105
|
+
| AggressiveTokenizerEs | Spanish | |
|
|
106
|
+
| AggressiveTokenizerIt | Italian | |
|
|
107
|
+
| AggressiveTokenizerPl | Polish | |
|
|
108
|
+
| AggressiveTokenizerPt | Portugese | |
|
|
109
|
+
| AggressiveTokenizerNo | Norwegian | |
|
|
110
|
+
| AggressiveTokenizerSv | Swedish | |
|
|
111
|
+
| AggressiveTokenizerVi | Vietnamese | |
|
|
112
|
+
| TokenizerJa | Japanese | | |
|
|
113
|
+
|
|
114
|
+
|
|
82
115
|
|
|
83
116
|
## String Distance
|
|
84
117
|
|
|
85
|
-
Natural provides an implementation of
|
|
86
|
-
This will return a number between 0 and 1 which tells how closely the strings match (0 = not at all, 1 = exact match):
|
|
118
|
+
Natural provides an implementation of three algorithms for calculating string distance: Hamming distance, Jaro-Winkler, Levenshtein distance, and Dice coefficient.
|
|
87
119
|
|
|
120
|
+
[Hamming distance](https://en.wikipedia.org/wiki/Hamming_distance) measures the distance between two strings of equal length by counting the number of different characters. The third parameter indicates whether case should be ignored. By default the algorithm is case sensitive.
|
|
88
121
|
```javascript
|
|
89
122
|
var natural = require('natural');
|
|
90
|
-
console.log(natural.
|
|
123
|
+
console.log(natural.HammingDistance("karolin", "kathrin", false));
|
|
124
|
+
console.log(natural.HammingDistance("karolin", "kerstin", false));
|
|
125
|
+
// If strings differ in length -1 is returned
|
|
126
|
+
console.log(natural.HammingDistance("short string", "longer string", false));
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Output:
|
|
130
|
+
```javascript
|
|
131
|
+
3
|
|
132
|
+
3
|
|
133
|
+
-1
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
The [Jaro–Winkler](http://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance) string distance measuring algorithm will return a number between 0 and 1 which tells how closely the strings match (0 = not at all, 1 = exact match):
|
|
138
|
+
|
|
139
|
+
```javascript
|
|
140
|
+
var natural = require('natural');
|
|
141
|
+
console.log(natural.JaroWinklerDistance("dixon","dicksonx"));
|
|
91
142
|
console.log(natural.JaroWinklerDistance('not', 'same'));
|
|
92
143
|
```
|
|
93
144
|
|
|
@@ -98,7 +149,14 @@ Output:
|
|
|
98
149
|
0
|
|
99
150
|
```
|
|
100
151
|
|
|
101
|
-
|
|
152
|
+
If the distance between the strings is already known you can pass it as a third parameter. And you can force the algorithm to ignore case by passing a fourth parameter as follows:
|
|
153
|
+
```javascript
|
|
154
|
+
var natural = require('natural');
|
|
155
|
+
console.log(natural.JaroWinklerDistance("dixon","dicksonx", undefined, true));
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
Natural also offers support for [Levenshtein](https://en.wikipedia.org/wiki/Levenshtein_distance) distances:
|
|
102
160
|
|
|
103
161
|
```javascript
|
|
104
162
|
var natural = require('natural');
|
|
@@ -129,7 +187,46 @@ Output:
|
|
|
129
187
|
1
|
|
130
188
|
```
|
|
131
189
|
|
|
132
|
-
|
|
190
|
+
Full Damerau-Levenshtein matching can be used if you want to consider character transpositions as a valid edit operation.
|
|
191
|
+
|
|
192
|
+
```javascript
|
|
193
|
+
console.log(natural.DamerauLevenshteinDistance("az", "za"));
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Output:
|
|
197
|
+
```javascript
|
|
198
|
+
1
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
The transposition cost can be modified as well:
|
|
202
|
+
|
|
203
|
+
```javascript
|
|
204
|
+
console.log(natural.DamerauLevenshteinDistance("az", "za", { transposition_cost: 0 }))
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Output:
|
|
208
|
+
```javascript
|
|
209
|
+
0
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
A restricted form of Damerau-Levenshtein (Optimal String Alignment) is available.
|
|
213
|
+
|
|
214
|
+
This form of matching is more space efficient than unrestricted Damerau-Levenshtein, by only considering a transposition if there are no characters between the transposed characters.
|
|
215
|
+
|
|
216
|
+
Comparison:
|
|
217
|
+
|
|
218
|
+
```javascript
|
|
219
|
+
// Optimal String Alignment
|
|
220
|
+
console.log(natural.DamerauLevenshteinDistance('ABC', 'ACB'), { restricted: true });
|
|
221
|
+
1
|
|
222
|
+
console.log(natural.DamerauLevenshteinDistance('CA', 'ABC', { restricted: true }));
|
|
223
|
+
2
|
|
224
|
+
// Unrestricted Damerau-Levenshtein
|
|
225
|
+
console.log(natural.DamerauLevenshteinDistance('CA', 'ABC', { restricted: false }));
|
|
226
|
+
1
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
And [Dice's co-efficient](https://en.wikipedia.org/wiki/S%C3%B8rensen%E2%80%93Dice_coefficient):
|
|
133
230
|
|
|
134
231
|
```javascript
|
|
135
232
|
var natural = require('natural');
|
|
@@ -144,9 +241,28 @@ Output:
|
|
|
144
241
|
0
|
|
145
242
|
```
|
|
146
243
|
|
|
244
|
+
## Approximate String Matching
|
|
245
|
+
Currently matching is supported via the Levenshtein algorithm.
|
|
246
|
+
|
|
247
|
+
```javascript
|
|
248
|
+
var natural = require('natural');
|
|
249
|
+
var source = 'The RainCoat BookStore';
|
|
250
|
+
var target = 'All the best books are here at the Rain Coats Book Store';
|
|
251
|
+
|
|
252
|
+
console.log(natural.LevenshteinDistance(source, target, {search: true}));
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
Output:
|
|
256
|
+
|
|
257
|
+
```javascript
|
|
258
|
+
{ substring: 'the Rain Coats Book Store', distance: 4 }
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
The following
|
|
262
|
+
|
|
147
263
|
## Stemmers
|
|
148
264
|
|
|
149
|
-
Currently stemming is supported via the [Porter](http://tartarus.org/martin/PorterStemmer/index.html) and [Lancaster](http://www.comp.lancs.ac.uk/computing/research/stemming/) (Paice/Husk) algorithms.
|
|
265
|
+
Currently stemming is supported via the [Porter](http://tartarus.org/martin/PorterStemmer/index.html) and [Lancaster](http://www.comp.lancs.ac.uk/computing/research/stemming/) (Paice/Husk) algorithms. The Indonesian and Japanese stemmers do not follow a known algorithm.
|
|
150
266
|
|
|
151
267
|
```javascript
|
|
152
268
|
var natural = require('natural');
|
|
@@ -170,6 +286,24 @@ console.log(natural.PorterStemmerRu.stem("падший"));
|
|
|
170
286
|
console.log(natural.PorterStemmerEs.stem("jugaría"));
|
|
171
287
|
```
|
|
172
288
|
|
|
289
|
+
The following stemmers are available:
|
|
290
|
+
|
|
291
|
+
| Language | Porter | Lancaster | Other | Module |
|
|
292
|
+
|:------------- |:-----------:|:---------:|:---------:|:------------------|
|
|
293
|
+
| Dutch | X | | | `PorterStemmerNl` |
|
|
294
|
+
| English | X | | | `PorterStemmer` |
|
|
295
|
+
| English | | X | | `LancasterStemmer` |
|
|
296
|
+
| Farsi (in progress) | X | | | `PorterStemmerFa` |
|
|
297
|
+
| French | X | | | `PorterStemmerFr` |
|
|
298
|
+
| Indonesian | | | X | `StemmerId` |
|
|
299
|
+
| Italian | X | | | `PorterStemmerIt` |
|
|
300
|
+
| Japanese | | | X | `StemmerJa` |
|
|
301
|
+
| Norwegian | X | | | `PorterStemmerNo` |
|
|
302
|
+
| Portugese | X | | | `PorterStemmerPt` |
|
|
303
|
+
| Russian | X | | | `PorterStemmerRu` |
|
|
304
|
+
| Swedish | X | | | `PorterStemmerSv` |
|
|
305
|
+
|
|
306
|
+
|
|
173
307
|
`attach()` patches `stem()` and `tokenizeAndStem()` to String as a shortcut to
|
|
174
308
|
`PorterStemmer.stem(token)`. `tokenizeAndStem()` breaks text up into single words
|
|
175
309
|
and returns an array of stemmed tokens.
|
|
@@ -180,7 +314,7 @@ console.log("i am waking up to the sounds of chainsaws".tokenizeAndStem());
|
|
|
180
314
|
console.log("chainsaws".stem());
|
|
181
315
|
```
|
|
182
316
|
|
|
183
|
-
|
|
317
|
+
The same thing can be done with a Lancaster stemmer:
|
|
184
318
|
|
|
185
319
|
```javascript
|
|
186
320
|
natural.LancasterStemmer.attach();
|
|
@@ -190,6 +324,8 @@ console.log("chainsaws".stem());
|
|
|
190
324
|
|
|
191
325
|
## Classifiers
|
|
192
326
|
|
|
327
|
+
### Bayesian and logistic regression
|
|
328
|
+
|
|
193
329
|
Two classifiers are currently supported, [Naive Bayes](http://en.wikipedia.org/wiki/Naive_Bayes_classifier) and [logistic regression](http://en.wikipedia.org/wiki/Logistic_regression).
|
|
194
330
|
The following examples use the BayesClassifier class, but the
|
|
195
331
|
LogisticRegressionClassifier class could be substituted instead.
|
|
@@ -247,7 +383,7 @@ classifier.addDocument(['sell', 'gold'], 'sell');
|
|
|
247
383
|
```
|
|
248
384
|
|
|
249
385
|
The training process can be monitored by subscribing to the event `trainedWithDocument` that's emitted by the classifier, this event's emitted each time a document is finished being trained against:
|
|
250
|
-
|
|
386
|
+
```javascript
|
|
251
387
|
classifier.events.on('trainedWithDocument', function (obj) {
|
|
252
388
|
console.log(obj);
|
|
253
389
|
/* {
|
|
@@ -257,7 +393,7 @@ The training process can be monitored by subscribing to the event `trainedWithDo
|
|
|
257
393
|
* }
|
|
258
394
|
*/
|
|
259
395
|
});
|
|
260
|
-
|
|
396
|
+
```
|
|
261
397
|
A classifier can also be persisted and recalled so you can reuse a training
|
|
262
398
|
|
|
263
399
|
```javascript
|
|
@@ -298,8 +434,215 @@ const PorterStemmerRu = require('./node_modules/natural/lib/natural/stemmers/por
|
|
|
298
434
|
var classifier = new natural.BayesClassifier(PorterStemmerRu);
|
|
299
435
|
```
|
|
300
436
|
|
|
301
|
-
|
|
437
|
+
### Maximum Entropy Classifier
|
|
438
|
+
This module provides a classifier based on maximum entropy modelling. The central idea to maximum entropy modelling is to estimate a probability distribution that that has maximum entropy subject to the evidence that is available. This means that the distribution follows the data it has "seen" but does not make any assumptions beyond that.
|
|
439
|
+
|
|
440
|
+
The module is not specific to natural language processing, or any other application domain. There are little requirements with regard to the data structure it can be trained on. For training, it needs a sample that consists of elements. These elements have two parts:
|
|
441
|
+
* part a: the class of the element
|
|
442
|
+
* part b: the context of the element
|
|
443
|
+
The classifier will, once trained, return the most probable class for a particular context.
|
|
444
|
+
|
|
445
|
+
We start with an explanation of samples and elements. You have to create your own specialisation of the Element class. Your element class should implement the generateFeatures method for inferring feature functions from the sample.
|
|
446
|
+
|
|
447
|
+
#### Samples and elements
|
|
448
|
+
Elements and contexts are created as follows:
|
|
449
|
+
|
|
450
|
+
```javascript
|
|
451
|
+
var MyElement = require('MyElementClass');
|
|
452
|
+
var Context = require('Context');
|
|
453
|
+
var Sample = require('Sample');
|
|
454
|
+
|
|
455
|
+
var x = new MyElementClass("x", new Context("0"));
|
|
456
|
+
// A sample is created from an array of elements
|
|
457
|
+
var sample = new Sample();
|
|
458
|
+
sample.addElement(x);
|
|
459
|
+
```
|
|
460
|
+
A class is a string, contexts may be as complex as you want (as long as it can be serialised).
|
|
461
|
+
|
|
462
|
+
A sample can be saved to and loaded from a file:
|
|
463
|
+
```javascript
|
|
464
|
+
sample.save('sample.json', function(error, sample) {
|
|
465
|
+
...
|
|
466
|
+
});
|
|
467
|
+
```
|
|
468
|
+
A sample can be read from a file as follows.
|
|
469
|
+
|
|
470
|
+
```javascript
|
|
471
|
+
sample.load('sample.json', MyElementClass, function(err, sample) {
|
|
472
|
+
|
|
473
|
+
});
|
|
474
|
+
```
|
|
475
|
+
You have to pass the element class to the load method so that the right element objects can be created from the data.
|
|
476
|
+
|
|
477
|
+
#### Features and feature sets
|
|
478
|
+
Features are functions that map elements to zero or one. Features are defined as follows:
|
|
479
|
+
```javascript
|
|
480
|
+
var Feature = require('Feature');
|
|
481
|
+
|
|
482
|
+
function f(x) {
|
|
483
|
+
if (x.b === "0") {
|
|
484
|
+
return 1;
|
|
485
|
+
}
|
|
486
|
+
return 0;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
var feature = new Feature(f, name, parameters);
|
|
490
|
+
```
|
|
491
|
+
<code>name</code> is a string for the name of the feature function, <code>parameters</code> is an array of strings for the parameters of the feature function. The combination of name and parameters should uniquely distinguish features from each other. Features that are added to a feature set are tested for uniqueness using these properties.
|
|
302
492
|
|
|
493
|
+
A feature set is created like this
|
|
494
|
+
```javascript
|
|
495
|
+
var FeatureSet = require('FeatureSet');
|
|
496
|
+
|
|
497
|
+
var set = new FeatureSet();
|
|
498
|
+
set.addFeature(f, "f", ["0"]);
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
In most cases you will generate feature functions using closures. For instance, when you generate feature functions in a loop that iterates through an array
|
|
502
|
+
```javascript
|
|
503
|
+
var FeatureSet = require('FeatureSet');
|
|
504
|
+
var Feature = require('Feature');
|
|
505
|
+
|
|
506
|
+
var listOfTags = ['NN', 'DET', 'PREP', 'ADJ'];
|
|
507
|
+
var featureSet = new FeatureSet();
|
|
508
|
+
|
|
509
|
+
listofTags.forEach(function(tag) {
|
|
510
|
+
function isTag(x) {
|
|
511
|
+
if (x.b.data.tag === tag) {
|
|
512
|
+
return 1
|
|
513
|
+
}
|
|
514
|
+
return 0;
|
|
515
|
+
}
|
|
516
|
+
featureSet.addFeature(new Feature(f, "f", [tag]));
|
|
517
|
+
});
|
|
518
|
+
```
|
|
519
|
+
In this example you create feature functions that each have a different value for <code>tag</code> in their closure.
|
|
520
|
+
|
|
521
|
+
#### Setting up and training the classifier
|
|
522
|
+
A classifier needs the following parameter:
|
|
523
|
+
* Classes: an array of classes (strings)
|
|
524
|
+
* Features: an array of feature functions
|
|
525
|
+
* Sample: a sample of elements for training the classifier
|
|
526
|
+
|
|
527
|
+
A classifier can be created as follows:
|
|
528
|
+
```javascript
|
|
529
|
+
var Classifier = require('Classifier');
|
|
530
|
+
var classifier = new Classifier(classes, featureSet, sample);
|
|
531
|
+
```
|
|
532
|
+
And it starts training with:
|
|
533
|
+
```javascript
|
|
534
|
+
var maxIterations = 100;
|
|
535
|
+
var minImprovement = .01;
|
|
536
|
+
var p = classifier.train(maxIterations, minImprovement);
|
|
537
|
+
```
|
|
538
|
+
Training is finished when either <code>maxIterations</code> is reached or the improvement in likelihood (of the sample) becomes smaller than <code>minImprovement</code>. It returns a probability distribution that can be stored and retrieved for later usage:
|
|
539
|
+
```javascript
|
|
540
|
+
classifier.save('classifier.json', function(err, c) {
|
|
541
|
+
if (err) {
|
|
542
|
+
console.log(err);
|
|
543
|
+
}
|
|
544
|
+
else {
|
|
545
|
+
// Continue using the classifier
|
|
546
|
+
}
|
|
547
|
+
});
|
|
548
|
+
|
|
549
|
+
classifier.load('classifier.json', function(err, c) {
|
|
550
|
+
if (err) {
|
|
551
|
+
console.log(err);
|
|
552
|
+
}
|
|
553
|
+
else {
|
|
554
|
+
// Use the classifier
|
|
555
|
+
}
|
|
556
|
+
});
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
The training algorithm is based on Generalised Iterative Scaling.
|
|
560
|
+
|
|
561
|
+
#### Applying the classifier
|
|
562
|
+
The classifier can be used to classify contexts in two ways. To get the probabilities for all classes:
|
|
563
|
+
```javascript
|
|
564
|
+
var classifications = classifier.getClassifications(context);
|
|
565
|
+
classifications.forEach(function(classPlusProbability) {
|
|
566
|
+
console.log('Class ' + classPlusProbability.label + ' has score ' + classPlusProbability.value);
|
|
567
|
+
});
|
|
568
|
+
```
|
|
569
|
+
This returns a map from classes to probabilities.
|
|
570
|
+
To get the highest scoring class:
|
|
571
|
+
```javascript
|
|
572
|
+
var class = classifier.classify(context);
|
|
573
|
+
console.log(class);
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
#### Simple example of maximum entropy modelling
|
|
577
|
+
A test is added to the spec folder based on simple elements that have contexts that are either "0" or "1", and classes are "x" and "y".
|
|
578
|
+
```javascript
|
|
579
|
+
{
|
|
580
|
+
"a": "x",
|
|
581
|
+
"b": {
|
|
582
|
+
"data": "0"
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
```
|
|
586
|
+
In the SE_Element class that inherits from Element, the method generateFeatures is implemented. It creates a feature function that tests for context "0".
|
|
587
|
+
|
|
588
|
+
After setting up your own element class, the classifier can be created and trained.
|
|
589
|
+
|
|
590
|
+
#### Application to POS tagging
|
|
591
|
+
A more elaborate example of maximum entropy modelling is provided for part of speech tagging. The following steps are taken to create a classifier and apply it to a test set:
|
|
592
|
+
* A new element class POS_Element is created that has a word window and a tag window around the word to be tagged.
|
|
593
|
+
* From the Brown corpus a sample is generated consisting of POS elements.
|
|
594
|
+
* Feature functions are generated from the sample.
|
|
595
|
+
* A classifier is created and trained.
|
|
596
|
+
* The classifier is applied to a test set. Results are compared to a simple lexicon-based tagger.
|
|
597
|
+
|
|
598
|
+
#### References
|
|
599
|
+
* Adwait RatnaParkhi, Maximum Entropy Models For Natural Language Ambiguity Resolution, University of Pennsylvania, 1998, URL: http://repository.upenn.edu/cgi/viewcontent.cgi?article=1061&context=ircs_reports
|
|
600
|
+
* Darroch, J.N.; Ratcliff, D. (1972). Generalized iterative scaling for log-linear models, The Annals of Mathematical Statistics, Institute of Mathematical Statistics, 43 (5): 1470–1480.
|
|
601
|
+
|
|
602
|
+
## Sentiment Analysis
|
|
603
|
+
This is a simple sentiment analysis algorithm based on a vocabulary that assigns polarity to words. The algorithm calculates the sentiment of a piece of text by summing the polarity of each word and normalizing with the length of the sentence. If a negation occurs the result is made negative. It is used as follows:
|
|
604
|
+
```javascript
|
|
605
|
+
var Analyzer = require('natural').SentimentAnalyzer;
|
|
606
|
+
var stemmer = require('natural').PorterStemmer;
|
|
607
|
+
var analyzer = new Analyzer("English", stemmer, "afinn")
|
|
608
|
+
console.log(analyzer.getSentiment("I like cherries"));
|
|
609
|
+
// 0.6666666666666666
|
|
610
|
+
```
|
|
611
|
+
The constructor has three parameters:
|
|
612
|
+
* Language: see below for supported languages.
|
|
613
|
+
* Stemmer: to increase the coverage of the sentiment analyzer a stemmer may be provided. May be `null`.
|
|
614
|
+
* Vocabulary: sets the type of vocabulary, `"afinn"`, `"senticon"` or `"pattern"` are valid values.
|
|
615
|
+
|
|
616
|
+
Currently, the following languages are supported with type of vocabulary and availability of negations (in alphabetic order):
|
|
617
|
+
|
|
618
|
+
| Language | AFINN | Senticon | Pattern | Negations |
|
|
619
|
+
| ------------- |:-----------:|:---------:|:---------:|:---------:|
|
|
620
|
+
| Basque | | X | | |
|
|
621
|
+
| Catalan | | X | | |
|
|
622
|
+
| Dutch | | | X | X |
|
|
623
|
+
| English | X | X | X | X |
|
|
624
|
+
| French | | | X | |
|
|
625
|
+
| Galician | | X | | |
|
|
626
|
+
| Italian | | | X | |
|
|
627
|
+
| Spanish | X | X | | X |
|
|
628
|
+
|
|
629
|
+
More languages can be added by adding vocabularies and extending the map `languageFiles` in `SentimentAnalyzer.js`. In the tools folder below `lib/natural/sentiment` some tools are provided for transforming vocabularies in Senticon and Pattern format into a JSON format.
|
|
630
|
+
|
|
631
|
+
|
|
632
|
+
|
|
633
|
+
### Acknowledgements and References
|
|
634
|
+
Thanks to Domingo Martín Mancera for providing the basis for this sentiment analyzer in his repo [Lorca](https://github.com/dmarman/lorca).
|
|
635
|
+
|
|
636
|
+
AFINN is a list of English words rated for valence with an integer
|
|
637
|
+
between minus five (negative) and plus five (positive). The words have
|
|
638
|
+
been manually labeled by Finn Årup Nielsen in 2009-2011. Scientific reference can be found [here](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6010). We used [afinn-165](https://github.com/words/afinn-165) which is available as nodejs module.
|
|
639
|
+
|
|
640
|
+
The senticon vocabulary is based on work by Fermin L. Cruz and others:
|
|
641
|
+
Cruz, Fermín L., José A. Troyano, Beatriz Pontes, F. Javier Ortega. Building layered, multilingual sentiment lexicons at synset and lemma levels, Expert Systems with Applications, 2014.
|
|
642
|
+
|
|
643
|
+
The Pattern vocabularies are from the [Pattern project](https://github.com/clips/pattern) of the CLiPS Research Center of University of Antwerpen. These have a PDDL license.
|
|
644
|
+
|
|
645
|
+
## Phonetics
|
|
303
646
|
Phonetic matching (sounds-like) matching can be done with the [SoundEx](http://en.wikipedia.org/wiki/Soundex),
|
|
304
647
|
[Metaphone](http://en.wikipedia.org/wiki/Metaphone) or [DoubleMetaphone](http://en.wikipedia.org/wiki/Metaphone#Double_Metaphone) algorithms
|
|
305
648
|
|
|
@@ -565,7 +908,11 @@ console.log(NGramsZH.ngrams(['一', '个', '中', '文', '测',
|
|
|
565
908
|
## tf-idf
|
|
566
909
|
|
|
567
910
|
[Term Frequency–Inverse Document Frequency (tf-idf)](http://en.wikipedia.org/wiki/Tf%E2%80%93idf) is implemented to determine how important a word (or words) is to a
|
|
568
|
-
document relative to a corpus. The following
|
|
911
|
+
document relative to a corpus. The following formulas are used for calculating tf and idf:
|
|
912
|
+
* tf(t, d) is a so-called raw count, so just the count of the term in the document
|
|
913
|
+
* idf(t, D) uses the following formula: 1 + ln(N / (1 + n_t)) where N is the number of documents, and n_t the number of documents in which the term appears. The 1 + in the denominator is for handling the possibility that n_t is 0.
|
|
914
|
+
|
|
915
|
+
The following example will add four documents to
|
|
569
916
|
a corpus and determine the weight of the word "node" and then the weight of the
|
|
570
917
|
word "ruby" in each document.
|
|
571
918
|
|
|
@@ -648,7 +995,7 @@ document #1 is 1
|
|
|
648
995
|
document #2 is 2
|
|
649
996
|
```
|
|
650
997
|
|
|
651
|
-
The examples above all use strings, which
|
|
998
|
+
The examples above all use strings, which causes natural to automatically tokenize the input.
|
|
652
999
|
If you wish to perform your own tokenization or other kinds of processing, you
|
|
653
1000
|
can do so, then pass in the resultant arrays later. This approach allows you to bypass natural's
|
|
654
1001
|
default preprocessing.
|
|
@@ -790,14 +1137,14 @@ get the number of vertexes:
|
|
|
790
1137
|
```javascript
|
|
791
1138
|
console.log(digraph.v());
|
|
792
1139
|
```
|
|
793
|
-
you will get
|
|
1140
|
+
you will get 7.
|
|
794
1141
|
|
|
795
1142
|
get the number of edges:
|
|
796
1143
|
|
|
797
1144
|
```javascript
|
|
798
1145
|
console.log(digraph.e());
|
|
799
1146
|
```
|
|
800
|
-
you will get
|
|
1147
|
+
you will get 6.
|
|
801
1148
|
|
|
802
1149
|
|
|
803
1150
|
|
|
@@ -825,22 +1172,9 @@ console.log(spt.getDistTo(4));
|
|
|
825
1172
|
```
|
|
826
1173
|
the output will be: 0.35
|
|
827
1174
|
|
|
828
|
-
### hasDistTo(vertex)
|
|
829
|
-
|
|
830
|
-
```javascript
|
|
831
|
-
console.log(spt.hasDistTo(4));
|
|
832
|
-
console.log(spt.hasDistTo(5));
|
|
833
|
-
```
|
|
834
|
-
|
|
835
|
-
output will be:
|
|
836
|
-
|
|
837
|
-
```javascript
|
|
838
|
-
true
|
|
839
|
-
false
|
|
840
|
-
```
|
|
841
|
-
|
|
842
1175
|
### pathTo(vertex)
|
|
843
|
-
|
|
1176
|
+
|
|
1177
|
+
Will return the shortest path:
|
|
844
1178
|
|
|
845
1179
|
```javascript
|
|
846
1180
|
console.log(spt.pathTo(4));
|
|
@@ -862,8 +1196,8 @@ hasPathTo(vertex),
|
|
|
862
1196
|
pathTo(vertex).
|
|
863
1197
|
|
|
864
1198
|
```javascript
|
|
865
|
-
var
|
|
866
|
-
var
|
|
1199
|
+
var LongestPathTree = natural.LongestPathTree;
|
|
1200
|
+
var lpt = new LongestPathTree(digraph, 5);
|
|
867
1201
|
```
|
|
868
1202
|
digraph is an instance of EdgeWeightedDigraph, the second param is the start vertex of DAG.
|
|
869
1203
|
|
|
@@ -872,29 +1206,16 @@ digraph is an instance of EdgeWeightedDigraph, the second param is the start ver
|
|
|
872
1206
|
Will return the dist to vertex.
|
|
873
1207
|
|
|
874
1208
|
```javascript
|
|
875
|
-
console.log(
|
|
1209
|
+
console.log(lpt.getDistTo(4));
|
|
876
1210
|
```
|
|
877
1211
|
the output will be: 2.06
|
|
878
1212
|
|
|
879
|
-
### hasDistTo(vertex)
|
|
880
|
-
|
|
881
|
-
```javascript
|
|
882
|
-
console.log(spt.hasDistTo(4));
|
|
883
|
-
console.log(spt.hasDistTo(5));
|
|
884
|
-
```
|
|
885
|
-
|
|
886
|
-
output will be:
|
|
887
|
-
|
|
888
|
-
```javascript
|
|
889
|
-
true
|
|
890
|
-
false
|
|
891
|
-
```
|
|
892
|
-
|
|
893
1213
|
### pathTo(vertex)
|
|
894
|
-
|
|
1214
|
+
|
|
1215
|
+
Will return the longest path:
|
|
895
1216
|
|
|
896
1217
|
```javascript
|
|
897
|
-
console.log(
|
|
1218
|
+
console.log(lpt.pathTo(4));
|
|
898
1219
|
```
|
|
899
1220
|
|
|
900
1221
|
output will be:
|
|
@@ -1000,9 +1321,19 @@ var rules = new natural.RuleSet(rulesFilename);
|
|
|
1000
1321
|
var tagger = new natural.BrillPOSTagger(lexicon, rules);
|
|
1001
1322
|
|
|
1002
1323
|
var sentence = ["I", "see", "the", "man", "with", "the", "telescope"];
|
|
1003
|
-
console.log(
|
|
1004
|
-
|
|
1005
|
-
|
|
1324
|
+
console.log(tagger.tag(sentence));
|
|
1325
|
+
```
|
|
1326
|
+
This outputs the following:
|
|
1327
|
+
```
|
|
1328
|
+
Sentence {
|
|
1329
|
+
taggedWords:
|
|
1330
|
+
[ { token: 'I', tag: 'NN' },
|
|
1331
|
+
{ token: 'see', tag: 'VB' },
|
|
1332
|
+
{ token: 'the', tag: 'DT' },
|
|
1333
|
+
{ token: 'man', tag: 'NN' },
|
|
1334
|
+
{ token: 'with', tag: 'IN' },
|
|
1335
|
+
{ token: 'the', tag: 'DT' },
|
|
1336
|
+
{ token: 'telescope', tag: 'NN' } ] }
|
|
1006
1337
|
```
|
|
1007
1338
|
|
|
1008
1339
|
### Lexicon
|
|
@@ -1043,34 +1374,30 @@ VBD NN PREV-TAG DT
|
|
|
1043
1374
|
Here the category of the previous word must be <code>DT</code> for the rule to be applied.
|
|
1044
1375
|
|
|
1045
1376
|
### Algorithm
|
|
1046
|
-
The tagger applies transformation rules that may change the category of words. The input sentence
|
|
1377
|
+
The tagger applies transformation rules that may change the category of words. The input sentence is a Sentence object with tagged words. The tagged sentence is processed from left to right. At each step all rules are applied once; rules are applied in the order in which they are specified. Algorithm:
|
|
1047
1378
|
```javascript
|
|
1048
|
-
function(sentence) {
|
|
1049
|
-
var
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
// Apply transformation rules
|
|
1054
|
-
for (var i = 0, size = sentence.length; i < size; i++) {
|
|
1055
|
-
this.transformation_rules.forEach(function(rule) {
|
|
1056
|
-
rule.apply(tagged_sentence, i);
|
|
1379
|
+
Brill_POS_Tagger.prototype.applyRules = function(sentence) {
|
|
1380
|
+
for (var i = 0, size = sentence.taggedWords.length; i < size; i++) {
|
|
1381
|
+
this.ruleSet.getRules().forEach(function(rule) {
|
|
1382
|
+
rule.apply(sentence, i);
|
|
1057
1383
|
});
|
|
1058
1384
|
}
|
|
1059
|
-
return
|
|
1060
|
-
}
|
|
1385
|
+
return sentence;
|
|
1386
|
+
};
|
|
1061
1387
|
```
|
|
1388
|
+
The output is a Sentence object just like the input sentence.
|
|
1062
1389
|
|
|
1063
1390
|
### Adding a predicate
|
|
1064
1391
|
Predicates are defined in module <code>lib/RuleTemplates.js</code>. In that file
|
|
1065
1392
|
predicate names are mapped to metadata for generaring transformation rules. The following properties must be supplied:
|
|
1066
1393
|
* Name of the predicate
|
|
1067
1394
|
* A function that evaluates the predicate (should return a boolean)
|
|
1068
|
-
* A window <code>[i, j]</code> that defines the span of the predicate in the
|
|
1395
|
+
* A window <code>[i, j]</code> that defines the span of the predicate in the
|
|
1069
1396
|
sentence relative to the current position
|
|
1070
1397
|
* The number of parameter the predicate needs: 0, 1 or 2
|
|
1071
|
-
* If relevant, a function for parameter 1 that returns its possible values
|
|
1398
|
+
* If relevant, a function for parameter 1 that returns its possible values
|
|
1072
1399
|
at the current position in the sentence (for generating rules in training)
|
|
1073
|
-
* If relevant, a function for parameter 2 that returns its possible values
|
|
1400
|
+
* If relevant, a function for parameter 2 that returns its possible values
|
|
1074
1401
|
at the current position in the sentence (for training)
|
|
1075
1402
|
|
|
1076
1403
|
A typical entry for a rule templates looks like this:
|
|
@@ -1086,13 +1413,13 @@ A typical entry for a rule templates looks like this:
|
|
|
1086
1413
|
"parameter1Values": nextTagParameterValues
|
|
1087
1414
|
}
|
|
1088
1415
|
```
|
|
1089
|
-
A predicate function accepts a
|
|
1090
|
-
sentence that should be tagged, and the outcome(s) of the predicate.
|
|
1416
|
+
A predicate function accepts a Sentence object, the current position in the
|
|
1417
|
+
sentence that should be tagged, and the outcome(s) of the predicate.
|
|
1091
1418
|
An example of a predicate that checks the category of the current word:
|
|
1092
1419
|
```javascript
|
|
1093
|
-
function next_tag_is(
|
|
1094
|
-
if (i <
|
|
1095
|
-
return(
|
|
1420
|
+
function next_tag_is(sentence, i, parameter) {
|
|
1421
|
+
if (i < sentence.taggedWords.length - 1) {
|
|
1422
|
+
return(sentence.taggedWords[i + 1][1] === parameter);
|
|
1096
1423
|
}
|
|
1097
1424
|
else {
|
|
1098
1425
|
return(false);
|
|
@@ -1100,7 +1427,7 @@ function next_tag_is(tagged_sentence, i, parameter) {
|
|
|
1100
1427
|
}
|
|
1101
1428
|
```
|
|
1102
1429
|
|
|
1103
|
-
A values function for a parameter returns an array all possible parameter
|
|
1430
|
+
A values function for a parameter returns an array all possible parameter
|
|
1104
1431
|
values given a location in a tagged sentence.
|
|
1105
1432
|
```javascript
|
|
1106
1433
|
function nextTagParameterValues(sentence, i) {
|
|
@@ -1112,15 +1439,11 @@ function nextTagParameterValues(sentence, i) {
|
|
|
1112
1439
|
}
|
|
1113
1440
|
}
|
|
1114
1441
|
```
|
|
1115
|
-
Please note that these functions work with a different data type. Here, a
|
|
1116
|
-
sentence is an array of tokens and tokens are maps that have at least a
|
|
1117
|
-
token (word) and a tag.
|
|
1118
|
-
|
|
1119
1442
|
|
|
1120
1443
|
### Training
|
|
1121
|
-
The trainer allows to learn a new set of transformation rules from a corpus.
|
|
1122
|
-
It takes as input a tagged corpus and a set of rule templates. The algorithm
|
|
1123
|
-
generates positive rules (rules that apply at some location in the corpus)
|
|
1444
|
+
The trainer allows to learn a new set of transformation rules from a corpus.
|
|
1445
|
+
It takes as input a tagged corpus and a set of rule templates. The algorithm
|
|
1446
|
+
generates positive rules (rules that apply at some location in the corpus)
|
|
1124
1447
|
from the templates and iteratively extends and optimises the rule set.
|
|
1125
1448
|
|
|
1126
1449
|
First, a corpus should be loaded. Currently, the format of Brown corpus is supported. Then a lexicon can be created from the corpus. The lexicon is needed for tagging the sentences before the learning algorithm is applied.
|
|
@@ -1130,8 +1453,8 @@ var text = fs.readFileSync(brownCorpusFile, 'utf8');
|
|
|
1130
1453
|
var corpus = new natural.Corpus(text, 1);
|
|
1131
1454
|
var lexicon = corpus.buildLexicon();
|
|
1132
1455
|
```
|
|
1133
|
-
The next step is to create a set of rule templates from which the learning
|
|
1134
|
-
algorithm can generate transformation rules. Rule templates are defined in
|
|
1456
|
+
The next step is to create a set of rule templates from which the learning
|
|
1457
|
+
algorithm can generate transformation rules. Rule templates are defined in
|
|
1135
1458
|
<code>PredicateMapping.js</code>.
|
|
1136
1459
|
```javascript
|
|
1137
1460
|
var natural require('natural');
|
|
@@ -1152,17 +1475,17 @@ var Tester = require('natural.BrillPOSTrainer');
|
|
|
1152
1475
|
var trainer = new Trainer(/* optional threshold */);
|
|
1153
1476
|
var ruleSet = trainer.train(corpus, templates, lexicon);
|
|
1154
1477
|
```
|
|
1155
|
-
A threshold value can be passed to constructor. Transformation rules with
|
|
1478
|
+
A threshold value can be passed to constructor. Transformation rules with
|
|
1156
1479
|
a score below the threshold are removed after training.
|
|
1157
|
-
The train method returns a set of transformation rules that can be used to
|
|
1158
|
-
create a POS tagger as usual. Also you can output the rule set in the right
|
|
1480
|
+
The train method returns a set of transformation rules that can be used to
|
|
1481
|
+
create a POS tagger as usual. Also you can output the rule set in the right
|
|
1159
1482
|
format for later usage.
|
|
1160
1483
|
```javascript
|
|
1161
1484
|
console.log(ruleSet.prettyPrint());
|
|
1162
1485
|
```
|
|
1163
1486
|
|
|
1164
1487
|
### Testing
|
|
1165
|
-
Now we can apply the lexicon and rule set to a test set.
|
|
1488
|
+
Now we can apply the lexicon and rule set to a test set.
|
|
1166
1489
|
```javascript
|
|
1167
1490
|
var tester = new natural.BrillPOSTester();
|
|
1168
1491
|
var tagger = new natural.BrillPOSTagger(lexicon, ruleSet);
|