2012-03-14 34 views
5

Tôi đang cố gắng tạo một trình phân loại văn bản trong JAVA với Weka. Tôi đã đọc một số hướng dẫn và tôi đang cố gắng xây dựng trình phân loại của riêng mình.Phân loại văn bản cơ bản với Weka trong Java

tôi có các loại sau:

computer,sport,unknown 

và sau dữ liệu đã được đào tạo

cs belongs to computer 
java -> computer 
soccer -> sport 
snowboard -> sport 

Vì vậy, ví dụ, nếu người dùng muốn để phân loại các java từ, nó sẽ trả về máy tính loại (không có nghi ngờ, java chỉ tồn tại trong thể loại đó!).

Nó biên dịch, nhưng tạo ra đầu ra lạ.

Đầu ra là:

 ====== RESULT ====== CLASSIFIED AS: [0.5769230769230769, 0.2884615384615385, 0.1346153846153846] 
     ====== RESULT ====== CLASSIFIED AS: [0.42857142857142855, 0.42857142857142855, 0.14285714285714285] 

Nhưng văn bản đầu tiên để phân loại là java và nó occures chỉ trong máy tính loại, do đó nó phải được

 [1.0 0.0 0.0] 

và cho người khác nó không nên được được tìm thấy ở tất cả, vì vậy nó phải được phân loại là không rõ

 [0.0 0.0 1.0]. 

Đây là mã số:

