NW.NGramTextClassification 4.2.1

dotnet add package NW.NGramTextClassification --version 4.2.1
                    
NuGet\Install-Package NW.NGramTextClassification -Version 4.2.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="NW.NGramTextClassification" Version="4.2.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="NW.NGramTextClassification" Version="4.2.1" />
                    
Directory.Packages.props
<PackageReference Include="NW.NGramTextClassification" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add NW.NGramTextClassification --version 4.2.1
                    
#r "nuget: NW.NGramTextClassification, 4.2.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package NW.NGramTextClassification@4.2.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=NW.NGramTextClassification&version=4.2.1
                    
Install as a Cake Addin
#tool nuget:?package=NW.NGramTextClassification&version=4.2.1
                    
Install as a Cake Tool

NW.NGramTextClassification

NW.NGramTextClassification is a library to perform text classification tasks on the text snippets you provide.

Getting Started

If /home/nw.ngramtextclassification is the folder in which the .nupkg file is located, you can install it using this command:

dotnet add package NW.NGramTextClassification --source /home/nw.ngramtextclassification

How Text Classification Works

Text Classification is a machine learning technique that calculates the similarity between the string of text you need to categorize and a collection of already categorized strings you provide to the library to learn from it.

Every string of text is decomposed in collections of n-grams and compared by using a similarity calculator. A n-gram is a contiguous sequence of n words, where n can be equal to 1 (monogram), 2 (bigram), 3 (trigram) and so on.

A Text Classification library can be very useful for the resolution of many problems, such as spam detection or language detection in an automated environment.

Text Classification And Language Detection

We have several strings of text and we want to detect their language.

We do know beforehand that these strings of text can be among three different languages, and we do have a batch of pre-labeled strings for each of them, but nothing more than that.

To perform the task above you need only few lines of code:

using System;
using System.Collections.Generic;
using NW.NGramTextClassification;
using NW.NGramTextClassification.LabeledExamples;
using NW.NGramTextClassification.TextClassifications;
using NW.NGramTextClassification.TextSnippets;

...

TextSnippet textSnippet 
    = new TextSnippet(
        text: "We are looking for several skilled and driven developers to join our team.");
List<LabeledExample> labeledExamples = CreateLabeledExamples();

ITextClassifier textClassifier = new TextClassifier();
TextClassifierSession session = textClassifier.ClassifyOrDefault(textSnippet, labeledExamples);

Console.WriteLine(session.Results[0].Label);

The entry point of the library (TextClassifier) offers a quite self-explanatory ClassifyOrDefault method.

The textSnippet object contains the string of text that we need to categorize, while the labeledExamples is a collection of strings that already have a label associated to them and that we will use to train the library.

Here how labeledExamples is getting populated (strings are truncated at [...] for a readibility purpose):

private static List<LabeledExample> CreateLabeledExamples()
{

    List<LabeledExample> labeledExamples = new List<LabeledExample>()
    {

        new LabeledExample(
            label: "en", 
            text: "VerksamhetsbeskrivningGoGift is a company which focuses on [...]"),
        new LabeledExample(
            label: "en", 
            text: "You will report to the Team Manager. You will get the opportunity [...]"),
        ...
        new LabeledExample(
            label: "sv", 
            text: "Conic Restaurants AB äger och driver idag SUBWAY restauranger [...]"),
        new LabeledExample(
            label: "sv", 
            text: "Du ska vara noggrann, van vid att ta eget ansvar och gilla att [...]"),
        ...
        new LabeledExample(
            label: "dk", 
            text: "Har du lyst til et nært samarbejde med kolleger i en klinik [...]"),
        new LabeledExample(
            label: "dk", 
            text: "Lægesekretær/SOSU-assistent 20-25 timer ugentligt til almen [...]"),
        ...

    };

    return labeledExamples;

}

Once you have both textSnippet and labeledExamples variables properly set, you can initialize a TextClassifier object and call its ClassifyOrDefault method.

Apart from Label, the TextClassifierResult object contains some diagnostic information, which we can use to improve the accuracy of the classsification.

Here how the TextClassifierResult class definition looks like:

public class TextClassifierResult
{

    public string Label { get; }
    public List<SimilarityIndex> SimilarityIndexes { get; }
    public List<SimilarityIndexAverage> SimilarityIndexAverages { get; }
    ...
}

The core logic of the ClassifyOrDefault method is the following one (some logging statements have been removed for readibility purpose):

private TextClassifierResult CreateResult(
    List<INGram> nGrams, 
    List<TokenizedExample> tokenizedExamples)
{

    List<SimilarityIndex> indexes = GetSimilarityIndexes(nGrams, tokenizedExamples);
    List<SimilarityIndexAverage> indexAverages = GetSimilarityIndexAverages(indexes);

    string label = GetLabel(indexAverages);
    _components.LoggingAction.Invoke(
        MessageCollection.TextClassifier_PredictedLabelIs(label));

    if (label == null)
        _components.LoggingAction.Invoke(
            MessageCollection.TextClassifier_PredictionHasFailedTryIncreasingTheAmountOfProvidedLabeledExamples);
    else
        _components.LoggingAction.Invoke(
            MessageCollection.TextClassifier_PredictionHasBeenSuccessful);

    TextClassifierResult result = new TextClassifierResult(label, indexes, indexAverages);

    return result;

} 

