natural 0.5.6 → 0.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.dockerignore +2 -0
- package/.idea/misc.xml +6 -0
- package/.idea/modules.xml +8 -0
- package/.idea/natural.iml +12 -0
- package/.idea/vcs.xml +6 -0
- package/.idea/workspace.xml +511 -0
- package/.travis.yml +8 -1
- package/README.md +331 -40
- package/bayes_classifier.json +1 -1
- package/classifier.json +418 -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/TransformationRule.js +10 -11
- package/lib/natural/classifiers/classifier.js +5 -3
- 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 +2 -2
- package/lib/natural/index.js +21 -2
- package/lib/natural/inflectors/noun_inflector.js +5 -3
- package/lib/natural/ngrams/ngrams.js +83 -25
- 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/data/kata-dasar.json +29935 -0
- package/lib/natural/stemmers/indonesian/prefix_rules.js +10 -9
- package/lib/natural/stemmers/indonesian/stemmer_id.js +16 -15
- package/lib/natural/stemmers/indonesian/suffix_rules.js +2 -2
- 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/stemmer_es.js +18 -12
- package/lib/natural/stemmers/stemmer_nl.js +64 -0
- package/lib/natural/tfidf/tfidf.js +27 -4
- package/lib/natural/tokenizers/aggressive_tokenizer_sv.js +1 -1
- 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 +24 -4
- package/lib/natural/tokenizers/sentence_tokenizer.js +1 -1
- package/lib/natural/wordnet/wordnet_file.js +7 -1
- package/lr_classifier.json +1 -1
- package/package.json +35 -23
- package/.npmignore +0 -4
- package/.vscode/temp.sql +0 -0
- package/Makefile +0 -38
- package/data/kata-dasar.txt +0 -29933
- package/package-lock.json +0 -79
- package/tests/stemmer_id_test.js +0 -361
|
@@ -35,8 +35,6 @@ function distance(s1, s2) {
|
|
|
35
35
|
return 0;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
s1 = s1.toLowerCase(), s2 = s2.toLowerCase();
|
|
39
|
-
|
|
40
38
|
var matchWindow = (Math.floor(Math.max(s1.length, s2.length) / 2.0)) - 1;
|
|
41
39
|
var matches1 = new Array(s1.length);
|
|
42
40
|
var matches2 = new Array(s2.length);
|
|
@@ -83,6 +81,7 @@ function distance(s1, s2) {
|
|
|
83
81
|
k++;
|
|
84
82
|
}
|
|
85
83
|
if (s1[i] !== s2[k]) { // if the characters don't match, increase transposition
|
|
84
|
+
// HtD: t is always less than the number of matches m, because transpositions are a subset of matches
|
|
86
85
|
t++;
|
|
87
86
|
}
|
|
88
87
|
k++; // iterate k index normally
|
|
@@ -91,7 +90,8 @@ function distance(s1, s2) {
|
|
|
91
90
|
// transpositions divided by 2
|
|
92
91
|
t = t / 2.0;
|
|
93
92
|
|
|
94
|
-
return ((m / s1.length) + (m / s2.length) + ((m - t) / m)) / 3.0;
|
|
93
|
+
return ((m / s1.length) + (m / s2.length) + ((m - t) / m)) / 3.0; // HtD: therefore, m - t > 0, and m - t < m
|
|
94
|
+
// HtD: => return value is between 0 and 1
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
// Computes the Winkler distance between two string -- intrepreted from:
|
|
@@ -99,19 +99,29 @@ function distance(s1, s2) {
|
|
|
99
99
|
// s1 is the first string to compare
|
|
100
100
|
// s2 is the second string to compare
|
|
101
101
|
// dj is the Jaro Distance (if you've already computed it), leave blank and the method handles it
|
|
102
|
-
|
|
102
|
+
// ignoreCase: if true strings are first converted to lower case before comparison
|
|
103
|
+
function JaroWinklerDistance(s1, s2, dj, ignoreCase) {
|
|
103
104
|
if (s1 === s2) {
|
|
104
105
|
return 1;
|
|
105
106
|
} else {
|
|
106
|
-
|
|
107
|
+
if (ignoreCase) {
|
|
108
|
+
s1 = s1.toLowerCase();
|
|
109
|
+
s2 = s2.toLowerCase();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
//console.log(news1);
|
|
113
|
+
//console.log(news2);
|
|
114
|
+
|
|
115
|
+
var jaro = (typeof(dj) === 'undefined') ? distance(s1, s2) : dj;
|
|
107
116
|
var p = 0.1; // default scaling factor
|
|
108
117
|
var l = 0 // length of the matching prefix
|
|
109
118
|
while(s1[l] === s2[l] && l < 4) {
|
|
110
119
|
l++;
|
|
111
120
|
}
|
|
112
121
|
|
|
122
|
+
// HtD: 1 - jaro >= 0
|
|
113
123
|
return jaro + l * p * (1 - jaro);
|
|
114
124
|
}
|
|
115
125
|
}
|
|
116
|
-
module.exports = JaroWinklerDistance;
|
|
117
126
|
|
|
127
|
+
module.exports = JaroWinklerDistance;
|
|
@@ -89,7 +89,7 @@ function getMinCostSubstring(distanceMatrix, source, target) {
|
|
|
89
89
|
* restricted: boolean (default: false)
|
|
90
90
|
*/
|
|
91
91
|
function DamerauLevenshteinDistance(source, target, options) {
|
|
92
|
-
var damLevOptions = _.
|
|
92
|
+
var damLevOptions = _.extend(
|
|
93
93
|
{ transposition_cost: 1, restricted: false },
|
|
94
94
|
options || {},
|
|
95
95
|
{ damerau: true }
|
|
@@ -98,7 +98,7 @@ function DamerauLevenshteinDistance(source, target, options) {
|
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
function LevenshteinDistance(source, target, options) {
|
|
101
|
-
var levOptions = _.
|
|
101
|
+
var levOptions = _.extend({}, options || {}, { damerau: false });
|
|
102
102
|
return levenshteinDistance(source, target, levOptions);
|
|
103
103
|
}
|
|
104
104
|
|
package/lib/natural/index.js
CHANGED
|
@@ -33,9 +33,12 @@ exports.PorterStemmerIt = require('./stemmers/porter_stemmer_it');
|
|
|
33
33
|
exports.PorterStemmerNo = require('./stemmers/porter_stemmer_no');
|
|
34
34
|
exports.PorterStemmerSv = require('./stemmers/porter_stemmer_sv');
|
|
35
35
|
exports.PorterStemmerPt = require('./stemmers/porter_stemmer_pt');
|
|
36
|
+
exports.PorterStemmerNl = require('./stemmers/porter_stemmer_nl');
|
|
36
37
|
exports.LancasterStemmer = require('./stemmers/lancaster_stemmer');
|
|
37
|
-
|
|
38
|
-
|
|
38
|
+
// StemmerFr and StemmerPl are not stemmers. A Polish stemmer is
|
|
39
|
+
// not available, and for French PorterStemmerFr should be used.
|
|
40
|
+
//exports.StemmerFr = require('./stemmers/stemmer_fr');
|
|
41
|
+
//exports.StemmerPl = require('./stemmers/stemmer_pl');
|
|
39
42
|
exports.StemmerJa = require('./stemmers/stemmer_ja');
|
|
40
43
|
exports.StemmerId = require('./stemmers/indonesian/stemmer_id');
|
|
41
44
|
exports.AggressiveTokenizerNl = require('./tokenizers/aggressive_tokenizer_nl');
|
|
@@ -48,9 +51,11 @@ exports.AggressiveTokenizerPl = require('./tokenizers/aggressive_tokenizer_pl');
|
|
|
48
51
|
exports.AggressiveTokenizerPt = require('./tokenizers/aggressive_tokenizer_pt');
|
|
49
52
|
exports.AggressiveTokenizerNo = require('./tokenizers/aggressive_tokenizer_no');
|
|
50
53
|
exports.AggressiveTokenizerSv = require('./tokenizers/aggressive_tokenizer_sv');
|
|
54
|
+
exports.AggressiveTokenizerVi = require('./tokenizers/aggressive_tokenizer_vi');
|
|
51
55
|
exports.AggressiveTokenizer = require('./tokenizers/aggressive_tokenizer');
|
|
52
56
|
exports.CaseTokenizer = require('./tokenizers/tokenizer_case');
|
|
53
57
|
exports.RegexpTokenizer = require('./tokenizers/regexp_tokenizer').RegexpTokenizer;
|
|
58
|
+
exports.OrthographyTokenizer = require('./tokenizers/regexp_tokenizer').OrthographyTokenizer;
|
|
54
59
|
exports.WordTokenizer = require('./tokenizers/regexp_tokenizer').WordTokenizer;
|
|
55
60
|
exports.WordPunctTokenizer = require('./tokenizers/regexp_tokenizer').WordPunctTokenizer;
|
|
56
61
|
exports.TreebankWordTokenizer = require('./tokenizers/treebank_word_tokenizer');
|
|
@@ -78,6 +83,7 @@ exports.JaroWinklerDistance = require('./distance/jaro-winkler_distance');
|
|
|
78
83
|
exports.LevenshteinDistance = require('./distance/levenshtein_distance').LevenshteinDistance;
|
|
79
84
|
exports.DamerauLevenshteinDistance = require('./distance/levenshtein_distance').DamerauLevenshteinDistance;
|
|
80
85
|
exports.DiceCoefficient = require('./distance/dice_coefficient');
|
|
86
|
+
exports.HammingDistance = require('./distance/hamming_distance');
|
|
81
87
|
exports.normalize = require('./normalizers/normalizer').normalize_tokens;
|
|
82
88
|
exports.normalize_ja = require('./normalizers/normalizer_ja').normalize_ja;
|
|
83
89
|
exports.removeDiacritics = require('./normalizers/remove_diacritics');
|
|
@@ -90,3 +96,16 @@ exports.RuleSet = require('./brill_pos_tagger/lib/RuleSet');
|
|
|
90
96
|
exports.RuleTemplates = require('./brill_pos_tagger/lib/RuleTemplates');
|
|
91
97
|
exports.RuleTemplate = require('./brill_pos_tagger/lib/RuleTemplate');
|
|
92
98
|
exports.Corpus = require('./brill_pos_tagger/lib/Corpus');
|
|
99
|
+
exports.MaxEntClassifier = require('./classifiers/maxent/Classifier');
|
|
100
|
+
exports.Context = require('./classifiers/maxent/Context');
|
|
101
|
+
exports.Feature = require('./classifiers/maxent/Feature');
|
|
102
|
+
exports.FeatureSet = require('./classifiers/maxent/FeatureSet');
|
|
103
|
+
exports.Sample = require('./classifiers/maxent/Sample');
|
|
104
|
+
exports.Element = require('./classifiers/maxent/Element');
|
|
105
|
+
exports.SE_Element = require('./classifiers/maxent/SimpleExample/SE_Element');
|
|
106
|
+
exports.Sentence = require('./brill_pos_tagger/lib/Sentence');
|
|
107
|
+
exports.GISScaler = require('./classifiers/maxent/GISScaler');
|
|
108
|
+
exports.POS_Element = require('./classifiers/maxent/POS/POS_Element');
|
|
109
|
+
exports.ME_Sentence = require('./classifiers/maxent/POS/ME_Sentence');
|
|
110
|
+
exports.ME_Corpus = require('./classifiers/maxent/POS/ME_Corpus');
|
|
111
|
+
exports.SentimentAnalyzer = require('./sentiment/SentimentAnalyzer');
|
|
@@ -38,7 +38,7 @@ function attach() {
|
|
|
38
38
|
|
|
39
39
|
var NounInflector = function() {
|
|
40
40
|
this.ambiguous = [
|
|
41
|
-
'bison', 'bream', 'carp', 'chassis', 'cod', 'corps', 'debris', 'deer',
|
|
41
|
+
'bison', 'bream', 'carp', 'chassis', 'christmas', 'cod', 'corps', 'debris', 'deer',
|
|
42
42
|
'diabetes', 'equipment', 'elk', 'fish', 'flounder', 'gallows', 'graffiti',
|
|
43
43
|
'headquarters', 'herpes', 'highjinks', 'homework', 'information',
|
|
44
44
|
'mackerel', 'mews', 'money', 'news', 'rice', 'rabies', 'salmon', 'series',
|
|
@@ -64,14 +64,16 @@ var NounInflector = function() {
|
|
|
64
64
|
this.addIrregular("ephemeris", "ephemerides");
|
|
65
65
|
this.addIrregular("cloth", "clothes");
|
|
66
66
|
this.addIrregular("hero", "heroes");
|
|
67
|
+
this.addIrregular("torso", "torsi");
|
|
67
68
|
|
|
68
69
|
// see if it is possible to unify the creation of both the singular and
|
|
69
70
|
// plural regexes or maybe even just have one list. with a complete list
|
|
70
71
|
// of rules it may only be possible for some regular forms, but worth a shot
|
|
72
|
+
this.pluralForms.regularForms.push([/([aeiou]y)$/i, '$1s']);
|
|
71
73
|
this.pluralForms.regularForms.push([/y$/i, 'ies']);
|
|
72
74
|
this.pluralForms.regularForms.push([/ife$/i, 'ives']);
|
|
73
75
|
this.pluralForms.regularForms.push([/(antenn|formul|nebul|vertebr|vit)a$/i, '$1ae']);
|
|
74
|
-
this.pluralForms.regularForms.push([/(octop|vir|radi|nucle|fung|cact|stimul)us$/i, '$1i']);
|
|
76
|
+
this.pluralForms.regularForms.push([/(octop|vir|radi|nucle|fung|cact|stimul|alumn|calcul|hippopotam|macrofung|phoet|syllab|troph)us$/i, '$1i']);
|
|
75
77
|
this.pluralForms.regularForms.push([/(buffal|tomat|tornad)o$/i, '$1oes']);
|
|
76
78
|
this.pluralForms.regularForms.push([/(sis)$/i, 'ses']);
|
|
77
79
|
this.pluralForms.regularForms.push([/(matr|vert|ind|cort)(ix|ex)$/i, '$1ices']);
|
|
@@ -83,7 +85,7 @@ var NounInflector = function() {
|
|
|
83
85
|
this.singularForms.regularForms.push([/([^v])ies$/i, '$1y']);
|
|
84
86
|
this.singularForms.regularForms.push([/ives$/i, 'ife']);
|
|
85
87
|
this.singularForms.regularForms.push([/(antenn|formul|nebul|vertebr|vit)ae$/i, '$1a']);
|
|
86
|
-
this.singularForms.regularForms.push([/(octop|vir|radi|nucle|fung|cact|stimul)(i)$/i, '$1us']);
|
|
88
|
+
this.singularForms.regularForms.push([/(octop|vir|radi|nucle|fung|cact|stimul|alumn|calcul|hippopotam|macrofung|phoet|syllab|troph)(i)$/i, '$1us']);
|
|
87
89
|
this.singularForms.regularForms.push([/(buffal|tomat|tornad)(oes)$/i, '$1o']);
|
|
88
90
|
this.singularForms.regularForms.push([/(analy|naly|synop|parenthe|diagno|the)ses$/i, '$1sis']);
|
|
89
91
|
this.singularForms.regularForms.push([/(vert|ind|cort)(ices)$/i, '$1ex']);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
Copyright (c) 2011, Rob Ellis, Chris Umbel
|
|
2
|
+
Copyright (c) 2011, 2018 Rob Ellis, Chris Umbel, Hugo W.L. ter Doest
|
|
3
3
|
|
|
4
4
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
5
|
of this software and associated documentation files (the "Software"), to deal
|
|
@@ -22,32 +22,57 @@ THE SOFTWARE.
|
|
|
22
22
|
|
|
23
23
|
var _ = require("underscore")._,
|
|
24
24
|
Tokenizer = require('../tokenizers/regexp_tokenizer').WordTokenizer,
|
|
25
|
-
tokenizer = new Tokenizer()
|
|
25
|
+
tokenizer = new Tokenizer(),
|
|
26
|
+
frequencies = {},
|
|
27
|
+
nrOfNgrams = 0;
|
|
26
28
|
|
|
27
29
|
exports.setTokenizer = function(t) {
|
|
28
30
|
if(!_.isFunction(t.tokenize))
|
|
29
31
|
throw new Error('Expected a valid Tokenizer');
|
|
30
32
|
tokenizer = t;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
exports.ngrams = function(sequence, n, startSymbol, endSymbol, stats) {
|
|
36
|
+
return ngrams(sequence, n, startSymbol, endSymbol, stats);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
exports.bigrams = function(sequence, startSymbol, endSymbol, stats) {
|
|
40
|
+
return ngrams(sequence, 2, startSymbol, endSymbol, stats);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
exports.trigrams = function(sequence, startSymbol, endSymbol, stats) {
|
|
44
|
+
return ngrams(sequence, 3, startSymbol, endSymbol, stats);
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
exports.multrigrams = function(sequence, n, startSymbol, endSymbol, stats) {
|
|
48
|
+
return ngrams(sequence, n, startSymbol, endSymbol, stats);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// Calculates a key (string) that can be used for a map
|
|
52
|
+
function arrayToKey(arr) {
|
|
53
|
+
result = "(";
|
|
54
|
+
arr.forEach(function(x) {
|
|
55
|
+
result += x + ", ";
|
|
56
|
+
});
|
|
57
|
+
result = result.substr(0, result.length - 2) + ")";
|
|
58
|
+
return result;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
// Updates the statistics for the new ngram
|
|
62
|
+
function countNgrams(ngram) {
|
|
63
|
+
nrOfNgrams++;
|
|
64
|
+
var key = arrayToKey(ngram);
|
|
65
|
+
if (!frequencies[key]) {
|
|
66
|
+
frequencies[key] = 0;
|
|
67
|
+
}
|
|
68
|
+
frequencies[key]++;
|
|
31
69
|
}
|
|
32
70
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
exports.bigrams = function(sequence, startSymbol, endSymbol) {
|
|
38
|
-
return ngrams(sequence, 2, startSymbol, endSymbol);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
exports.trigrams = function(sequence, startSymbol, endSymbol) {
|
|
42
|
-
return ngrams(sequence, 3, startSymbol, endSymbol);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
exports.multrigrams = function(sequence, n, startSymbol, endSymbol) {
|
|
46
|
-
return ngrams(sequence, n, startSymbol, endSymbol);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
var ngrams = function(sequence, n, startSymbol, endSymbol) {
|
|
71
|
+
// If stats is true, statistics will be returned
|
|
72
|
+
var ngrams = function(sequence, n, startSymbol, endSymbol, stats) {
|
|
50
73
|
var result = [];
|
|
74
|
+
frequencies = {};
|
|
75
|
+
nrOfNgrams = 0;
|
|
51
76
|
|
|
52
77
|
if (!_(sequence).isArray()) {
|
|
53
78
|
sequence = tokenizer.tokenize(sequence);
|
|
@@ -66,13 +91,21 @@ var ngrams = function(sequence, n, startSymbol, endSymbol) {
|
|
|
66
91
|
// Create the left padding
|
|
67
92
|
for(var p = n - 1 ; p > 0 ; p--) {
|
|
68
93
|
// Create a tuple of (p) start symbols and (n - p) words
|
|
69
|
-
|
|
94
|
+
var ngram = blanks.slice(0, p).concat(sequence.slice(0, n - p));
|
|
95
|
+
result.push(ngram);
|
|
96
|
+
if (stats) {
|
|
97
|
+
countNgrams(ngram);
|
|
98
|
+
}
|
|
70
99
|
}
|
|
71
100
|
}
|
|
72
101
|
|
|
73
102
|
// Build the complete ngrams
|
|
74
103
|
for (var i = 0; i < count; i++) {
|
|
75
|
-
|
|
104
|
+
var ngram = sequence.slice(i, i + n);
|
|
105
|
+
result.push(ngram);
|
|
106
|
+
if (stats) {
|
|
107
|
+
countNgrams(ngram);
|
|
108
|
+
}
|
|
76
109
|
}
|
|
77
110
|
|
|
78
111
|
// Check for right padding
|
|
@@ -86,10 +119,35 @@ var ngrams = function(sequence, n, startSymbol, endSymbol) {
|
|
|
86
119
|
// create the right padding
|
|
87
120
|
for(var p = n - 1 ; p > 0 ; p--) {
|
|
88
121
|
// Create a tuple of (p) start symbols and (n - p) words
|
|
89
|
-
|
|
122
|
+
var ngram = sequence.slice(sequence.length - p, sequence.length).concat(blanks.slice(0, n - p));
|
|
123
|
+
result.push(ngram);
|
|
124
|
+
if (stats) {
|
|
125
|
+
countNgrams(ngram);
|
|
126
|
+
}
|
|
90
127
|
}
|
|
91
128
|
}
|
|
92
129
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
130
|
+
if (stats) {
|
|
131
|
+
|
|
132
|
+
// Count frequencies
|
|
133
|
+
var Nr = {};
|
|
134
|
+
Object.keys(frequencies).forEach(function(key) {
|
|
135
|
+
if (!Nr[frequencies[key]]) {
|
|
136
|
+
Nr[frequencies[key]] = 0;
|
|
137
|
+
}
|
|
138
|
+
Nr[frequencies[key]]++;
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
// Return the ngrams AND statistics
|
|
142
|
+
return {
|
|
143
|
+
"ngrams": result,
|
|
144
|
+
"frequencies": frequencies,
|
|
145
|
+
"Nr": Nr,
|
|
146
|
+
"numberOfNgrams": nrOfNgrams
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
}
|
|
150
|
+
else { // Do not break existing API of this module
|
|
151
|
+
return result;
|
|
152
|
+
}
|
|
153
|
+
};
|