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.
Files changed (80) hide show
  1. package/.dockerignore +2 -0
  2. package/.idea/misc.xml +6 -0
  3. package/.idea/modules.xml +8 -0
  4. package/.idea/natural.iml +12 -0
  5. package/.idea/vcs.xml +6 -0
  6. package/.idea/workspace.xml +511 -0
  7. package/.travis.yml +8 -1
  8. package/README.md +331 -40
  9. package/bayes_classifier.json +1 -1
  10. package/classifier.json +418 -0
  11. package/lib/natural/brill_pos_tagger/lib/Brill_POS_Tagger.js +8 -9
  12. package/lib/natural/brill_pos_tagger/lib/Brill_POS_Tester.js +5 -5
  13. package/lib/natural/brill_pos_tagger/lib/Brill_POS_Trainer.js +10 -6
  14. package/lib/natural/brill_pos_tagger/lib/Corpus.js +21 -16
  15. package/lib/natural/brill_pos_tagger/lib/Lexicon.js +22 -13
  16. package/lib/natural/brill_pos_tagger/lib/Predicate.js +2 -2
  17. package/lib/natural/brill_pos_tagger/lib/RuleTemplate.js +2 -2
  18. package/lib/natural/brill_pos_tagger/lib/RuleTemplates.js +132 -146
  19. package/lib/natural/brill_pos_tagger/lib/Sentence.js +41 -0
  20. package/lib/natural/brill_pos_tagger/lib/TransformationRule.js +10 -11
  21. package/lib/natural/classifiers/classifier.js +5 -3
  22. package/lib/natural/classifiers/maxent/Classifier.js +125 -0
  23. package/lib/natural/classifiers/maxent/Context.js +33 -0
  24. package/lib/natural/classifiers/maxent/Distribution.js +145 -0
  25. package/lib/natural/classifiers/maxent/Element.js +34 -0
  26. package/lib/natural/classifiers/maxent/Feature.js +88 -0
  27. package/lib/natural/classifiers/maxent/FeatureSet.js +67 -0
  28. package/lib/natural/classifiers/maxent/GISScaler.js +148 -0
  29. package/lib/natural/classifiers/maxent/POS/ME_Corpus.js +56 -0
  30. package/lib/natural/classifiers/maxent/POS/ME_Sentence.js +73 -0
  31. package/lib/natural/classifiers/maxent/POS/POS_Element.js +172 -0
  32. package/lib/natural/classifiers/maxent/Sample.js +141 -0
  33. package/lib/natural/classifiers/maxent/SimpleExample/SE_Element.js +49 -0
  34. package/lib/natural/distance/hamming_distance.js +52 -0
  35. package/lib/natural/distance/jaro-winkler_distance.js +16 -6
  36. package/lib/natural/distance/levenshtein_distance.js +2 -2
  37. package/lib/natural/index.js +21 -2
  38. package/lib/natural/inflectors/noun_inflector.js +5 -3
  39. package/lib/natural/ngrams/ngrams.js +83 -25
  40. package/lib/natural/sentiment/Basque/senticon_eu.json +21557 -0
  41. package/lib/natural/sentiment/Catalan/senticon_ca.json +36352 -0
  42. package/lib/natural/sentiment/Dutch/negations_du.json +3 -0
  43. package/lib/natural/sentiment/Dutch/pattern-sentiment-nl.json +39650 -0
  44. package/lib/natural/sentiment/English/negations_en.json +3 -0
  45. package/lib/natural/sentiment/English/pattern-sentiment-en.json +16024 -0
  46. package/lib/natural/sentiment/English/senticon_en.json +124197 -0
  47. package/lib/natural/sentiment/French/pattern-sentiment-fr.json +40906 -0
  48. package/lib/natural/sentiment/Galician/senticon_gl.json +24427 -0
  49. package/lib/natural/sentiment/Italian/pattern-sentiment-it.json +24522 -0
  50. package/lib/natural/sentiment/SentimentAnalyzer.js +116 -0
  51. package/lib/natural/sentiment/Spanish/afinnShortSortedSpanish.json +1655 -0
  52. package/lib/natural/sentiment/Spanish/negations_es.json +3 -0
  53. package/lib/natural/sentiment/Spanish/senticon_es.json +56722 -0
  54. package/lib/natural/sentiment/tools/README.md +31 -0
  55. package/lib/natural/sentiment/tools/XmlParser4PatternData.js +31 -0
  56. package/lib/natural/sentiment/tools/sentimentXmlParser.js +30 -0
  57. package/lib/natural/stemmers/indonesian/data/kata-dasar.json +29935 -0
  58. package/lib/natural/stemmers/indonesian/prefix_rules.js +10 -9
  59. package/lib/natural/stemmers/indonesian/stemmer_id.js +16 -15
  60. package/lib/natural/stemmers/indonesian/suffix_rules.js +2 -2
  61. package/lib/natural/stemmers/porter_stemmer_es.js +265 -199
  62. package/lib/natural/stemmers/porter_stemmer_fr.js +1 -1
  63. package/lib/natural/stemmers/porter_stemmer_nl.js +362 -0
  64. package/lib/natural/stemmers/stemmer_es.js +18 -12
  65. package/lib/natural/stemmers/stemmer_nl.js +64 -0
  66. package/lib/natural/tfidf/tfidf.js +27 -4
  67. package/lib/natural/tokenizers/aggressive_tokenizer_sv.js +1 -1
  68. package/lib/natural/tokenizers/aggressive_tokenizer_vi.js +37 -0
  69. package/lib/natural/tokenizers/orthography_matchers.js +33 -0
  70. package/lib/natural/tokenizers/regexp_tokenizer.js +24 -4
  71. package/lib/natural/tokenizers/sentence_tokenizer.js +1 -1
  72. package/lib/natural/wordnet/wordnet_file.js +7 -1
  73. package/lr_classifier.json +1 -1
  74. package/package.json +35 -23
  75. package/.npmignore +0 -4
  76. package/.vscode/temp.sql +0 -0
  77. package/Makefile +0 -38
  78. package/data/kata-dasar.txt +0 -29933
  79. package/package-lock.json +0 -79
  80. 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
- function JaroWinklerDistance(s1, s2, dj) {
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
- var jaro = (typeof(dj) === 'undefined') ? distance(s1,s2) : dj;
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 = _.assign(
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 = _.assign({}, options || {}, { damerau: false });
101
+ var levOptions = _.extend({}, options || {}, { damerau: false });
102
102
  return levenshteinDistance(source, target, levOptions);
103
103
  }
104
104
 
@@ -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
- exports.StemmerFr = require('./stemmers/stemmer_fr');
38
- exports.StemmerPl = require('./stemmers/stemmer_pl');
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
- exports.ngrams = function(sequence, n, startSymbol, endSymbol) {
34
- return ngrams(sequence, n, startSymbol, endSymbol);
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
- result.push(blanks.slice(0, p).concat(sequence.slice(0, n - p)));
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
- result.push(sequence.slice(i, i + n));
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
- result.push(sequence.slice(sequence.length - p, sequence.length).concat(blanks.slice(0, n - p)));
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
- return result;
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
+ };