import java.io.FileNotFoundException; 
    import java.io.Serializable; 
    import java.util.Arrays; 

    import weka.classifiers.Classifier; 
    import weka.classifiers.bayes.NaiveBayesMultinomialUpdateable; 
    import weka.core.Attribute; 
    import weka.core.FastVector; 
    import weka.core.Instance; 
    import weka.core.Instances; 
    import weka.filters.Filter; 
    import weka.filters.unsupervised.attribute.StringToWordVector; 

    public class TextClassifier implements Serializable { 

     private static final long serialVersionUID = -1397598966481635120L; 
     public static void main(String[] args) { 
      try { 
       TextClassifier cl = new TextClassifier(new NaiveBayesMultinomialUpdateable()); 
       cl.addCategory("computer"); 
       cl.addCategory("sport"); 
       cl.addCategory("unknown"); 
       cl.setupAfterCategorysAdded(); 

       // 
       cl.addData("cs", "computer"); 
       cl.addData("java", "computer"); 
       cl.addData("soccer", "sport"); 
       cl.addData("snowboard", "sport"); 

       double[] result = cl.classifyMessage("java"); 
       System.out.println("====== RESULT ====== \tCLASSIFIED AS:\t" + Arrays.toString(result)); 

       result = cl.classifyMessage("asdasdasd"); 
       System.out.println("====== RESULT ======\tCLASSIFIED AS:\t" + Arrays.toString(result)); 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
     } 
     private Instances trainingData; 
     private StringToWordVector filter; 
     private Classifier classifier; 
     private boolean upToDate; 
     private FastVector classValues; 
     private FastVector attributes; 
     private boolean setup; 

     private Instances filteredData; 

     public TextClassifier(Classifier classifier) throws FileNotFoundException { 
      this(classifier, 10); 
     } 

     public TextClassifier(Classifier classifier, int startSize) throws FileNotFoundException { 
      this.filter = new StringToWordVector(); 
      this.classifier = classifier; 
      // Create vector of attributes. 
      this.attributes = new FastVector(2); 
      // Add attribute for holding texts. 
      this.attributes.addElement(new Attribute("text", (FastVector) null)); 
      // Add class attribute. 
      this.classValues = new FastVector(startSize); 
      this.setup = false; 

     } 

     public void addCategory(String category) { 
      category = category.toLowerCase(); 
      // if required, double the capacity. 
      int capacity = classValues.capacity(); 
      if (classValues.size() > (capacity - 5)) { 
       classValues.setCapacity(capacity * 2); 
      } 
      classValues.addElement(category); 
     } 

     public void addData(String message, String classValue) throws IllegalStateException { 
      if (!setup) { 
       throw new IllegalStateException("Must use setup first"); 
      } 
      message = message.toLowerCase(); 
      classValue = classValue.toLowerCase(); 
      // Make message into instance. 
      Instance instance = makeInstance(message, trainingData); 
      // Set class value for instance. 
      instance.setClassValue(classValue); 
      // Add instance to training data. 
      trainingData.add(instance); 
      upToDate = false; 
     } 

     /** 
     * Check whether classifier and filter are up to date. Build i necessary. 
     * @throws Exception 
     */ 
     private void buildIfNeeded() throws Exception { 
      if (!upToDate) { 
       // Initialize filter and tell it about the input format. 
       filter.setInputFormat(trainingData); 
       // Generate word counts from the training data. 
       filteredData = Filter.useFilter(trainingData, filter); 
       // Rebuild classifier. 
       classifier.buildClassifier(filteredData); 
       upToDate = true; 
      } 
     } 

     public double[] classifyMessage(String message) throws Exception { 
      message = message.toLowerCase(); 
      if (!setup) { 
       throw new Exception("Must use setup first"); 
      } 
      // Check whether classifier has been built. 
      if (trainingData.numInstances() == 0) { 
       throw new Exception("No classifier available."); 
      } 
      buildIfNeeded(); 
      Instances testset = trainingData.stringFreeStructure(); 
      Instance testInstance = makeInstance(message, testset); 

      // Filter instance. 
      filter.input(testInstance); 
      Instance filteredInstance = filter.output(); 
      return classifier.distributionForInstance(filteredInstance); 

     } 

     private Instance makeInstance(String text, Instances data) { 
      // Create instance of length two. 
      Instance instance = new Instance(2); 
      // Set value for message attribute 
      Attribute messageAtt = data.attribute("text"); 
      instance.setValue(messageAtt, messageAtt.addStringValue(text)); 
      // Give instance access to attribute information from the dataset. 
      instance.setDataset(data); 
      return instance; 
     } 

     public void setupAfterCategorysAdded() { 
      attributes.addElement(new Attribute("class", classValues)); 
      // Create dataset with initial capacity of 100, and set index of class. 
      trainingData = new Instances("MessageClassificationProblem", attributes, 100); 
      trainingData.setClassIndex(trainingData.numAttributes() - 1); 
      setup = true; 
     } 

    } 

Btw, tìm thấy một trang tốt:

http://www.hakank.org/weka/TextClassifierApplet3.html

Trả lời

4

Bộ phân loại Bayes cung cấp cho bạn một (trọng số) xác suất mà một từ thuộc về một thể loại. Bạn có thể thiết lập một ngưỡng cắt (ví dụ 0.5) và quyết định thành viên cho một lớp dựa trên điều này, hoặc kiểm tra xác suất được tính toán và quyết định dựa trên đó (tức là bản đồ cao nhất đến 1, thấp nhất đến 0).

+0

Vâng tôi biết điều đó. Nhưng trong ví dụ này, khi tôi cố gắng phân loại: result = cl.classifyMessage ("asdasdasd"); kết quả nên được phân loại là không xác định, nhưng không phải là:/ Nhưng, tôi có thể thấy rằng nó có thể sẽ không hoạt động. Bởi vì tôi không có bất kỳ tài liệu nào cả cho thể loại đó ... Có giải pháp thông minh nào để thêm danh mục "uknown" hay tương tự không? Và cũng với từ java, tôi nghĩ rằng nó sẽ được trọng số hơn đối với các loại máy tính, bởi vì nó thậm chí không được đề cập trong các loại khác. – joxxe

+2

Bạn sẽ phải thêm thủ công các mục vào danh mục "không xác định" nếu xác suất cho tư cách thành viên của từng lớp học của bạn quá thấp. –

+0

Nhưng xác suất với nhau luôn là 1.0. Vì vậy, nếu tôi cố gắng phân loại một số từ không tồn tại trong bất kỳ tài liệu nào, xác suất cùng nhau (cho tất cả các danh mục) vẫn là 1.0 – joxxe

0

Nếu bạn cố gắng để có được lớp dứt khoát thay vì phân phối, cố gắng chuyển

return classifier.distributionForInstance(filteredInstance);

để

return classifier.classifyInstance(filteredInstance);

+0

câu trả lời này là khó hiểu - khi bạn đăng mã, bạn nên cố gắng giải thích nó – ronalchn

+4

Vâng, nếu joxxe thử điều này trong mã của mình, ông sẽ hiểu những gì tôi có ý nghĩa. Dù sao, phương thức distributionForInstance() trả về xác suất cho mỗi lớp đích. Và phương thức classifyInstance() chọn lớp có xác suất cao nhất và trả về chỉ mục lớp. Vì vậy, tôi đoán joxxe cần phương pháp thứ hai. –

1

Tôi nghĩ rằng tôi sẽ chỉ cung cấp lên rằng bạn có thể làm như vậy nhất phân loại văn bản hoạt động mà không cần mã hóa bằng cách chỉ cần tải xuống và sử dụng LightSIDE từ http://lightsidelabs.com. Gói Java mã nguồn mở này bao gồm WEKA và có sẵn cho các bản phân phối trên cả Windows và Mac - có thể xử lý hầu hết các bộ dữ liệu thân thiện với WEKA với tính linh hoạt cao, cho phép bạn lặp qua các mô hình, cài đặt và tham số khác nhau. lưu dữ liệu và mô hình của bạn và kết quả phân loại vào bất kỳ thời điểm nào cho đến khi bạn xây dựng mô hình mà bạn hài lòng. Sản phẩm này đã chứng minh chính nó trong cuộc thi ASAP trên Kaggle.com năm ngoái, và đang nhận được rất nhiều lực kéo. Tất nhiên luôn luôn có những lý do mọi người muốn hoặc cần phải "cuộn của riêng mình" nhưng có lẽ ngay cả khi kiểm tra, biết và sử dụng LightSIDE nếu bạn đang lập trình các giải pháp WEKA có thể rất tiện dụng.

Các vấn đề liên quan