2010-09-07 24 views
28

Comment générer un n-gramme d'une chaîne comme:génération N-gramme à partir d'une phrase

String Input="This is my car." 

Je veux générer n-grammes avec cette entrée:

Input Ngram size = 3 

sortie devrait être :

This 
is 
my 
car 

This is 
is my 
my car 

This is my 
is my car 

Donnez une idée en Java, comment l'implémenter ou si une bibliothèque est disponible pour cela. J'essaie d'utiliser this NGramTokenizer mais il donne n-gramme de séquence de caractères et je veux n-grammes de séquence de mots.

Répondre

23

Vous recherchez ShingleFilter.

Mise à jour: Le lien pointe vers la version 3.0.2. Cette classe peut être dans un package différent dans une version plus récente de Lucene.

38

Je crois que ce serait faire ce que vous voulez:

import java.util.*; 

public class Test { 

    public static List<String> ngrams(int n, String str) { 
     List<String> ngrams = new ArrayList<String>(); 
     String[] words = str.split(" "); 
     for (int i = 0; i < words.length - n + 1; i++) 
      ngrams.add(concat(words, i, i+n)); 
     return ngrams; 
    } 

    public static String concat(String[] words, int start, int end) { 
     StringBuilder sb = new StringBuilder(); 
     for (int i = start; i < end; i++) 
      sb.append((i > start ? " " : "") + words[i]); 
     return sb.toString(); 
    } 

    public static void main(String[] args) { 
     for (int n = 1; n <= 3; n++) { 
      for (String ngram : ngrams(n, "This is my car.")) 
       System.out.println(ngram); 
      System.out.println(); 
     } 
    } 
} 

Sortie:

This 
is 
my 
car. 

This is 
is my 
my car. 

This is my 
is my car. 

solution Une "sur demande" mis en œuvre comme Iterator:

class NgramIterator implements Iterator<String> { 

    String[] words; 
    int pos = 0, n; 

    public NgramIterator(int n, String str) { 
     this.n = n; 
     words = str.split(" "); 
    } 

    public boolean hasNext() { 
     return pos < words.length - n + 1; 
    } 

    public String next() { 
     StringBuilder sb = new StringBuilder(); 
     for (int i = pos; i < pos + n; i++) 
      sb.append((i > pos ? " " : "") + words[i]); 
     pos++; 
     return sb.toString(); 
    } 

    public void remove() { 
     throw new UnsupportedOperationException(); 
    } 
} 
6

Ce code renvoie un tableau de toutes les chaînes de la longueur donnée:

public static String[] ngrams(String s, int len) { 
    String[] parts = s.split(" "); 
    String[] result = new String[parts.length - len + 1]; 
    for(int i = 0; i < parts.length - len + 1; i++) { 
     StringBuilder sb = new StringBuilder(); 
     for(int k = 0; k < len; k++) { 
      if(k > 0) sb.append(' '); 
      sb.append(parts[i+k]); 
     } 
     result[i] = sb.toString(); 
    } 
    return result; 
} 

Par ex

System.out.println(Arrays.toString(ngrams("This is my car", 2))); 
//--> [This is, is my, my car] 
System.out.println(Arrays.toString(ngrams("This is my car", 3))); 
//--> [This is my, is my car] 
+2

'ngrams (« Ceci est ma voiture », -3)' (désolé, pas pu résister) – wds

+0

'ngrams (" Ceci est mon voiture ", -3)' fonctionne bien. 'ngrams (" Ceci est ma voiture ", 6)' aboutit à une exception 'NegativeArraySizeException'. – aioobe

+6

Qu'attendez-vous dans ces cas? Je suggère de mettre un test au début de la méthode et retourner un tableau vide. En général, je vois peu de réponses SO avec une gestion d'erreur sophistiquée. – Landei

