dataMining.KMeans.java Source code

Java tutorial

Introduction

Here is the source code for dataMining.KMeans.java

Source

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package dataMining;

import couchdb.PrepareData;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Random;
import weka.core.Instance;
import weka.core.Instances;
import weka.core.converters.ArffLoader;

/**
 *
 * @author Mateusz lzak
 */
public class KMeans {

    /**
     * Pole przechowujce wczytane dane
     */
    private Instances dataSet;

    /**
     * Mapa przechowujca grupy z ich rodkami w postaci klucz - rodek warto
     * - elementy grupy
     */
    private HashMap<Instance, ArrayList<Instance>> groups;

    /**
     * Pole przechowujce liczb grup
     */
    private int countOfGroups;

    /**
     * Konstruktor klasy. Wczytuje dane oraz losuje pocztkowe rodki grup.
     *
     * @param nameData nazwa bazy
     * @param countGroups ilo grup
     */
    public KMeans(String nameData, int countGroups) {
        PrepareData pd = new PrepareData(nameData);
        dataSet = pd.getDataForWeka();
        countOfGroups = countGroups;
        createGroups();
    }

    /**
     * Metoda do wczytywania danych do programu.
     */
    @Deprecated
    private void openFile() {
        try {
            ArffLoader loader = new ArffLoader();
            loader.setFile(new File(""));
            dataSet = loader.getDataSet();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * Gwna metoda klasy. Operacje wykonuj si w ptli while. Warunkiem
     * wyjcia z ptli jest dwukrotne z rzdu wyznaczenie takich samych
     * wsprzdnych rodka grupy. Pierwszy etap wykonywany w ptli to
     * przyporzdkowanie obiektw do grup, w zalenoci od tego, do ktrego
     * rodka jest najbliej. Nastpnie wyznaczny jest nowy rodek grup jako
     * rednia arytmetyczna kolejnych wsprzdnych obiektw nalecych do
     * grupy. Jeli wszystkie grupy nie zmieniy swoich rodkw to nastpuje
     * wyjcie z ptli, w przeciwnym wypadku ptla wkonuje si ponownie. Jeli
     * ptla wykonaa si 1000 razy rwnie zostanie zatrzymana. Wwczas zostan
     * przekazane grupy stworzone w ostatniej iteracji.
     *
     * @return Wynik grupowania.
     */
    public String reviewData() {

        boolean working = true;
        int tmp = 0;
        int checkPoint = 0;
        int countTheSame = 0;
        int isLooped = 0;
        while (working) {
            for (int i = 0; i < dataSet.numInstances(); i++) {
                Instance ins = dataSet.instance(i);
                findGroup(ins);
            }
            ArrayList<Instance> listOfNewMeans = makeNewMeans();
            for (Instance i : groups.keySet()) {
                if (equals(i, listOfNewMeans.get(checkPoint))) {
                    countTheSame++;
                }
                checkPoint++;
            }
            if (checkPoint == countTheSame || isLooped > 1000) {
                working = false;
            } else {

                checkPoint = 0;
                countTheSame = 0;
                groups = new HashMap<>();
                for (Instance in : listOfNewMeans) {
                    groups.put(in, new ArrayList<>());
                }
            }
            isLooped++;
        }
        String s = "";
        if (!working && tmp == 0) {
            int i = 1;

            for (Instance instance : groups.keySet()) {
                ArrayList<Instance> list = groups.get(instance);
                s = s + "**************************************************\n";
                s = s + "Grupa: " + i + "\n";
                s = s + "Liczba elementw w grupie: " + list.size() + "\n";
                s = s + "rodek grupy: " + instance.toString() + "\n";
                s = s + "Elementy grupy: \n";
                for (Instance ins : list) {
                    s = s + ins.toString() + "\n";
                }
                s = s + "\n";
                i++;

            }
        }

        return s;

    }

    /**
     * Metoda do sprawdzania czy instancje podane jako parametr s takie same.
     *
     * @param insA piewrsza instanca
     * @param insB druga instancja
     * @return True, jeli s takie same, false w przeciwnym wypadku.
     */
    private boolean equals(Instance insA, Instance insB) {
        if (insA.numAttributes() != insB.numAttributes()) {
            throw new NullPointerException("Rna liczba atrybutw");
        } else {
            int countTheSame = 0;
            for (int i = 0; i < insA.numAttributes(); i++) {
                double a = 0;
                double b = 0;
                try {
                    a = Double.parseDouble(insA.toString(i));
                } catch (NumberFormatException ex) {
                    a = 0;
                }
                try {
                    b = Double.parseDouble(insB.toString(i));
                } catch (NumberFormatException ex) {
                    b = 0;
                }
                if (Math.abs(a - b) == 0) {
                    countTheSame++;
                }

            }
            int countAttr = insB.numAttributes();

            if (countTheSame == countAttr) {
                return true;
            } else {
                return false;
            }

        }

    }

    /**
     * Metoda, ktra przyporzdkowuje obiekt podany jako parametr do grupy,
     * ktrej rodek jest najbliej.
     *
     * @param ins obiekt, ktry ma by przypisany do grupy.
     */
    private void findGroup(Instance ins) {
        ArrayList<Double> list = new ArrayList<>();
        for (Instance instance : groups.keySet()) {
            list.add(euclid(ins, instance));
        }
        double min = list.get(0);
        for (Double d : list) {
            if (min > d) {
                min = d;
            }
        }
        for (Instance instance : groups.keySet()) {
            if (euclid(ins, instance) == min) {
                ArrayList<Instance> listOfInstances = groups.get(instance);
                listOfInstances.add(ins);
                groups.replace(instance, listOfInstances);

            }
        }
    }

    /**
     * Metoda do wyznaczania nowych rodkw grup.
     *
     * @return lista zawierajca nowe rodki.
     */
    private ArrayList<Instance> makeNewMeans() {
        ArrayList<Instance> listOfMeans = new ArrayList<>();
        for (Instance i : groups.keySet()) {
            ArrayList<Instance> list = groups.get(i);
            double[] tab = new double[i.numAttributes()];
            for (Instance in : list) {
                for (int j = 0; j < tab.length; j++) {
                    double d = 0;
                    try {
                        d = Double.parseDouble(in.toString(j));
                    } catch (NumberFormatException ex) {
                        d = 0;
                    }
                    tab[j] = tab[j] + d;
                }
            }
            for (int j = 0; j < tab.length; j++) {
                tab[j] = tab[j] / list.size();
            }
            Instance ins = new Instance(tab.length);
            for (int j = 0; j < tab.length; j++) {
                ins.setValue(j, tab[j]);
            }
            listOfMeans.add(ins);
        }
        return listOfMeans;
    }

    /**
     * Metoda do wyznaczania odlegoci pomiedzy obiektami podanymi jako
     * parametr. Odlego liczona metryk Euklidesow.
     *
     * @param a pierwszy obiekt
     * @param b drugi obiekt
     * @return Odlego pomidzy obiektami.
     */
    private double euclid(Instance a, Instance b) {
        float sum = 0;
        float attrA = 0;
        float attrB = 0;
        for (int i = 0; i < a.numAttributes(); i++) {
            try {
                attrA = Float.parseFloat(a.toString(i));
            } catch (NumberFormatException ex) {
                attrA = 0;
            }
            try {
                attrB = Float.parseFloat(b.toString(i));
            } catch (NumberFormatException ex) {
                attrB = 0;
            }

            float d = attrA - attrB;
            sum = sum + d * d;
        }
        return Math.sqrt(sum);
    }

    /**
     * Metoda wywoana w konstruktrze. Z pocztkowego zbioru danych losuje
     * obiekty, ktre na pocztku bd rodkami i ustawia je jako klucze w
     * mapie, ktra przechowuje grupy.
     */
    private void createGroups() {
        groups = new HashMap<>();
        int countGroups = countOfGroups;
        int countInstances = dataSet.numInstances();
        Random r = new Random();
        while (countGroups > 0) {
            groups.put(dataSet.instance(r.nextInt(countInstances + 1)), new ArrayList<>());
            countGroups--;
        }
    }
}