natural 0.1.28 → 0.4.0
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/.editorconfig +7 -0
- package/.npmignore +4 -11
- package/README.md +190 -50
- package/bayes_classifier.json +1 -0
- package/lib/natural/analyzers/sentence_analyzer.js +8 -5
- package/lib/natural/brill_pos_tagger/data/Dutch/README.txt +2 -0
- package/lib/natural/brill_pos_tagger/data/Dutch/brill_CONTEXTRULES.jg +285 -0
- package/lib/natural/brill_pos_tagger/data/Dutch/brill_LEXICON.jg +11699 -0
- package/lib/natural/brill_pos_tagger/data/English/README.txt +8 -0
- package/lib/natural/brill_pos_tagger/data/English/lexicon_from_posjs.json +297827 -0
- package/lib/natural/brill_pos_tagger/data/English/tr_from_brill_paper.txt +10 -0
- package/lib/natural/brill_pos_tagger/data/English/tr_from_posjs.txt +18 -0
- package/lib/natural/brill_pos_tagger/lib/Brill_POS_Tagger.js +136 -0
- package/lib/natural/brill_pos_tagger/lib/Predicate.js +410 -0
- package/lib/natural/brill_pos_tagger/lib/TF_Parser.js +717 -0
- package/lib/natural/brill_pos_tagger/lib/TF_Parser.pegjs +55 -0
- package/lib/natural/brill_pos_tagger/lib/TransformationRule.js +49 -0
- package/lib/natural/classifiers/bayes_classifier.js +6 -5
- package/lib/natural/classifiers/classifier.js +3 -2
- package/lib/natural/classifiers/logistic_regression_classifier.js +9 -5
- package/lib/natural/distance/dice_coefficient.js +22 -12
- package/lib/natural/distance/jaro-winkler_distance.js +13 -8
- package/lib/natural/index.js +6 -0
- package/lib/natural/inflectors/present_verb_inflector.js +1 -0
- package/lib/natural/ngrams/ngrams.js +6 -0
- package/lib/natural/normalizers/normalizer_ja.js +26 -8
- package/lib/natural/phonetics/double_metaphone.js +9 -4
- package/lib/natural/phonetics/metaphone.js +4 -0
- package/lib/natural/phonetics/soundex.js +11 -7
- package/lib/natural/spellcheck/spellcheck.js +80 -0
- package/lib/natural/stemmers/porter_stemmer.js +90 -62
- package/lib/natural/stemmers/porter_stemmer_fr.js +8 -3
- package/lib/natural/stemmers/porter_stemmer_pt.js +302 -0
- package/lib/natural/stemmers/stemmer.js +31 -6
- package/lib/natural/stemmers/stemmer_pt.js +65 -0
- package/lib/natural/stemmers/token.js +163 -0
- package/lib/natural/tfidf/tfidf.js +49 -18
- package/lib/natural/tokenizers/regexp_tokenizer.js +3 -3
- package/{examples/inflection/noun.js → lib/natural/tokenizers/sentence_tokenizer.js} +14 -10
- package/lib/natural/tokenizers/tokenizer_case.js +58 -0
- package/lib/natural/util/bag.js +1 -0
- package/lib/natural/util/stopwords_pt.js +136 -0
- package/lib/natural/wordnet/wordnet.js +2 -2
- package/lib/natural/wordnet/wordnet_file.js +1 -1
- package/lr_classifier.json +1 -0
- package/package.json +7 -4
- package/package.json~ +66 -0
- package/benchmarks/index.js +0 -32
- package/benchmarks/metaphone.js +0 -27
- package/benchmarks/soundex.js +0 -27
- package/examples/classification/basic.js +0 -35
- package/examples/classification/recall.js +0 -28
- package/examples/classification/store.js +0 -37
- package/examples/inflection/count.js +0 -35
- package/examples/inflection/noun_attach.js +0 -33
- package/examples/phonetics/compare.js +0 -39
- package/examples/phonetics/sounds_like.js +0 -40
- package/examples/phonetics/tokenize_and_phoneticize.js +0 -54
- package/examples/stemming/stem_corpus.js +0 -29
- package/examples/stemming/stem_word.js +0 -26
- package/examples/tfidf/array_example.js +0 -34
- package/examples/tfidf/multiple_terms.js +0 -33
- package/examples/tfidf/tfidf_example.js +0 -44
- package/io_spec/test_data/tfidf/one +0 -1
- package/io_spec/test_data/tfidf/two +0 -1
- package/io_spec/tfidf_spec.js +0 -50
- package/io_spec/wordnet_spec.js +0 -81
- package/spec/aggressive_tokenizer_es_spec.js +0 -36
- package/spec/aggressive_tokenizer_fr_spec.js +0 -101
- package/spec/aggressive_tokenizer_nl_spec.js +0 -36
- package/spec/aggressive_tokenizer_pt_spec.js +0 -56
- package/spec/aggressive_tokenizer_spec.js +0 -56
- package/spec/bayes_classifier_spec.js +0 -173
- package/spec/classifier_spec.js +0 -91
- package/spec/count_inflector_fr_spec.js +0 -44
- package/spec/count_inflector_spec.js +0 -73
- package/spec/dice_coefficient_spec.js +0 -26
- package/spec/double_metaphone_spec.js +0 -743
- package/spec/jaro-winkler_spec.js +0 -53
- package/spec/lancaster_stemmer_spec.js +0 -73
- package/spec/levenshtein_spec.js +0 -66
- package/spec/logistic_regression_classifier_spec.js +0 -122
- package/spec/longest_path_tree_spec.js +0 -102
- package/spec/metaphone_spec.js +0 -247
- package/spec/ngram_spec.js +0 -130
- package/spec/ngram_zh_spec.js +0 -122
- package/spec/normalizer_ja_spec.js +0 -154
- package/spec/normalizer_no_spec.js +0 -111
- package/spec/normalizer_spec.js +0 -118
- package/spec/noun_inflector_fr_spec.js +0 -476
- package/spec/noun_inflector_ja_spec.js +0 -112
- package/spec/noun_inflector_spec.js +0 -270
- package/spec/porter_stemmer_fr_spec.js +0 -101
- package/spec/porter_stemmer_it_spec.js +0 -44
- package/spec/porter_stemmer_no_spec.js +0 -143
- package/spec/porter_stemmer_ru_spec.js +0 -63
- package/spec/porter_stemmer_spec.js +0 -137
- package/spec/present_verb_inflector_spec.js +0 -125
- package/spec/sentence_analyzer_spec.js +0 -29
- package/spec/shortest_path_tree_spec.js +0 -132
- package/spec/soundex_spec.js +0 -154
- package/spec/stemmer_ja_spec.js +0 -66
- package/spec/test_data/snowball_fr.txt +0 -20402
- package/spec/test_data/snowball_it.txt +0 -35482
- package/spec/test_data/snowball_no.txt +0 -20628
- package/spec/test_data/tfdif_testcorpus.txt +0 -7
- package/spec/test_data/tfidf_document1.txt +0 -1
- package/spec/test_data/tfidf_document2.txt +0 -1
- package/spec/test_data/tfidf_document3.txt +0 -1
- package/spec/test_data/tfidf_document4.txt +0 -1
- package/spec/test_data/tfidf_teststopwords.txt +0 -1
- package/spec/test_data/wordnet_mini.sql +0 -95
- package/spec/tfidf_spec.js +0 -198
- package/spec/tokenizer_ja_spec.js +0 -58
- package/spec/transliterator_ja_spec.js +0 -103
- package/spec/treebank_word_tokenizer_spec.js +0 -36
- package/spec/trie_spec.js +0 -206
package/.editorconfig
ADDED
package/.npmignore
CHANGED
package/README.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
natural
|
|
2
2
|
=======
|
|
3
3
|
|
|
4
|
+
[](https://www.npmjs.com/package/natural)
|
|
4
5
|
[](https://travis-ci.org/NaturalNode/natural)
|
|
5
6
|
|
|
6
7
|
"Natural" is a general natural language facility for nodejs. Tokenizing,
|
|
@@ -18,8 +19,30 @@ will be in order. Thanks to Polyakov Vladimir, Russian stemming has been added!,
|
|
|
18
19
|
|
|
19
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) 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.
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
### TABLE OF CONTENTS
|
|
23
|
+
|
|
24
|
+
* [Installation](#installation)
|
|
25
|
+
* [Tokenizers](#tokenizers)
|
|
26
|
+
* [String Distance](#string-distance)
|
|
27
|
+
* [Stemmers](#stemmers)
|
|
28
|
+
* [Classifiers](#classifiers)
|
|
29
|
+
* [Phonetics](#phonetics)
|
|
30
|
+
* [Inflectors](#inflectors)
|
|
31
|
+
* [N-Grams](#n-grams)
|
|
32
|
+
* [tf-idf](#tf-idf)
|
|
33
|
+
* [Tries](#tries)
|
|
34
|
+
* [EdgeWeightedDigraph](#edgeweighteddigraph)
|
|
35
|
+
* [ShortestPathTree](#shortestpathtree)
|
|
36
|
+
* [LongestPathTree](#longestpathtree)
|
|
37
|
+
* [WordNet](#wordnet)
|
|
38
|
+
* [Spellcheck](#spellcheck)
|
|
39
|
+
* [POS Tagger](#pos-tagger)
|
|
40
|
+
* [Acknowledgements/references](#acknowledgements-and-references)
|
|
41
|
+
* [Development](#development)
|
|
42
|
+
* [License](#license)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
## Installation
|
|
23
46
|
|
|
24
47
|
If you're just looking to use natural without your own node application,
|
|
25
48
|
you can install via NPM like so:
|
|
@@ -29,8 +52,7 @@ you can install via NPM like so:
|
|
|
29
52
|
If you're interested in contributing to natural, or just hacking on it, then by all
|
|
30
53
|
means fork away!
|
|
31
54
|
|
|
32
|
-
Tokenizers
|
|
33
|
-
----------
|
|
55
|
+
## Tokenizers
|
|
34
56
|
|
|
35
57
|
Word, Regexp, and [Treebank tokenizers](http://www.cis.upenn.edu/~treebank/tokenization.html) are provided for breaking text up into
|
|
36
58
|
arrays of tokens:
|
|
@@ -58,8 +80,8 @@ console.log(tokenizer.tokenize("my dog hasn't any fleas."));
|
|
|
58
80
|
// [ 'my', 'dog', 'hasn', '\'', 't', 'any', 'fleas', '.' ]
|
|
59
81
|
```
|
|
60
82
|
|
|
61
|
-
String Distance
|
|
62
|
-
|
|
83
|
+
## String Distance
|
|
84
|
+
|
|
63
85
|
Natural provides an implementation of the [Jaro–Winkler](http://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance) string distance measuring algorithm.
|
|
64
86
|
This will return a number between 0 and 1 which tells how closely the strings match (0 = not at all, 1 = exact match):
|
|
65
87
|
|
|
@@ -122,8 +144,7 @@ Output:
|
|
|
122
144
|
0
|
|
123
145
|
```
|
|
124
146
|
|
|
125
|
-
Stemmers
|
|
126
|
-
--------
|
|
147
|
+
## Stemmers
|
|
127
148
|
|
|
128
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.
|
|
129
150
|
|
|
@@ -167,8 +188,7 @@ console.log("i am waking up to the sounds of chainsaws".tokenizeAndStem());
|
|
|
167
188
|
console.log("chainsaws".stem());
|
|
168
189
|
```
|
|
169
190
|
|
|
170
|
-
Classifiers
|
|
171
|
-
----------------------
|
|
191
|
+
## Classifiers
|
|
172
192
|
|
|
173
193
|
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).
|
|
174
194
|
The following examples use the BayesClassifier class, but the
|
|
@@ -184,7 +204,7 @@ tokenize and stem the text.
|
|
|
184
204
|
|
|
185
205
|
```javascript
|
|
186
206
|
classifier.addDocument('i am long qqqq', 'buy');
|
|
187
|
-
classifier.addDocument('buy the q'
|
|
207
|
+
classifier.addDocument('buy the q\'s', 'buy');
|
|
188
208
|
classifier.addDocument('short gold', 'sell');
|
|
189
209
|
classifier.addDocument('sell gold', 'sell');
|
|
190
210
|
|
|
@@ -208,8 +228,8 @@ You have access to the set of matched classes and the associated value from the
|
|
|
208
228
|
Outputs:
|
|
209
229
|
|
|
210
230
|
```javascript
|
|
211
|
-
[ { label: '
|
|
212
|
-
{ label: '
|
|
231
|
+
[ { label: 'buy', value: 0.39999999999999997 },
|
|
232
|
+
{ label: 'sell', value: 0.19999999999999998 } ]
|
|
213
233
|
```
|
|
214
234
|
|
|
215
235
|
From this:
|
|
@@ -234,7 +254,8 @@ The training process can be monitored by subscribing to the event `trainedWithDo
|
|
|
234
254
|
* total: 23 // There are 23 total documents being trained against
|
|
235
255
|
* index: 12 // The index/number of the document that's just been trained against
|
|
236
256
|
* doc: {...} // The document that has just been indexed
|
|
237
|
-
|
|
257
|
+
* }
|
|
258
|
+
*/
|
|
238
259
|
});
|
|
239
260
|
|
|
240
261
|
A classifier can also be persisted and recalled so you can reuse a training
|
|
@@ -268,8 +289,7 @@ var restoredClassifier = natural.BayesClassifier.restore(JSON.parse(raw));
|
|
|
268
289
|
console.log(restoredClassifier.classify('i should sell that'));
|
|
269
290
|
```
|
|
270
291
|
|
|
271
|
-
Phonetics
|
|
272
|
-
---------
|
|
292
|
+
## Phonetics
|
|
273
293
|
|
|
274
294
|
Phonetic matching (sounds-like) matching can be done with the [SoundEx](http://en.wikipedia.org/wiki/Soundex),
|
|
275
295
|
[Metaphone](http://en.wikipedia.org/wiki/Metaphone) or [DoubleMetaphone](http://en.wikipedia.org/wiki/Metaphone#Double_Metaphone) algorithms
|
|
@@ -356,8 +376,7 @@ if(wordA.soundsLike(wordB))
|
|
|
356
376
|
console.log('phonetics'.phonetics());
|
|
357
377
|
```
|
|
358
378
|
|
|
359
|
-
Inflectors
|
|
360
|
-
----------
|
|
379
|
+
## Inflectors
|
|
361
380
|
|
|
362
381
|
### Nouns
|
|
363
382
|
|
|
@@ -442,8 +461,7 @@ console.log('walks'.pluralizePresentVerb());
|
|
|
442
461
|
```
|
|
443
462
|
|
|
444
463
|
|
|
445
|
-
N-Grams
|
|
446
|
-
-------
|
|
464
|
+
## N-Grams
|
|
447
465
|
|
|
448
466
|
n-grams can be obtained for either arrays or strings (which will be tokenized
|
|
449
467
|
for you):
|
|
@@ -534,8 +552,7 @@ console.log(NGramsZH.ngrams(['一', '个', '中', '文', '测',
|
|
|
534
552
|
'试'], 4));
|
|
535
553
|
```
|
|
536
554
|
|
|
537
|
-
tf-idf
|
|
538
|
-
-----
|
|
555
|
+
## tf-idf
|
|
539
556
|
|
|
540
557
|
[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
|
|
541
558
|
document relative to a corpus. The following example will add four documents to
|
|
@@ -597,7 +614,7 @@ tfidf.addFileSync('data_files/two.txt');
|
|
|
597
614
|
|
|
598
615
|
Multiple terms can be measured as well, with their weights being added into
|
|
599
616
|
a single measure value. The following example determines that the last document
|
|
600
|
-
is the most
|
|
617
|
+
is the most relevant to the words "node" and "ruby".
|
|
601
618
|
|
|
602
619
|
```javascript
|
|
603
620
|
var natural = require('natural'),
|
|
@@ -650,7 +667,7 @@ tfidf.listTerms(0 /*document index*/).forEach(function(item) {
|
|
|
650
667
|
});
|
|
651
668
|
```
|
|
652
669
|
|
|
653
|
-
A TfIdf instance can also be serialized and
|
|
670
|
+
A TfIdf instance can also be serialized and deserialized for save and recall.
|
|
654
671
|
|
|
655
672
|
```javascript
|
|
656
673
|
var tfidf = new TfIdf();
|
|
@@ -663,12 +680,11 @@ var s = JSON.stringify(tfidf);
|
|
|
663
680
|
var tfidf = new TfIdf(JSON.parse(s));
|
|
664
681
|
```
|
|
665
682
|
|
|
666
|
-
Tries
|
|
667
|
-
-----
|
|
683
|
+
## Tries
|
|
668
684
|
|
|
669
685
|
Tries are a very efficient data structure used for prefix-based searches.
|
|
670
|
-
Natural comes packaged with a basic Trie implementation
|
|
671
|
-
|
|
686
|
+
Natural comes packaged with a basic Trie implementation which can support match collection along a path,
|
|
687
|
+
existence search and prefix search.
|
|
672
688
|
|
|
673
689
|
### Building The Trie
|
|
674
690
|
|
|
@@ -741,9 +757,9 @@ ciTrie.contains("TEsT"); // true
|
|
|
741
757
|
```
|
|
742
758
|
In the case of the searches which return strings, all strings returned will be in lower case if you are in case-_in_sensitive mode.
|
|
743
759
|
|
|
744
|
-
EdgeWeightedDigraph
|
|
745
|
-
|
|
746
|
-
EdgeWeightedDigraph represents a digraph, you can add an edge, get the number
|
|
760
|
+
## EdgeWeightedDigraph
|
|
761
|
+
|
|
762
|
+
EdgeWeightedDigraph represents a digraph, you can add an edge, get the number vertexes, edges, get all edges and use toString to print the Digraph.
|
|
747
763
|
|
|
748
764
|
initialize a digraph:
|
|
749
765
|
|
|
@@ -759,7 +775,7 @@ digraph.add(6,4,0.93);
|
|
|
759
775
|
```
|
|
760
776
|
the api used is: add(from, to, weight).
|
|
761
777
|
|
|
762
|
-
get the number of
|
|
778
|
+
get the number of vertexes:
|
|
763
779
|
|
|
764
780
|
```javascript
|
|
765
781
|
console.log(digraph.v());
|
|
@@ -775,8 +791,7 @@ you will get 5.
|
|
|
775
791
|
|
|
776
792
|
|
|
777
793
|
|
|
778
|
-
ShortestPathTree
|
|
779
|
-
----------------
|
|
794
|
+
## ShortestPathTree
|
|
780
795
|
|
|
781
796
|
ShortestPathTree represents a data type for solving the single-source shortest paths problem in
|
|
782
797
|
edge-weighted directed acyclic graphs (DAGs).
|
|
@@ -815,7 +830,7 @@ false
|
|
|
815
830
|
```
|
|
816
831
|
|
|
817
832
|
### pathTo(vertex)
|
|
818
|
-
this will
|
|
833
|
+
this will return a shortest path:
|
|
819
834
|
|
|
820
835
|
```javascript
|
|
821
836
|
console.log(spt.pathTo(4));
|
|
@@ -827,8 +842,7 @@ output will be:
|
|
|
827
842
|
[5, 4]
|
|
828
843
|
```
|
|
829
844
|
|
|
830
|
-
LongestPathTree
|
|
831
|
-
----------------
|
|
845
|
+
## LongestPathTree
|
|
832
846
|
|
|
833
847
|
LongestPathTree represents a data type for solving the single-source shortest paths problem in
|
|
834
848
|
edge-weighted directed acyclic graphs (DAGs).
|
|
@@ -867,7 +881,7 @@ false
|
|
|
867
881
|
```
|
|
868
882
|
|
|
869
883
|
### pathTo(vertex)
|
|
870
|
-
this will
|
|
884
|
+
this will return a shortest path:
|
|
871
885
|
|
|
872
886
|
```javascript
|
|
873
887
|
console.log(spt.pathTo(4));
|
|
@@ -879,21 +893,18 @@ output will be:
|
|
|
879
893
|
[5, 1, 3, 6, 4]
|
|
880
894
|
```
|
|
881
895
|
|
|
882
|
-
WordNet
|
|
883
|
-
-------
|
|
896
|
+
## WordNet
|
|
884
897
|
|
|
885
898
|
One of the newest and most experimental features in natural is WordNet integration. Here's an
|
|
886
899
|
example of using natural to look up definitions of the word node. To use the WordNet module,
|
|
887
|
-
first install the WordNet database files using
|
|
900
|
+
first install the WordNet database files using [wordnet-db](https://github.com/moos/wordnet-db):
|
|
888
901
|
|
|
889
|
-
npm install
|
|
890
|
-
|
|
891
|
-
(For node < v0.6, please use 'npm install WNdb@3.0.0')
|
|
902
|
+
npm install wordnet-db
|
|
892
903
|
|
|
893
904
|
Keep in mind that the WordNet integration is to be considered experimental at this point,
|
|
894
|
-
and not production-ready. The API is also subject to change.
|
|
905
|
+
and not production-ready. The API is also subject to change. For an implementation with vastly increased performance, as well as a command-line interface, see [wordpos](https://github.com/moos/wordpos).
|
|
895
906
|
|
|
896
|
-
Here's an example of looking up definitions for the word
|
|
907
|
+
Here's an example of looking up definitions for the word "node".
|
|
897
908
|
|
|
898
909
|
```javascript
|
|
899
910
|
var wordnet = new natural.WordNet();
|
|
@@ -935,8 +946,138 @@ As of v0.1.11, WordNet data files are no longer automatically downloaded.
|
|
|
935
946
|
|
|
936
947
|
Princeton University "About WordNet." WordNet. Princeton University. 2010. <http://wordnet.princeton.edu>
|
|
937
948
|
|
|
938
|
-
|
|
939
|
-
|
|
949
|
+
## Spellcheck
|
|
950
|
+
|
|
951
|
+
A probabilistic spellchecker based on http://norvig.com/spell-correct.html
|
|
952
|
+
|
|
953
|
+
This is best constructed with an array of tokens from a corpus, but a simple list of words from a dictionary will work.
|
|
954
|
+
|
|
955
|
+
```javascript
|
|
956
|
+
var corpus = ['something', 'soothing'];
|
|
957
|
+
var spellcheck = new Spellcheck(corpus);
|
|
958
|
+
```
|
|
959
|
+
|
|
960
|
+
It uses the trie datastructure for fast boolean lookup of a word
|
|
961
|
+
|
|
962
|
+
```javascript
|
|
963
|
+
spellcheck.isCorrect('cat'); // false
|
|
964
|
+
```
|
|
965
|
+
|
|
966
|
+
It suggests corrections (sorted by probability in descending order) that are up to a maximum edit distance away from the input word. According to Norvig, a max distance of 1 will cover 80% to 95% of spelling mistakes. After a distance of 2, it becomes very slow.
|
|
967
|
+
|
|
968
|
+
```javascript
|
|
969
|
+
spellcheck.getCorrections('soemthing', 1); // ['something']
|
|
970
|
+
spellcheck.getCorrections('soemthing', 2); // ['something', 'soothing']
|
|
971
|
+
```
|
|
972
|
+
|
|
973
|
+
## POS Tagger
|
|
974
|
+
|
|
975
|
+
This is a part-of-speech tagger based on Eric Brill's transformational
|
|
976
|
+
algorithm. Transformation rules are specified in external files.
|
|
977
|
+
|
|
978
|
+
### Usage
|
|
979
|
+
```javascript
|
|
980
|
+
var Tagger = require("./lib/natural").BrillPOSTagger;
|
|
981
|
+
|
|
982
|
+
var base_folder = "some_path/lib/natural/brill_pos_tagger";
|
|
983
|
+
var rules_file = base_folder + "/data/tr_from_posjs.txt";
|
|
984
|
+
var lexicon_file = base_folder + "/data/lexicon_from_posjs.json";
|
|
985
|
+
var default_category = 'N';
|
|
986
|
+
|
|
987
|
+
var tagger = new Tagger(lexicon_file, rules_file, default_category, function(error) {
|
|
988
|
+
if (error) {
|
|
989
|
+
console.log(error);
|
|
990
|
+
}
|
|
991
|
+
else {
|
|
992
|
+
var sentence = ["I", "see", "the", "man", "with", "the", "telescope"];
|
|
993
|
+
console.log(JSON.stringify(tagger.tag(sentence)));
|
|
994
|
+
}
|
|
995
|
+
});
|
|
996
|
+
```
|
|
997
|
+
|
|
998
|
+
### Lexicon
|
|
999
|
+
The lexicon is either a JSON file that has the following structure:
|
|
1000
|
+
```javascript
|
|
1001
|
+
{
|
|
1002
|
+
"word1": ["cat1"],
|
|
1003
|
+
"word2": ["cat2", "cat3"],
|
|
1004
|
+
...
|
|
1005
|
+
}
|
|
1006
|
+
```
|
|
1007
|
+
or a text file:
|
|
1008
|
+
```
|
|
1009
|
+
word1 cat1 cat2
|
|
1010
|
+
word2 cat3
|
|
1011
|
+
...
|
|
1012
|
+
```
|
|
1013
|
+
Words may have multiple categories in the lexicon file. The tagger uses only
|
|
1014
|
+
the first category specified.
|
|
1015
|
+
|
|
1016
|
+
### Specifying transformation rules
|
|
1017
|
+
Transformation rules are specified as follows:
|
|
1018
|
+
```
|
|
1019
|
+
OLD_CAT NEW_CAT PREDICATE PARAMETER
|
|
1020
|
+
```
|
|
1021
|
+
This means that if the category of the current position is OLD_CAT and the predicate is true, the category is replaced by NEW_CAT. The predicate
|
|
1022
|
+
may use the parameter in different ways: sometimes the parameter is used for
|
|
1023
|
+
specifying the outcome of the predicate:
|
|
1024
|
+
```
|
|
1025
|
+
NN CD CURRENT-WORD-IS-NUMBER YES
|
|
1026
|
+
```
|
|
1027
|
+
This means that if the outcome of predicate CURRENT-WORD-IS-NUMBER is YES, the
|
|
1028
|
+
category is replaced by <code>CD</code>.
|
|
1029
|
+
The parameter can also be used to check the category of a word in the sentence:
|
|
1030
|
+
```
|
|
1031
|
+
VBD NN PREV-TAG DT
|
|
1032
|
+
```
|
|
1033
|
+
Here the category of the previous word must be <code>DT</code> for the rule to be applied.
|
|
1034
|
+
|
|
1035
|
+
### Algorithm
|
|
1036
|
+
The tagger applies transformation rules that may change the category of words. The input sentence must be split into words which are assigned with categories. The tagged sentence is then 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:
|
|
1037
|
+
```javascript
|
|
1038
|
+
function(sentence) {
|
|
1039
|
+
var tagged_sentence = new Array(sentence.length);
|
|
1040
|
+
|
|
1041
|
+
// snip
|
|
1042
|
+
|
|
1043
|
+
// Apply transformation rules
|
|
1044
|
+
for (var i = 0, size = sentence.length; i < size; i++) {
|
|
1045
|
+
this.transformation_rules.forEach(function(rule) {
|
|
1046
|
+
rule.apply(tagged_sentence, i);
|
|
1047
|
+
});
|
|
1048
|
+
}
|
|
1049
|
+
return(tagged_sentence);
|
|
1050
|
+
}
|
|
1051
|
+
```
|
|
1052
|
+
|
|
1053
|
+
### Adding a predicate
|
|
1054
|
+
Predicates are defined in module <code>lib/Predicate.js</code>. In that file
|
|
1055
|
+
a function must be created that serves as predicate. A predicate accepts a
|
|
1056
|
+
tagged sentence, the current position in the sentence that should be tagged, and
|
|
1057
|
+
the
|
|
1058
|
+
outcome(s) of the predicate. An example of a predicate that checks the category of the current word:
|
|
1059
|
+
```javascript
|
|
1060
|
+
function current_word_is_tag(tagged_sentence, i, parameter) {
|
|
1061
|
+
return(tagged_sentence[i][0] === parameter);
|
|
1062
|
+
}
|
|
1063
|
+
```
|
|
1064
|
+
Some predicates accept two parameters. Next step is to map a keyword to this predicate so that it can be used in the transformation rules. The mapping is also defined in <code>lib/Predicate.js</code>:
|
|
1065
|
+
```javascript
|
|
1066
|
+
var predicates = {
|
|
1067
|
+
"CURRENT-WORD-IS-TAG": current_word_is_tag,
|
|
1068
|
+
"PREV-WORD-IS-CAP": prev_word_is_cap
|
|
1069
|
+
}
|
|
1070
|
+
```
|
|
1071
|
+
|
|
1072
|
+
### Acknowledgements and References
|
|
1073
|
+
* Part of speech tagger by Percy Wegmann, https://code.google.com/p/jspos/
|
|
1074
|
+
* Node.js version of jspos: https://github.com/neopunisher/pos-js
|
|
1075
|
+
* A simple rule-based part of speech tagger, Eric Brill, Published in: Proceeding ANLC '92 Proceedings of the third conference on Applied natural language processing, Pages 152-155. http://dl.acm.org/citation.cfm?id=974526
|
|
1076
|
+
|
|
1077
|
+
|
|
1078
|
+
|
|
1079
|
+
## Development
|
|
1080
|
+
|
|
940
1081
|
When developing, please:
|
|
941
1082
|
|
|
942
1083
|
+ Write unit tests
|
|
@@ -947,8 +1088,7 @@ The current configuration of the unit tests requires the following environment v
|
|
|
947
1088
|
export NODE_PATH=.
|
|
948
1089
|
|
|
949
1090
|
|
|
950
|
-
License
|
|
951
|
-
-------
|
|
1091
|
+
## License
|
|
952
1092
|
|
|
953
1093
|
Copyright (c) 2011, 2012 Chris Umbel, Rob Ellis, Russell Mull
|
|
954
1094
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"classifier":{"classFeatures":{"computing":{"0":2,"1":2,"2":2,"3":3,"4":2,"5":2},"literature":{"2":2,"6":4,"7":2,"8":2}},"classTotals":{"computing":4,"literature":4},"totalExamples":7,"smoothing":1},"docs":[{"label":"computing","text":["fix","box"]},{"label":"computing","text":["write","code"]},{"label":"computing","text":["nasti","script","code"]},{"label":"literature","text":["write","book"]},{"label":"literature","text":["read","book"]},{"label":"literature","text":["studi","book"]}],"features":{"fix":1,"box":1,"write":2,"code":2,"nasti":1,"script":1,"book":3,"read":1,"studi":1},"stemmer":{},"lastAdded":6,"events":{"domain":null,"_events":{},"_maxListeners":10}}
|
|
@@ -135,13 +135,16 @@ Sentences.prototype.toString = function() {
|
|
|
135
135
|
// This is quick and incomplete.
|
|
136
136
|
Sentences.prototype.type = function(callback) {
|
|
137
137
|
var callback = callback || false;
|
|
138
|
-
|
|
138
|
+
|
|
139
|
+
// Check for implicit you before popping a tag.
|
|
140
|
+
var implicitYou = this.implicitYou();
|
|
141
|
+
|
|
139
142
|
// FIXME - punct seems useless
|
|
140
143
|
var lastElement = this.posObj.punct();
|
|
141
144
|
lastElement = (lastElement.length != 0) ? lastElement.pop() : this.posObj.tags.pop();
|
|
142
|
-
|
|
145
|
+
|
|
143
146
|
if (lastElement.pos !== ".") {
|
|
144
|
-
if (
|
|
147
|
+
if (implicitYou) {
|
|
145
148
|
this.senType = "COMMAND";
|
|
146
149
|
} else if (_(["WDT","WP","WP$","WRB"]).contains(this.posObj.tags[0].pos)) {
|
|
147
150
|
// Sentences that start with: who, what where when why and how, then they are questions
|
|
@@ -158,8 +161,8 @@ Sentences.prototype.type = function(callback) {
|
|
|
158
161
|
} else {
|
|
159
162
|
switch(lastElement.token) {
|
|
160
163
|
case "?": this.senType = "INTERROGATIVE"; break;
|
|
161
|
-
case "!": this.senType = (
|
|
162
|
-
case ".": this.senType = (
|
|
164
|
+
case "!": this.senType = (implicitYou) ? "COMMAND":"EXCLAMATORY"; break;
|
|
165
|
+
case ".": this.senType = (implicitYou) ? "COMMAND":"DECLARATIVE"; break;
|
|
163
166
|
}
|
|
164
167
|
}
|
|
165
168
|
|