Ci-Bayes kategorizáló bővítése visszavonás funkcióval

Posted by | · · | Szoftverfejlesztés | Nincs hozzászólás a(z) Ci-Bayes kategorizáló bővítése visszavonás funkcióval bejegyzéshez

A CI-Bayes egy Java könyvtár, amely szöveg osztályozásra alkalmas. A könyvtár használatát nagyon jól bemutatja Joseph Ottinger Using CI-Bayes című cikkében.

A cikkben Joseph Ottinger a 1.0.4 verziót mutatja be, ezzel szemben én a 2.0.0.RELEASE verziót használtam (az api-ban nem érzékeltem különbséget).

A CI-Bayes könyvtár elérhető a Maven repository-ban: CI-Bayes maven repository.

A probléma

Olyan dokumentum tárat szeretnénk készíteni, melyben a felhasználók előre definiált kategóriákba sorolhatják a dokumentumokat, illetve törölhetik dokumentumhoz rendelt kategóriákat. A cél, hogy a rendszer ezen visszajelzések alapján tanuljon és ezen ismereteket fel tudja használni automatikus kategorizálásra.

A nehézség a dokumentumhoz rendelt kategória törlésében rejlik, hisz ez azt vonja magával, hogy a kategorizáló rendszerből – a kategóriára vonatkozó megtanult ismeretből – ki kellene venni az adott dokumentum hozzájárulását. A CI-Bayes api ezt sajnálatosan nem támogatja.

Az ötlet

Mivel a törlés funkcióra szükség volt, elkezdtem nézegetni a CI-Bayes forráskódját, kikutatni, hogy hogyan is működik a tanulás. A tanulásért a com.enigmastation.classifier.impl.ClassifierImpl.train(Object item, String category) metódus felelős, ahol az item a dokumentum szövege, a category pedig azon kategória, amelybe egy felhasználó sorolta az adott dokumentumot. A train() metódus implementációja a következő:


public void train(Object item, String category) {
    Set<String> features = wordLister.getUniqueWords(item);

    for (String f : features) {
        incf(f, category);
    }
    incc(category);
}

Ezen algoritmus a következőt teszi:

  • a szövegből kiszedi a különböző szavakat
  • az adott kategória tudástárába felveszi a dokumentum azon szavait, melyek még nem szerepeltek benne (ezek számossága egy lesz), illetve meglevő szavak számosságát növeli eggyel
  • a tudásbázisba felveszi az adott kategóriát, ha még nem létezett (ekkor a kategória számossága egy lesz), egyébként meg növeli a kategória számosságát

A tanítás csupán ennyi. Egy dokumentum kategóriába sorolása pedig ezen megszerzett ismeret felhasználásával történik. A CI-Bayes könyvtár három Bayesian osztályozót szolgáltat ehhez: a “simple Bayesian” classifiert, a naïve classifiert, és – a leghasznosabb – a Fisher classifiert.

Mint fent láthattuk, az osztályozó tanítása számlálók inkrementálásával történik, így a számlálók dekrementálásával visszavonható a megtanult ismeret.

A megvalósítás

Az osztályozónak megtanított ismeret (adott dokumentum adott kategóriába tartozik) visszavonására implementáltam egy revokeTrain(Object item, String category) metódust a train(Object item, String category) metódus mintájára:

  • a szövegből kiszedi a különböző szavakat
  • az adott kategória tudástárában csökkenti azon szavak számosságát, amelyek a dokumentumban szerepeltek, és amennyiben valamely szó számossága lecsökken nullára, akkor törli a szót a tudástárból
  • a tudásbázisban csökkenti az adott kategória számosságát, és ha a számosság lecsökken nullára, akkor törli a kategóriát a tudásbázisból.

A megvalósításhoz leszármaztattam a com.enigmastation.classifier.impl.FisherClassifierImpl osztályt (de természetesen lehet a NaiveClassifierImpl-ből, vagy a ClassifierImpl-ből is származtatni, ki melyiket kívánja használni).

Az implementációm a következő:


import com.enigmastation.classifier.CategoryIncrement;
import com.enigmastation.classifier.ClassifierListener;
import com.enigmastation.classifier.ClassifierProbability;
import com.enigmastation.classifier.FeatureIncrement;
import com.enigmastation.classifier.impl.FisherClassifierImpl;
import com.google.common.collect.Sets;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Map;
import java.util.Set;

public class MyFisherClassifier extends FisherClassifierImpl {

    private Set<ClassifierListener> trainingListeners;

    @Override
    public void addListener(ClassifierListener listener) {
        super.addListener(listener);
        if (trainingListeners == null) {
            trainingListeners = Sets.newHashSet();
        }
        trainingListeners.add(listener);
    }

    public void revokeTrain(Object item, String category) {
        Set<String> features = wordLister.getUniqueWords(item);

        for (String feature : features) {
            decf(feature, category);
        }
        decc(category);
    }

    void decf(String feature, String category) {
        Map<String, Integer> fm = getClassifierDataModelFactory().getFeatureMap(feature);
        if (fm == null) {
            throw new IllegalStateException("You must be able to create a feature map");
        }

        decrementCategory(fm, category);

        final Integer count = fm.get(category);

        if (trainingListeners != null) {
            FeatureIncrement fi = new FeatureIncrement(feature, category, count);
            for (ClassifierListener listener : trainingListeners) {
                listener.handleFeatureUpdate(fi);
            }
        }

        if (count == 0) {
            fm.remove(category);
        }
    }

    void decc(String category) {
        decrementCategory(getCategoryDocCount(), category);

        final Integer categoryDocCount = getCategoryDocCount().get(category);

        if (trainingListeners != null) {
            CategoryIncrement ci = new CategoryIncrement(category, categoryDocCount);
            for (ClassifierListener listener : trainingListeners) {
                listener.handleCategoryUpdate(ci);
            }
        }

        if (categoryDocCount == 0) {
            getCategoryDocCount().remove(category);
        }
    }

    private void decrementCategory(Map<String, Integer> map, String category) {
        Integer val = map.get(category);
        if (val != null) {
            map.put(category, val - 1);
        } else {
            map.put(category, 1);
        }
    }
}

 

 

Hasznos anyagok

What is Text Classification- Stanford NLP

Naive Bayes – Stanford NLP

Naive Bayes classifier

CI-Bayes


No Comments

Leave a comment