Java tutorial
/* * 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--; } } }