natural, 用于 node的一般自然语言设施

分享于 

57分钟阅读

GitHub

  繁體 雙語
general natural language facilities for node
  • 源代码名称:natural
  • 源代码网址:http://www.github.com/NaturalNode/natural
  • natural源代码文档
  • natural源代码下载
  • Git URL:
    git://www.github.com/NaturalNode/natural.git
    Git Clone代码到本地:
    git clone http://www.github.com/NaturalNode/natural
    Subversion代码到本地:
    $ svn co --depth empty http://www.github.com/NaturalNode/natural
    Checked out revision 1.
    $ cd repo
    $ svn up trunk
    
    自然

    NPM versionBuild StatusSlack

    Natural自然"是nodejs的通用自然语言设施。 目前支持标记。干扰。分类。语音。adf ,。string。字符串相似性等。

    它仍处于早期阶段,因这里我们对 Bug 报告。捐赠和等等非常感兴趣。

    请注意,来自ellis的Rob nltools的许多算法合并到这个项目中,并将从这里继续维护。

    虽然大多数算法都是英语特定的,但是贡献者已经实现了对其他语言的支持。 感谢 Polyakov Vladimir,添加了俄罗斯的词干 ! 感谢 David Przybilla,西班牙推出了 ! 感谢更多的贡献者,词干和标记的更多语言已经加入。

    在这个版本中,唯一的文档是这个DZone文章,在我的博客这个免费课程,在我的博客,这是一个比较老的。

    table-内容

    安装

    如果你只是想在没有自己的node 应用程序的情况下使用自然,你可以通过如下方式安装:

    
    npm install natural
    
    
    
    

    如果你感兴趣的是自然的,或者只是黑进它,那么就意味着 fork 离开了 !

    Tokenizers

    为将文本分解为标记数组,提供了单词,正则表达式和语法分析器 tokenizers:

    var natural =require('natural');var tokenizer =newnatural.WordTokenizer();console.log(tokenizer.tokenize("your dog has fleas."));// [ 'your', 'dog', 'has', 'fleas' ]

    另一个tokenizers遵循类似的Pattern:

    tokenizer =newnatural.TreebankWordTokenizer();console.log(tokenizer.tokenize("my dog hasn't any fleas."));// [ 'my', 'dog', 'has', 'n't', 'any', 'fleas', '.' ]tokenizer =newnatural.RegexpTokenizer({pattern:/-/});console.log(tokenizer.tokenize("flea-dog"));// [ 'flea', 'dog' ]tokenizer =newnatural.WordPunctTokenizer();console.log(tokenizer.tokenize("my dog hasn't any fleas."));// [ 'my', 'dog', 'hasn', ''', 't', 'any', 'fleas', '.' ]tokenizer =newnatural.OrthographyTokenizer({language:"fi"});console.log(tokenizer.tokenize("Mikä sinun nimesi on?"));// [ 'Mikä', 'sinun', 'nimesi', 'on' ]

    可用tokenizers的概述:

    标记记号语言解释
    WordTokenizer任意除字母字符。数字和下划线以外的任何内容
    WordPunctTokenizer任意除字母字符。数字。标点和下划线以外的任何内容
    SentenceTokenizer任意基于punctation和引号将字符串分成几个部分
    CaseTokenizer任意?如果小写和大写是相同的,则假定字符是空格或者它的他( 标点符号)。
    RegexpTokenizer任意在正则表达式上拆分,该表达式定义单词字符或者间隙字符的序列
    OrthographyTokenizer芬兰语除alpabetic字符,数字和下划线以外的任何内容
    TreebankWordTokenizer任意
    AggressiveTokenizer简体中文
    AggressiveTokenizerFa波斯语
    AggressiveTokenizerFr法语
    AggressiveTokenizerRu俄文
    AggressiveTokenizerEs西班牙语
    AggressiveTokenizerIt意大利语
    AggressiveTokenizerPl波兰语
    AggressiveTokenizerPt葡萄牙语葡萄牙语
    AggressiveTokenizerNo挪威语
    AggressiveTokenizerSv瑞典语
    AggressiveTokenizerVi越南语
    TokenizerJa日语

    字符串距离

    自然提供了三种计算字符串距离的算法的实现: 汉明距离,jaro winkler,Levenshtein距离和骰子系数。

    通过计算不同字符数的个数,汉明距离度量长度相等的两个字符串之间的距离。 第三个参数指示是否应忽略大小写。 默认情况下,该算法区分大小写。

    var natural =require('natural');console.log(natural.HammingDistance("karolin", "kathrin", false));console.log(natural.HammingDistance("karolin", "kerstin", false));// If strings differ in length -1 is returnedconsole.log(natural.HammingDistance("short string", "longer string", false));

    输出:

    33-1

    在字符串距离测量算法中,字符串距离测量算法将返回一个介于 0到 1之间的数字,这说明字符串的MATCH ( 0 = 根本不匹配,1 = 完全匹配) 是如何紧密的:

    var natural =require('natural');console.log(natural.JaroWinklerDistance("dixon","dicksonx"));console.log(natural.JaroWinklerDistance('not', 'same'));

    输出:

    0.74666666666666660

    如果字符串之间的距离已经知道,你可以将它作为第三个参数传递。 通过传递第四个参数,你可以强制该算法忽略大小写,如下所示:

    var natural =require('natural');console.log(natural.JaroWinklerDistance("dixon","dicksonx", undefined, true));

    自然也提供了对 的支持:

    var natural =require('natural');console.log(natural.LevenshteinDistance("ones","onez"));console.log(natural.LevenshteinDistance('one', 'one'));

    输出:

    10

    三种编辑操作的成本可以修改为 Levenshtein:

    console.log(natural.LevenshteinDistance("ones","onez", {
     insertion_cost:1,
     deletion_cost:1,
     substitution_cost:1}));

    输出:

    1

    如果你想将字符转换视为有效的编辑操作,则可以使用完全 Damerau levenshtein匹配。

    console.log(natural.DamerauLevenshteinDistance("az", "za"));

    输出:

    1

    转换成本也可以修改:

    console.log(natural.DamerauLevenshteinDistance("az", "za", { transposition_cost:0 }))

    输出:

    0

    可用的Damerau levenshtein ( 最佳字符串对齐方式)的限制形式。

    这种匹配形式比无限制Damerau的空间有效,只考虑转换的字符之间没有字符。

    比较:

    // Optimal String Alignmentconsole.log(natural.DamerauLevenshteinDistance('ABC', 'ACB'), { restricted:true });1console.log(natural.DamerauLevenshteinDistance('CA', 'ABC', { restricted:true }));2// Unrestricted Damerau-Levenshteinconsole.log(natural.DamerauLevenshteinDistance('CA', 'ABC', { restricted:false }));1

    的高效骰子:

    var natural =require('natural');console.log(natural.DiceCoefficient('thing', 'thing'));console.log(natural.DiceCoefficient('not', 'same'));

    输出:

    10

    近似字符串匹配

    当前匹配是通过Levenshtein算法支持的。

    var natural =require('natural');var source ='The RainCoat BookStore';var target ='All the best books are here at the Rain Coats Book Store';console.log(natural.LevenshteinDistance(source, target, {search:true}));

    输出:

    { substring:'the Rain Coats Book Store', distance:4 }

    以下内容

    Stemmers

    目前,通过波特Lancaster的算法支持当前的词干。 印度尼西亚和日本的词干跟踪不遵循已知的算法。

    var natural =require('natural');

    本示例使用波特字符分析器。 返回""。

    console.log(natural.PorterStemmer.stem("words")); // stem a single word

    在俄语中:

    console.log(natural.PorterStemmerRu.stem("падший"));

    在西班牙语中:

    console.log(natural.PorterStemmerEs.stem("jugaría"));

    下面是可用的词干分析器:

    语言波特Lancaster其他模块
    荷兰语XPorterStemmerNl
    简体中文XPorterStemmer
    简体中文XLancasterStemmer
    波斯语( 进行中)XPorterStemmerFa
    法语XPorterStemmerFr
    瑞典语XStemmerId
    意大利语XPorterStemmerIt
    日语XStemmerJa
    挪威语XPorterStemmerNo
    葡萄牙语葡萄牙语XPorterStemmerPt
    俄文XPorterStemmerRu
    瑞典语XPorterStemmerSv

    attach() 修补程序 stem()tokenizeAndStem() 以字符串的形式指向 PorterStemmer.stem(token)tokenizeAndStem() 将文本分解成单个单词,并返回一个 array 标记的。

    natural.PorterStemmer.attach();console.log("i am waking up to the sounds of chainsaws".tokenizeAndStem());console.log("chainsaws".stem());

    同样的事情也可以通过 Lancaster stemmer完成:

    natural.LancasterStemmer.attach();console.log("i am waking up to the sounds of chainsaws".tokenizeAndStem());console.log("chainsaws".stem());

    分类器

    贝叶斯和logistic回归

    目前支持两种分类器,即 Naive Bayeslogistic回归模型。 下面的示例使用BayesClassifier类,但可以替代LogisticRegressionClassifier类。

    var natural =require('natural');var classifier =newnatural.BayesClassifier();

    你可以对样本文本中的分类器进行训练。 它将使用合理的默认标记来标记文本。

    classifier.addDocument('i am long qqqq', 'buy');classifier.addDocument('buy the q's', 'buy');classifier.addDocument('short gold', 'sell');classifier.addDocument('sell gold', 'sell');classifier.train();

    输出"销售"

    console.log(classifier.classify('i am short silver'));

    输出""

    console.log(classifier.classify('i am long copper'));

    你可以访问匹配类的集合和来自分类器的相关值。

    输出:

    [ { label:'buy', value:0.39999999999999997 },
     { label:'sell', value:0.19999999999999998 } ]

    从这个角度:

    console.log(classifier.getClassifications('i am long copper'));

    分类器也可以被训练和可以分类的标记,字符串或者任何混合的任何混合物。 数组使你可以使用自己的标记/干扰来完全使用自定义数据,如果选择实现它。

    classifier.addDocument(['sell', 'gold'], 'sell');

    可以通过订阅分类器发出的事件 trainedWithDocument 来监视培训过程,每次对文档进行训练时发出:

    classifier.events.on('trainedWithDocument', function (obj) {
     console.log(obj);
     /* { * total: 23//There are 23 total documents being trained against * index: 12//The index/number of the document that's just been trained against * doc: {...}//The document that has just been indexed * }*/ });

    分类器也可以保持和召回,这样你就可以重用训练

    classifier.save('classifier.json', function(err, classifier) {
     // the classifier is saved to the classifier.json file!});

    要从上面保存的classifier.json 撤回:

    natural.BayesClassifier.load('classifier.json', null, function(err, classifier) {
     console.log(classifier.classify('long SUNW'));
     console.log(classifier.classify('short SUNW'));
    });

    分类器也可以像这样序列化和反序列化:

    var classifier =newnatural.BayesClassifier();classifier.addDocument(['sell', 'gold'], 'sell');classifier.addDocument(['buy', 'silver'], 'buy');// serializevar raw =JSON.stringify(classifier);// deserializevar restoredClassifier =natural.BayesClassifier.restore(JSON.parse(raw));console.log(restoredClassifier.classify('i should sell that'));

    注意:如果你使用的语言不是英语,那么你可能需要将stemmer传递给 stemmer。 实际上,你可以对任何包含备用英语词干分析器的词干分析器执行这里操作。 默认值为 PorterStemmer

    constPorterStemmerRu=require('./node_modules/natural/lib/natural/stemmers/porter_stemmer_ru');var classifier =newnatural.BayesClassifier(PorterStemmerRu);

    最大熵分类器

    这个 MODULE 提供了基于最大熵模型的分类器。 最大熵建模的核心思想是估计具有最大熵的概率分布,该概率分布与可用的证据相匹配。 这意味着分布遵循"看见"拥有的数据,但不进行任何假设。

    MODULE 不特定于自然语言处理,也不特定于任何其他应用程序域。 对数据结构的要求很少,可以对它的进行培训。 对于训练,需要一个由元素组成的示例。 这些元素有两个部分:

    • 部件 a: 元素的类
    • 第 b: 部分分类器将被训练的元素上下文,返回特定上下文中最可能的类。

    我们从样本和元素的解释开始。 你必须创建你自己的元素类专门化。 元素类应该实现generateFeatures方法来从示例中推断特征函数。

    示例和元素

    元素和上下文按如下方式创建:

    var MyElement =require('MyElementClass');var Context =require('Context');var Sample =require('Sample');var x =newMyElementClass("x", newContext("0"));// A sample is created from an array of elementsvar sample =newSample();sample.addElement(x);

    类是一个字符串,上下文可以能与你想要的( 只要是 serialised ) 一样复杂。

    可以从 file: 中保存和加载示例

    sample.save('sample.json', function(error, sample) {
     ...});

    可以从文件中读取示例,如下所示。

    sample.load('sample.json', MyElementClass, function(err, sample) {
    });

    必须将元素类传递给load方法,以便从数据创建正确的元素对象。

    特性和特性集

    要素是将元素映射到零或者一个的函数。 特性的定义如下:

    var Feature =require('Feature');functionf(x) {
     if (x.b==="0") {
     return1;
     }
     return0;
    }var feature =newFeature(f, name, parameters);

    name 是特征函数的NAME的字符串,parameters 是特征函数参数的字符串的array。 NAME 和参数的组合应该唯一地区分特性。 添加到特性集的特性将使用这些属性测试唯一性。

    像这样创建一个特性集

    var FeatureSet =require('FeatureSet');var set =newFeatureSet();set.addFeature(f, "f", ["0"]);

    在大多数情况下,你将使用闭包生成特征函数。 例如当你在循环中生成用于循环访问 array的特征函数时

    var FeatureSet =require('FeatureSet');var Feature =require('Feature');var listOfTags = ['NN', 'DET', 'PREP', 'ADJ'];var featureSet =newFeatureSet();listofTags.forEach(function(tag) {
     functionisTag(x) {
     if (x.b.data.tag=== tag) {
     return1 }
     return0;
     }
     featureSet.addFeature(newFeature(f, "f", [tag]));
    });

    在这个例子中,你创建了一个特性函数,每个函数在它的闭包中都有一个不同的tag 值。

    设置和训练分类器

    分类器需要以下参数:

    • 类:类的array ( 字符串)
    • 特征:特征函数的array
    • 样本:用于训练分类器的元素示例

    可以按如下方式创建分类器:

    var Classifier =require('Classifier');var classifier =newClassifier(classes, featureSet, sample);

    然后开始训练:

    var maxIterations =100;var minImprovement =.01;var p =classifier.train(maxIterations, minImprovement);

    maxIterations 达到或者可能的似然( 示例) 小于 minImprovement 时,训练就完成了。 它返回一个可以存储和检索的概率分布,以便以后使用:

    classifier.save('classifier.json', function(err, c) {
     if (err) {
     console.log(err);
     }
     else {
     // Continue using the classifier }
    });classifier.load('classifier.json', function(err, c) {
     if (err) {
     console.log(err);
     }
     else {
     // Use the classifier }
    });

    训练算法是基于广义迭代缩放的。

    应用分类器

    分类器可以用两种方法来分类上下文。 要获取所有类的概率:

    var classifications =classifier.getClassifications(context);classifications.forEach(function(classPlusProbability) {
     console.log('Class '+classPlusProbability.label+' has score '+classPlusProbability.value);
    });

    这将从类到概率返回映射。 要获得最高评分类别:

    varclass=classifier.classify(context);console.log(class);
    最大熵模型的简单例子

    基于具有" 0"或者" 1"的上下文的简单元素,将测试添加到规定文件夹中,并且类是"x"和"y"。

    {
     "a":"x",
     "b": {
     "data":"0" }
    }

    在从元素继承的SE_Element类中,实现了方法 generateFeatures。 它创建了一个测试上下文" 0"的特性函数。

    在设置自己的元素类之后,可以创建和训练分类器。

    在POS标记中的应用

    一个更为精确的最大熵模型示例,用于词性标注。 创建分类器并将它的应用到测试集的步骤如下:

    • 创建一个新元素类 POS_Element,它有一个单词窗口和一个标记窗口,该窗口围绕要标记的单词。
    • 从Brown语料库生成一个由POS元素组成的示例。
    • 从示例中生成功能函数。
    • 创建并训练一个分类器。
    • 分类器被应用到测试集。 将结果与基于简单词典的tagger进行比较。
    引用

    基于的情感分析

    这是一个基于词汇的简单情感分析算法,它为单词分配极性。 算法通过对每个单词的极性和句子长度的规范化来计算文本的情感。 如果出现否定,结果将变为负数。 它按如下方式使用:

    var Analyzer =require('natural').SentimentAnalyzer;var stemmer =require('natural').PorterStemmer;var analyzer =newAnalyzer("English", stemmer, "afinn");// getSentiment expects an array of stringsconsole.log(analyzer.getSentiment(["I", "like", "cherries"]));// 0.6666666666666666

    构造函数有三个参数:

    • 语言:请参阅支持的语言的below。
    • Stemmer: 为了增加情感分析器的覆盖率,可以提供一个词干分析器。 可能是 null
    • 词汇:设置词汇类型,"afinn""senticon" 或者 "pattern" 是有效值。

    目前,使用词汇表类型和 negations ( 按字母顺序排列)的可用性支持以下语言:

    语言 AFINN Senticon Pattern Negations
    BasqueX
    Catalan语X
    荷兰语XX
    简体中文XXXX
    法语X
    加利西亚语X
    意大利语X
    西班牙语XXX

    添加词汇表并在 SentimentAnalyzer.js 中扩展映射 languageFiles,可以增加更多的语言。 在工具文件夹 below lib/natural/sentiment 中,提供了一些工具,用于将Senticon和 Pattern 格式的词汇转换为JSON格式。

    确认和引用

    感谢 Domingo Martín Mancera在他的repo Lorca 提供了这个情绪分析器的基础。

    AFINN是一个英文单词列表,它的中有一个整数在减五( 负片) 和五个( 正) 之间的整数。 科学参考可以在这里找到: 我们使用了 afinn-165,它作为nodejs模块可用。

    senticon词汇表是基于Fermin工作的。 Cruz和其他:Cruz,Fermín L,José。 Troyano,Beatriz Pontes,F Ortega。 在synset和引理层面构建分层。多语言的词汇词典,具有应用的专家系统,2014.

    Pattern 词汇表来自大学剪辑研究中心的 Pattern 项目插件。 这些有PDDL许可证。

    语音

    可以使用 Metaphone或者DoubleMetaphone算法来匹配语音匹配( 声音像) 匹配

    var natural =require('natural');var metaphone =natural.Metaphone;var soundEx =natural.SoundEx;var wordA ='phonetics';var wordB ='fonetix';

    要测试这两个单词是否发音相同,请执行以下操作:

    if(metaphone.compare(wordA, wordB))
     console.log('they sound alike!');

    使用 process() 获得原始语音:

    console.log(metaphone.process('phonetics'));

    可以提供最大代码长度:

    console.log(metaphone.process('phonetics', 3));

    DoubleMetaphone 处理在 array 中返回的两个编码。 这里特性是实验性的,并且可以更改:

    var natural =require('natural');var dm =natural.DoubleMetaphone;var encodings =dm.process('Matrix');console.log(encodings[0]);console.log(encodings[1]);

    附加将使用有用的方法修补字符串:

    metaphone.attach();

    soundsLike 实质上是 Metaphone.compare的快捷方式:

    if(wordA.soundsLike(wordB))
     console.log('they sound alike!');

    使用 phonetics() 获得原始语音:

    console.log('phonetics'.phonetics());

    完整的文本字符串可以被标记为语音( 非常类似于tokenization-to-arrays如何在词干分析器中工作) 数组:

    console.log('phonetics rock'.tokenizeAndPhoneticize());

    SoundEx 应用的相同 MODULE 操作:

    if(soundEx.compare(wordA, wordB))
     console.log('they sound alike!');

    SoundEx 一起应用的相同字符串修补程序:

    soundEx.attach();if(wordA.soundsLike(wordB))
     console.log('they sound alike!');console.log('phonetics'.phonetics());

    Inflectors

    名词

    名词可以是复数/singularized,也可以是 NounInflector:

    var natural =require('natural');var nounInflector =newnatural.NounInflector();

    若要将单词数字化为( 输出"半径"):

    console.log(nounInflector.pluralize('radius'));

    要使用单词啤酒"),请执行以下操作:

    console.log(nounInflector.singularize('beers'));

    其他许多特性一样,可以对字符串进行修补以直接执行操作。 方法上的"名词"后缀是必需的,因为将来会支持动词。

    nounInflector.attach();console.log('radius'.pluralizeNoun());console.log('beers'.singularizeNoun());

    电子邮件编号

    数字可以用CountInflector计算:

    var countInflector =natural.CountInflector;

    输出" 1st":

    console.log(countInflector.nth(1));

    输出" 111th":

    console.log(countInflector.nth(111));

    现在时态动词

    现在时态动词可以用 PresentVerbInflector pluralized/singularized。 这里功能在 0.0.42年仍处于实验阶段,因此请谨慎使用,并提供反馈。

    var verbInflector =newnatural.PresentVerbInflector();

    输出"变成":

    console.log(verbInflector.singularize('become'));

    输出"变成":

    console.log(verbInflector.pluralize('becomes'));

    其他许多自然模块一样,attach() 也可以用方便的方法来修补字符串。

    verbInflector.attach();console.log('walk'.singularizePresentVerb());console.log('walks'.pluralizePresentVerb());

    对于数组或者字符串( 将为你 tokenized ),可以获得n 克:

    var NGrams =natural.NGrams;

    bigrams

    console.log(NGrams.bigrams('some words here'));console.log(NGrams.bigrams(['some', 'words', 'here']));

    两个 上面 输出: [ [ 'some', 'words' ], [ 'words', 'here' ] ]

    console.log(NGrams.trigrams('some other words here'));console.log(NGrams.trigrams(['some', 'other', 'words', 'here']));

    两个 上面 输出: [ [ 'some', 'other', 'words' ], [ 'other', 'words', 'here' ] ]

    任意n 克

    console.log(NGrams.ngrams('some other words here for you', 4));console.log(NGrams.ngrams(['some', 'other', 'words', 'here', 'for',
     'you'], 4));

    上面 输出: [ [ 'some', 'other', 'words', 'here' ], [ 'other', 'words', 'here', 'for' ], [ 'words', 'here', 'for', 'you' ] ]

    填充

    n 克还可以通过向,或者ngrams传递开始和/或者结束符号来返回左或者右 padding。

    console.log(NGrams.ngrams('some other words here for you', 4, '[start]', '[end]'));

    上面 将输出:

    
    [ [ '[start]', '[start]', '[start]', 'some' ],
    
    
     [ '[start]', '[start]', 'some', 'other' ],
    
    
     [ '[start]', 'some', 'other', 'words' ],
    
    
     [ 'some', 'other', 'words', 'here' ],
    
    
     [ 'other', 'words', 'here', 'for' ],
    
    
     [ 'words', 'here', 'for', 'you' ],
    
    
     [ 'here', 'for', 'you', '[end]' ],
    
    
     [ 'for', 'you', '[end]', '[end]' ],
    
    
     [ 'you', '[end]', '[end]', '[end]' ] ]
    
    
    
    

    对于只有结束符号,请为起始符号传递 null,例如:

    console.log(NGrams.ngrams('some other words here for you', 4, null, '[end]'));

    将输出:

    
    [ [ 'some', 'other', 'words', 'here' ],
    
    
     [ 'other', 'words', 'here', 'for' ],
    
    
     [ 'words', 'here', 'for', 'you' ],
    
    
     [ 'here', 'for', 'you', '[end]' ],
    
    
     [ 'for', 'you', '[end]', '[end]' ],
    
    
     [ 'you', '[end]', '[end]', '[end]' ] ]
    
    
    
    

    NGramsZH

    对于中文类似语言,可以使用NGramsZH做n 克,所有的api都是相同的:

    var NGramsZH =natural.NGramsZH;console.log(NGramsZH.bigrams('中文测试'));console.log(NGramsZH.bigrams(['', '', '', '']));console.log(NGramsZH.trigrams('中文测试'));console.log(NGramsZH.trigrams(['', '', '', '']));console.log(NGramsZH.ngrams('一个中文测试', 4));console.log(NGramsZH.ngrams(['', '', '', '', '',
     ''], 4));

    idf

    术语频率反向文档频率( tf-idf ) 中,实现了一个词( 或者单词) 对文档 relative的重要程度的影响。 以下公式用于计算tf和 idf:

    • tf ( t,d ) 是所谓的原始计数,所以仅仅是文档中的术语计数
    • idf ( t,D ) 使用以下公式: 1 + ln ( N/( 1 + n_t ) ) 其中N 是文档数量,n_t表示出现该术语的文档数。 分母中的1 + 用于处理n_t是 0的可能性。

    以下示例将向语料库添加四个文档,并确定单词"node"的权重,然后确定每个文档中单词"ruby"的权重。

    var natural =require('natural');var TfIdf =natural.TfIdf;var tfidf =newTfIdf();tfidf.addDocument('this document is about node.');tfidf.addDocument('this document is about ruby.');tfidf.addDocument('this document is about ruby and node.');tfidf.addDocument('this document is about node. it has node examples');console.log('node --------------------------------');tfidf.tfidfs('node', function(i, measure) {
     console.log('document #'+ i +' is '+ measure);
    });console.log('ruby --------------------------------');tfidf.tfidfs('ruby', function(i, measure) {
     console.log('document #'+ i +' is '+ measure);
    });

    上面 输出:

    
    node --------------------------------
    
    
    document #0 is 1
    
    
    document #1 is 0
    
    
    document #2 is 1
    
    
    document #3 is 2
    
    
    ruby --------------------------------
    
    
    document #0 is 0
    
    
    document #1 is 1.2876820724517808
    
    
    document #2 is 1.2876820724517808
    
    
    document #3 is 0
    
    
    
    

    这里方法也可以应用于各个文档。

    以下示例对第一个和第二个文档中的术语"node"进行度量。

    console.log(tfidf.tfidf('node', 0));console.log(tfidf.tfidf('node', 1));

    TfIdf实例还可以从磁盘上的文件加载文档。

    var tfidf =newTfIdf();tfidf.addFileSync('data_files/one.txt');tfidf.addFileSync('data_files/two.txt');

    还可以测量多个术语,它们的权重被添加到单个度量值中。 下面的示例确定最后一个文档与"node"和"ruby"中的单词最相关。

    var natural =require('natural');var TfIdf =natural.TfIdf;var tfidf =newTfIdf();tfidf.addDocument('this document is about node.');tfidf.addDocument('this document is about ruby.');tfidf.addDocument('this document is about ruby and node.');tfidf.tfidfs('node ruby', function(i, measure) {
     console.log('document #'+ i +' is '+ measure);
    });

    上面 输出:

    
    document #0 is 1
    
    
    document #1 is 1
    
    
    document #2 is 2
    
    
    
    

    示例 上面 都使用字符串,这导致自然地自动标记输入。 如果你希望执行自己的标记化或者它的他类型的处理,则可以执行这里操作,然后传递到结果数组。 这种方法允许你绕过默认的自然预处理。

    var natural =require('natural');var TfIdf =natural.TfIdf;var tfidf =newTfIdf();tfidf.addDocument(['document', 'about', 'node']);tfidf.addDocument(['document', 'about', 'ruby']);tfidf.addDocument(['document', 'about', 'ruby', 'node']);tfidf.addDocument(['document', 'about', 'node', 'node', 'examples']);tfidf.tfidfs(['node', 'ruby'], function(i, measure) {
     console.log('document #'+ i +' is '+ measure);
    });

    可以从文档中检索所有术语的列表,按它的重要性排序。

    tfidf.listTerms(0/*document index*/).forEach(function(item) {
     console.log(item.term+': '+item.tfidf);
    });

    TfIdf实例还可以进行序列化和反序列化以保存和收回。

    var tfidf =newTfIdf();tfidf.addDocument('document one', 'un');tfidf.addDocument('document Two', 'deux');var s =JSON.stringify(tfidf);// save"s" to disk, database or otherwise// assuming you pulled"s" back out of storage.var tfidf =newTfIdf(JSON.parse(s));

    尝试

    尝试是一种非常有效的数据结构,用于基于前缀的搜索。 自然来自一个基本的,实现,它可以支持沿路径。存在搜索和前缀搜索的MATCH 集合。

    构建Trie树

    要构建Trie字典,需要添加单词,这是基本Trie设置的示例:

    var natural =require('natural');var Trie =natural.Trie;var trie =newTrie();// Add one string at a timetrie.addString("test");// Or add many stringstrie.addStrings(["string1", "string2", "string3"]);

    全文搜索

    包含

    Trie树上最基本的操作是在Trie树中检查搜索字符串是否被标记为单词。

    console.log(trie.contains("test")); // trueconsole.log(trie.contains("asdf")); // false

    查找前缀

    查找前缀搜索将查找在trie树中标识为单词的最长前缀。 它还将返回它无法匹配的字符串的剩余部分。

    console.log(trie.findPrefix("tester")); // ['test', 'er']console.log(trie.findPrefix("string4")); // [null, '4']console.log(trie.findPrefix("string3")); // ['string3', '']

    路径上的所有前缀

    这里搜索将沿着搜索字符串路径返回所有前缀 MATCHES。

    trie.addString("tes");trie.addString("est");console.log(trie.findMatchesOnPath("tester")); // ['tes', 'test'];

    所有带有前缀的键

    这个搜索将返回Trie中具有给定前缀的所有单词,如果没有找到,则返回 [ ]。

    console.log(trie.keysWithPrefix("string")); // ["string1","string2","string3"]

    区分大小写

    默认情况下Trie是区分大小写的,你可以通过将 false 传递给Trie构造函数来在case-_in_sensitive模式中使用它。

    trie.contains("TEST"); // falsevar ciTrie =newTrie(false);ciTrie.addString("test");ciTrie.contains("TEsT"); // true

    在返回字符串的搜索中,如果你处于case-_in_sensitive模式,返回的所有字符串都将处于较低的状态。

    EdgeWeightedDigraph

    EdgeWeightedDigraph表示有向图,你可以添加边,得到数顶点,边,获取所有边,使用toString来打印有向图。

    初始化有向图:

    var EdgeWeightedDigraph =natural.EdgeWeightedDigraph;var digraph =newEdgeWeightedDigraph();digraph.add(5,4,0.35);digraph.add(5,1,0.32);digraph.add(1,3,0.29);digraph.add(6,2,0.40);digraph.add(3,6,0.52);digraph.add(6,4,0.93);

    使用的api是:添加( 从,到,重量)。

    获取顶点数:

    console.log(digraph.v());

    你会得到 7.

    获取边的数目:

    console.log(digraph.e());

    你会得到 6.

    ShortestPathTree

    ShortestPathTree表示边界加权无环图( DAGs ) 中单源最短路径问题的一种数据类型。 边缘权重可以是正数,负数或者零。 有三个 api: getDistTo(vertex), hasPathTo(vertex), pathTo(vertex)。

    var ShortestPathTree =natural.ShortestPathTree;var spt =newShortestPathTree(digraph, 5);

    图是EdgeWeightedDigraph的一个实例,第二个参数是DAG的起始顶点。

    getDistTo ( 顶点)

    将向顶点返回顶点。

    console.log(spt.getDistTo(4));

    输出将为:0.35

    路径( 顶点)

    将返回最短路径:

    console.log(spt.pathTo(4));

    输出将为:

    [5, 4]

    LongestPathTree

    LongestPathTree表示边界加权无环图( DAGs ) 中最长路径问题的一种数据类型。 边缘权重可以是正数,负数或者零。 有三个与ShortestPathTree相同的api: getDistTo(vertex), hasPathTo(vertex), pathTo(vertex)。

    var LongestPathTree =natural.LongestPathTree;var lpt =newLongestPathTree(digraph, 5);

    图是EdgeWeightedDigraph的一个实例,第二个参数是DAG的起始顶点。

    getDistTo ( 顶点)

    将向顶点返回顶点。

    console.log(lpt.getDistTo(4));

    输出将为:2.06

    路径( 顶点)

    将返回最长的路径:

    console.log(lpt.pathTo(4));

    输出将为:

    [5, 1, 3, 6, 4]

    WordNet

    最新和最具实验性的特性之一是WordNet集成。 下面是使用自然查找单词 node的定义的示例。 使用 WordNet MODULE,首先使用 WordNet db 安装WordNet数据库文件:

    
    npm install wordnet-db
    
    
    
    

    请记住,ccr集成在这里时被认为是实验,而不是生产准备。 这个API也可能会改变。 对于性能大大提高的实现以及命令行接口,请参见 wordPos

    下面是查找单词"node"的定义的示例。

    var wordnet =newnatural.WordNet();wordnet.lookup('node', function(results) {
     results.forEach(function(result) {
     console.log('------------------------------------');
     console.log(result.synsetOffset);
     console.log(result.pos);
     console.log(result.lemma);
     console.log(result.synonyms);
     console.log(result.pos);
     console.log(result.gloss);
     });
    });

    如果给定同义词的偏移量和词性,可以直接查找定义。

    var wordnet =newnatural.WordNet();wordnet.get(4424418, 'n', function(result) {
     console.log('------------------------------------');
     console.log(result.lemma);
     console.log(result.pos);
     console.log(result.gloss);
     console.log(result.synonyms);
    });

    你可以通过手动下载WordNet数据库文件,将文件夹传递到构造函数:

    var wordnet =newnatural.WordNet('/my/wordnet/dict');

    从v0.1.11开始,将不再自动下载WordNet数据文件。

    普林斯顿大学"关于 WordNet。"WordNet。 普林斯顿大学。2010.http://wordnet.princeton.edu

    拼写检查

    基于 http://norvig.com/spell-correct.html的概率校对器

    这是最好用来自一个语料库的令牌的array,但是一个词典中的单词列表将会工作。

    var corpus = ['something', 'soothing'];var spellcheck =newnatural.Spellcheck(corpus);

    它使用 trie datastructure来快速查找单词

    spellcheck.isCorrect('cat'); // false

    它建议修改( 按概率按降序排序),使它的最大限度地远离输入单词。 根据 Norvig,最大距离 1将覆盖 80%到 95%的拼写错误。 距离为 2,它变得非常慢。

    spellcheck.getCorrections('soemthing', 1); // ['something']spellcheck.getCorrections('soemthing', 2); // ['something', 'soothing']

    Tagger

    这是一个基于Brill算法的Eric变换的part-of-speech。 在外部文件中指定转换规则。

    用法

    var natural =require("natural");var path =require("path");var base_folder =path.join(path.dirname(require.resolve("natural")), "brill_pos_tagger");var rulesFilename = base_folder +"/data/English/tr_from_posjs.txt";var lexiconFilename = base_folder +"/data/English/lexicon_from_posjs.json";var defaultCategory ='N';var lexicon =newnatural.Lexicon(lexiconFilename, defaultCategory);var rules =newnatural.RuleSet(rulesFilename);var tagger =newnatural.BrillPOSTagger(lexicon, rules);var sentence = ["I", "see", "the", "man", "with", "the", "telescope"];console.log(tagger.tag(sentence));

    这里输出将输出以下内容:

    
    Sentence {
    
    
     taggedWords:
    
    
     [ { token: 'I', tag: 'NN' },
    
    
     { token: 'see', tag: 'VB' },
    
    
     { token: 'the', tag: 'DT' },
    
    
     { token: 'man', tag: 'NN' },
    
    
     { token: 'with', tag: 'IN' },
    
    
     { token: 'the', tag: 'DT' },
    
    
     { token: 'telescope', tag: 'NN' } ] }
    
    
    
    

    词典

    字典是一个具有以下结构的JSON文件:

    {
     "word1": ["cat1"],
     "word2": ["cat2", "cat3"],
     ...}

    或者文本 file:

    
    word1 cat1 cat2
    
    
    word2 cat3
    
    
    ...
    
    
    
    

    词汇在词典文件中可能有多个类别。 tagger只使用指定的第一个类别。

    指定转换规则

    转换规则按如下方式指定:

    
    OLD_CAT NEW_CAT PREDICATE PARAMETER
    
    
    
    

    这意味着当当前位置的类别为OLD_CAT且谓词为 true 时,该类别将替换为 NEW_CAT。 谓词可以不同的方式使用参数: 有时,参数用于指定谓词的结果:

    
    NN CD CURRENT-WORD-IS-NUMBER YES
    
    
    
    

    这意味着如果谓词CURRENT-WORD-IS-NUMBER的结果是 YES,那么该类别将被 CD 替换。 参数还可以用于检查语句中某个单词的类别:

    
    VBD NN PREV-TAG DT
    
    
    
    

    在这里,要应用规则,前一个单词的类别必须是 DT

    算法

    tagger应用转换规则,可以改变单词的类别。 输入句是带标记词的句子宾语。 标记句从左到右处理。 在每个步骤中,所有规则都被应用一次;规则按照它们指定的顺序应用。 算法:

    Brill_POS_Tagger.prototype.applyRules=function(sentence) {
     for (var i =0, size =sentence.taggedWords.length; i < size; i++) {
     this.ruleSet.getRules().forEach(function(rule) {
     rule.apply(sentence, i);
     });
     }
     return sentence;
    };

    输出是一个句子对象,就像输入语句一样。

    添加谓词

    谓词在 MODULE lib/RuleTemplates.js 中定义。 在文件谓词名称中映射到generaring转换规则的元数据。 必须提供以下属性:

    • 谓词的名称
    • 计算谓词的函数( 应返回布尔值)
    • 将句子 relative 中谓词的span 定义为当前位置的窗口 [i, j]
    • 谓词需要的参数数: 0,1或者 2
    • 如果相关,参数 1的函数返回语句中当前位置的可能值( 用于在训练中生成规则)
    • 如果相关,参数 2将在语句的当前位置返回可能值的函数( 用于训练)

    规则模板的典型条目如下所示:

    "NEXT-TAG": {
     // maps to the predicate function"function": next_tag_is,
     // Minimum required window before or after current position to be a relevant predicate"window": [0, 1],
     // The number of parameters the predicate takes"nrParameters":1,
     // Function that returns relevant values for parameter 1"parameter1Values": nextTagParameterValues
     }

    谓词函数接受句子对象,该句中应当标记的当前位置,以及谓词的结果。 检查当前单词的类别的谓词的示例:

    functionnext_tag_is(sentence, i, parameter) {
     if (i <sentence.taggedWords.length-1) {
     return(sentence.taggedWords[i +1][1] === parameter);
     }
     else {
     return(false);
     }
    }

    参数的值函数返回一个 array 所有可以能的参数值,给定一个标记句中的位置。

    functionnextTagParameterValues(sentence, i) {
     if (i <sentence.length-1) {
     return [sentence[i +1].tag];
     }
     else {
     return [];
     }
    }

    培训

    教练允许从语料库学习一组新的转换规则。 它作为输入标签语料库和一组规则模板。 算法从模板生成正规则( 在语料库中的某些位置应用的规则),并迭代地扩展和优化规则集。

    首先,应该加载一个语料库。 目前,支持Brown语料库的格式。 然后从语料库中创建一个词典。 学习算法前对句子进行标注需要词典。

    var natural =require(natural);var text =fs.readFileSync(brownCorpusFile, 'utf8');var corpus =newnatural.Corpus(text, 1);var lexicon =corpus.buildLexicon();

    下一步是创建一组规则模板,学习算法可以从这些模板模板生成转换规则。 规则模板在 PredicateMapping.js 中定义。

    var natural require('natural');var templateNames = [
     "NEXT-TAG",
     "NEXT-WORD-IS-CAP",
     "PREV-1-OR-2-OR-3-TAG",
     "...",
    ];var templates =templateNames.map(function(name) {
     returnnewnatural.RuleTemplate(name);
    });

    使用词汇表和规则模板,我们现在可以启动训练器。

    var natural require('natural');var Tester =require('natural.BrillPOSTrainer');var trainer =newTrainer(/* optional threshold */);var ruleSet =trainer.train(corpus, templates, lexicon);

    可以将阈值传递给构造函数。 带有分数 below的转换规则在训练后删除阈值。 方法返回一组转换规则,这些规则可以用于像通常那样创建一个 tagger。 也可以输出正确格式的规则集以便以后使用。

    console.log(ruleSet.prettyPrint());

    测试

    现在我们可以将字典和规则集应用到测试集。

    var tester =newnatural.BrillPOSTester();var tagger =newnatural.BrillPOSTagger(lexicon, ruleSet);var scores =tester.test(corpora[1], tagger);

    测试方法返回两个百分比的array: 第一个百分比是标签后标签标签的比例;第二个百分比是应用转换规则后的右标签比例。

    console.log("Test score lexicon "+ scores[0] +"%");console.log("Test score after applying rules "+ scores[1] +"%");

    确认和引用

    插件开发

    开发时,请:

    • 编写单元测试
    • 确保你的单元测试通过

    单元测试的当前配置需要设置以下环境变量:

    
    export NODE_PATH=.
    
    
    
    

    许可证

    版权( c ) 2011,2012 Chris Umbel,Rob Ellis,Russell Mull

    若要在取得该软件副本时免费授予任何人,如有下列条件的软件,请免费授予该软件的副本,并与相关的文档文件("软件") 进行许可,包括不受限制的权利,包括以下条件:

    上述版权声明和本许可声明须包括在所有的副本或实质性部分的软件。

    软件是"是",没有任何保证,表示或者隐含,包括但不限于销售,适合特定用途和 NONINFRINGEMENT。 作者或者版权持有人在合同。侵权或者它的他与软件或者它的他用户交易的行为。

    许可许可证

    这里许可证可以作为文件许可证在任何已经下载的WordNet版本中使用。 WordNet 3.0许可证:( 下载)

    WordNet发布 3.0这里软件和数据库被普林斯顿大学提供,被许可人在下列许可下。 通过获取。使用和复制这里软件和数据库,你同意你已经阅读。理解和符合这些条款。 如果软件和数据库均符合下列版权声明,数据库和文档,包括你对内部使用或者分发的修改,则允许使用。复制。修改和分发这里软件和数据库及其文档,并提供相应的许可。 Princeton大学版权所有 3.0版权 2006. 保留所有权利。本软件和数据库提供"是"和普林斯顿大学没有表示或者担保,明示或者暗示。 PRINCETON大学没有任何特定用途或者许可,不会侵犯任何第三方专利。版权。商标或者其他权利,也不会侵犯任何第三方专利。版权或者其他权利。 普林斯森大学或者普林斯顿的NAME 可以能不会用于广告或者宣传软件和/或者数据库的分发。 本软件版权。数据库和任何相关文档的标题应随时保留在斯斯林大学。


    相关文章