1
/** 
* 
* @param sentence should has at least one string 
* @param maxGramSize should be 1 at least 
* @return set of continuous word n-grams up to maxGramSize from the sentence 
*/ 
public static List<String> generateNgramsUpto(String str, int maxGramSize) { 

    List<String> sentence = Arrays.asList(str.split("[\\W+]")); 

    List<String> ngrams = new ArrayList<String>(); 
    int ngramSize = 0; 
    StringBuilder sb = null; 

    //sentence becomes ngrams 
    for (ListIterator<String> it = sentence.listIterator(); it.hasNext();) { 
     String word = (String) it.next(); 

     //1- add the word itself 
     sb = new StringBuilder(word); 
     ngrams.add(word); 
     ngramSize=1; 
     it.previous(); 

     //2- insert prevs of the word and add those too 
     while(it.hasPrevious() && ngramSize<maxGramSize){ 
      sb.insert(0,' '); 
      sb.insert(0,it.previous()); 
      ngrams.add(sb.toString()); 
      ngramSize++; 
     } 

     //go back to initial position 
     while(ngramSize>0){ 
      ngramSize--; 
      it.next(); 
     }     
    } 
    return ngrams; 
} 

Appel:

long startTime = System.currentTimeMillis(); 
ngrams = ToolSet.generateNgramsUpto("This is my car.", 3); 
long stopTime = System.currentTimeMillis(); 
System.out.println("My time = "+(stopTime-startTime)+" ms with ngramsize = "+ngrams.size()); 
System.out.println(ngrams.toString()); 

Sortie:

Mon temps = 1 ms avec ngramsize = 9 [Ceci est, Ceci est, mon, ma, ce est ma, voiture, ma voiture, ma voiture est]

1
public static void CreateNgram(ArrayList<String> list, int cutoff) { 
    try 
    { 
     NGramModel ngramModel = new NGramModel(); 
     POSModel model = new POSModelLoader().load(new File("en-pos-maxent.bin")); 
     PerformanceMonitor perfMon = new PerformanceMonitor(System.err, "sent"); 
     POSTaggerME tagger = new POSTaggerME(model); 
     perfMon.start(); 
     for(int i = 0; i<list.size(); i++) 
     { 
      String inputString = list.get(i); 
      ObjectStream<String> lineStream = new PlainTextByLineStream(new StringReader(inputString)); 
      String line; 
      while ((line = lineStream.read()) != null) 
      { 
       String whitespaceTokenizerLine[] = WhitespaceTokenizer.INSTANCE.tokenize(line); 
       String[] tags = tagger.tag(whitespaceTokenizerLine); 

       POSSample sample = new POSSample(whitespaceTokenizerLine, tags); 

       perfMon.incrementCounter(); 

       String words[] = sample.getSentence(); 

       if(words.length > 0) 
       { 
        for(int k = 2; k< 4; k++) 
        { 
         ngramModel.add(new StringList(words), k, k); 
        } 
       } 
      } 
     } 
     ngramModel.cutoff(cutoff, Integer.MAX_VALUE); 
     Iterator<StringList> it = ngramModel.iterator(); 
     while(it.hasNext()) 
     { 
      StringList strList = it.next(); 
      System.out.println(strList.toString()); 
     } 
     perfMon.stopAndPrintFinalResult(); 
    }catch(Exception e) 
    { 
     System.out.println(e.toString()); 
    } 
} 

Voici mes codes pour créer n-gramme. Dans ce cas, n = 2, 3. n-gramme de séquences de mots dont la valeur inférieure à la valeur de coupure sera ignorée à partir de l'ensemble de résultats. L'entrée est la liste des phrases, puis analyser en utilisant un outil de OpenNLP

0
public static void main(String[] args) { 

    String[] words = "This is my car.".split(" "); 
    for (int n = 0; n < 3; n++) { 

     List<String> list = ngrams(n, words); 
     for (String ngram : list) { 
      System.out.println(ngram); 
     } 
     System.out.println(); 

    } 
} 

public static List<String> ngrams(int stepSize, String[] words) { 
    List<String> ngrams = new ArrayList<String>(); 
    for (int i = 0; i < words.length-stepSize; i++) { 

     String initialWord = ""; 
     int internalCount = i; 
     int internalStepSize = i + stepSize; 
     while (internalCount <= internalStepSize 
       && internalCount < words.length) { 
      initialWord = initialWord+" " + words[internalCount]; 
      ++internalCount; 
     } 
     ngrams.add(initialWord); 

    } 
    return ngrams; 
}