The content of the textSnippet variable gets tokenized into a collection of INGrams, and each of them is compared to the provided collection of LabeledExamples.

The outcome is a collection of SimilarityIndexes, which looks like:

Id Label Value
1 en 0,01995
2 en 0,014888
... ... ...
11 sv 0,002268
12 sv 0
... ... ...
21 dk 0,005025
22 dk 0
... ... ...

All these values need to be averaged, so that we have one average value for each label:

Label Value
en 0,016777
sv 0,000942
dk 0,003026

The GetLabel method will run this collection of SimilarityIndexAverage objects thru a bunch of strategies, and eventually return the label with the highest average value (highest similarity), which in this case is en.

The ClassifyOrDefault method can return:

  • a TextClassifierResult object containing the presumed label
  • a TextClassifierResult object containing a null label.

The TextClassifierResult object is contained into a TextClassifierSession object, which contains additional information about the classification process.

The TextClassifierSession class definition looks like:

public class TextClassifierSession
{

    public double MinimumAccuracySingleLabel { get; }
    public double MinimumAccuracyMultipleLabels { get; }
    public List<TextClassifierResult> Results { get; }
    public string Version { get; }
    ...

}

The Tokenizazion Process

The library component responsible for the tokenization process is NGramTokenizer and it requires a NGramTokenizerRuleSet in order to create a collection of INGram objects our of whatever string of text.

A NGramTokenizerRuleSet looks like the following:

INGramTokenizerRuleSet nGramTokenizerRuleSet 
    = new NGramTokenizerRuleSet(
            doForMonogram: true, 
            doForBigram: true, 
            doForTrigram: true, 
            doForFourgram: false, 
            doForFivegram: false
        );

If your textSnippet is "We are looking for several skilled and driven developers to join our team.", the NGramTokenizerRuleSet above will generate the following collection of INGram objects:

List<INGram> nGrams = new List<INGram>() {

    new Monogram("we"),
    new Monogram("are"),
    new Monogram("looking"),
    new Monogram("for"),
    new Monogram("several"),
    new Monogram("skilled"),
    new Monogram("and"),
    new Monogram("driven"),
    new Monogram("developers"),
    new Monogram("to"),
    new Monogram("join"),
    new Monogram("our"),
    new Monogram("team"),
    new Bigram("we are"),
    new Bigram("are looking"),
    new Bigram("looking for"),
    new Bigram("for several"),
    new Bigram("several skilled"),
    new Bigram("skilled and"),
    new Bigram("and driven"),
    new Bigram("driven developers"),
    new Bigram("developers to"),
    new Bigram("to join"),
    new Bigram("join our"),
    new Bigram("our team"),
    new Bigram("team"),
    new Trigram("we are looking"),
    new Trigram("are looking for"),
    new Trigram("looking for several"),
    new Trigram("for several skilled"),
    new Trigram("several skilled and"),
    new Trigram("skilled and driven"),
    new Trigram("and driven developers"),
    new Trigram("driven developers to"),
    new Trigram("developers to join"),
    new Trigram("to join our"),
    new Trigram("join our team"),
    new Trigram("our team"),
    new Trigram("team")

};

Side note: one of the two constructors in the NGramTokenizerRuleSet class is decorated with the [JsonConstructor] attribute because otherwise System.Text.Json.JsonSerializer would use the default constructor to perform the serialization:

[JsonConstructor] 
public NGramTokenizerRuleSet(
    bool doForMonogram, 
    bool doForBigram, 
    bool doForTrigram, 
    bool doForFourgram, 
    bool doForFivegram)
{ ... }

How To Improve The Accuracy

The accuracy of the classification can be improved:

  1. By increasing the number of LabeledExamples for each label.
  2. By using a collection of LabeledExamples that is as closer as possible to the knowledge domain of the uncategorized text - e.g. attempting to detect the language of a piece of text about anthropology using a collection of multilingual LabeledExample objects about the same topic.
  3. Increasing the number of INGram objects - e.g. using only Monograms, Bigrams and Trigrams is good enough in most common scenarios, but Fourgrams and Fivegrams are also available in the library.

License

MIT

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
4.2.1 87 7/19/2026
4.2.0 319 2/14/2024
4.1.0 267 2/12/2024
4.0.0 243 2/6/2024
3.7.0 480 12/26/2022
3.6.0 484 11/8/2022
3.5.0 513 10/30/2022
3.0.0 573 9/28/2022
2.2.0 867 9/27/2021
2.1.0 523 9/26/2021
2.0.0 696 9/24/2021
1.1.0 548 5/1/2021
1.0.0 543 2/16/2021