/* *Copyright 2007, 2011 CCLS Columbia University (USA), LIFO University of Orl��ans (France), BRGM (France) * *Authors: Cyril Nortet, Xiangrong Kong, Ansaf Salleb-Aouissi, Christel Vrain, Daniel Cassard * *This file is part of QuantMiner. * *QuantMiner is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version. * *QuantMiner is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. * *You should have received a copy of the GNU General Public License along with QuantMiner. If not, see <http://www.gnu.org/licenses/>. */ package src.apriori; import java.sql.*; import java.util.*; import java.util.*; import src.database.*; import src.solver.*; public class AprioriQuantitative { ArrayList m_listeAttributsQual = null; ArrayList m_listeAttributsQuant = null; TableItems m_tableItems = null; ArrayList m_listeListeItemSets = null; public DatabaseAdmin m_gestionnaireBD = null; private ResolutionContext m_contexteResolution = null; float m_fMinSupp = 0.0f; int m_iNombreTransactions = 0; // Classe de base permettant l'ex�cution d'un code particulier pendant la g�n�ration des itemsets : static public class TraitementExternePendantCalcul { // Renvoie faux si le traitement externe demande l'arr�t des calculs : public boolean ExecuterTraitementExterne() { return true; } } TraitementExternePendantCalcul m_traitementExterne = null; public AprioriQuantitative(ResolutionContext contexteResolution) { m_listeAttributsQual = new ArrayList(); m_listeAttributsQuant = new ArrayList(); m_tableItems = new TableItems(); m_listeListeItemSets = new ArrayList(); m_fMinSupp = 0.0f; m_iNombreTransactions = 0; m_traitementExterne = null; m_contexteResolution = contexteResolution; if (m_contexteResolution != null) m_gestionnaireBD = m_contexteResolution.m_gestionnaireBD; } /** specify external treatment * @param traitementExterne External Treatment For Calculating */ public void SpecifierTraitementExterne(TraitementExternePendantCalcul traitementExterne) { m_traitementExterne = traitementExterne; } /** * Run Pretreatment * @param bGenererItemSetsSingletons */ public void ExecuterPretraitement(boolean bGenererItemSetsSingletons) { int iNombreAttributsQual = 0; int iIndiceAttributQual = 0; int iNombreColonnes = 0; int iIndiceColonne = 0; int iTypePriseEnCompte = 0; AttributQualitative attributQual = null; AttributQuantitative attributQuant = null; DataColumn colonneDonnees = null; m_iNombreTransactions = m_gestionnaireBD.ObtenirNombreLignes(); //obtain the number of lines iNombreColonnes = m_gestionnaireBD.ObtenirNombreColonnesPrisesEnCompte(); //obtain the number of selected columns?? for (iIndiceColonne = 0; iIndiceColonne < iNombreColonnes; iIndiceColonne++) { colonneDonnees = m_gestionnaireBD.ObtenirColonneBDPriseEnCompte(iIndiceColonne); iTypePriseEnCompte = m_contexteResolution.ObtenirTypePrisEnCompteAttribut(colonneDonnees.m_sNomColonne); switch ( colonneDonnees.m_iTypeValeurs) { case DatabaseAdmin.TYPE_VALEURS_COLONNE_ITEM : //add categorical attribute to categorical list if (iTypePriseEnCompte != ResolutionContext.PRISE_EN_COMPTE_ITEM_NULLE_PART) { attributQual = new AttributQualitative( colonneDonnees.m_sNomColonne, colonneDonnees ); m_listeAttributsQual.add(attributQual); } break; case DatabaseAdmin.TYPE_VALEURS_COLONNE_REEL : //add quantitative attribute to categorical list if (iTypePriseEnCompte != ResolutionContext.PRISE_EN_COMPTE_ITEM_NULLE_PART) { attributQuant = new AttributQuantitative( colonneDonnees.m_sNomColonne, colonneDonnees ); m_listeAttributsQuant.add(attributQuant); } break; } } iNombreAttributsQual = m_listeAttributsQual.size(); iIndiceAttributQual = 0; for (iIndiceAttributQual = 0; iIndiceAttributQual < iNombreAttributsQual; iIndiceAttributQual++) { attributQual = (AttributQualitative)m_listeAttributsQual.get(iIndiceAttributQual); attributQual.GenererItems(m_tableItems); } if (bGenererItemSetsSingletons) GenererNouvelleListeItemSets(); //generate new itemset list } /** * Calculate Distribution Items * @param iIndiceRepartition Index Distribution * @param iNombreItems Number of Items * @return */ public static boolean [] CalculerRepartitionItems(int iIndiceRepartition, int iNombreItems) { boolean [] tRepartitionItems = null; int iIndiceItem = 0; int iIndiceMaxPourItem = 0; int iNombreItemsRestants = 0; boolean bTestPremierItem = true; // Vrai tant qu'on peut contruire l'ensemble contenant tous les attributs, qu'il faut prendre garde d'�liminer if (iNombreItems==0) return null; tRepartitionItems = new boolean [iNombreItems]; Arrays.fill(tRepartitionItems, false); iNombreItemsRestants = iNombreItems; iIndiceItem = 0; bTestPremierItem = true; while (iIndiceItem<iNombreItems) { iIndiceMaxPourItem = 1 << (iNombreItems - iIndiceItem - 1); if (bTestPremierItem) iIndiceMaxPourItem--; if (iIndiceRepartition==0) { tRepartitionItems[iIndiceItem] = true; iNombreItemsRestants--; iIndiceItem = iNombreItems; // Pour provoquer la fin de l'algo } else if (iIndiceRepartition<iIndiceMaxPourItem) { tRepartitionItems[iIndiceItem] = true; iNombreItemsRestants--; iIndiceRepartition--; } else { iIndiceRepartition -= iIndiceMaxPourItem; bTestPremierItem = false; } iIndiceItem++; } if (iNombreItemsRestants==iNombreItems) return null; else return tRepartitionItems; } // Calcule tous les ensembles d'items possibles, chaque ensemble �tant constitu� de 'iNombrePlaces' �l�ments // (renvoie un tableau indiquant la pr�sence ou non du i-�me item dans l'ensemble) : /** * Calculate Sets Items * @param iIndiceRepartition Index Distribution * @param iNombreItems Number of items * @param iNombrePlaces Number of places */ public static boolean [] CalculerEnsemblesItems(int iIndiceRepartition, int iNombreItems, int iNombrePlaces) { boolean [] tRepartitionItems = null; boolean bItemAffecte = false; int iIndiceItem = 0; int iNombreItemsRestants = 0; int iNombrePlacesRestantes = 0; int iCompteur = 0; int factN = 0, factP = 0, factN_P = 0, iCNP = 0; // Variables d�di�es au calcul des combinaisons de p valeurs parmi n if (iNombreItems==0) return null; tRepartitionItems = new boolean [iNombreItems]; Arrays.fill(tRepartitionItems, false); iIndiceItem = 0; iNombreItemsRestants = iNombreItems; iNombrePlacesRestantes = iNombrePlaces; while ( (iNombrePlacesRestantes>0) && (iNombreItemsRestants>=iNombrePlacesRestantes) && (iIndiceItem<iNombreItems) ) { if (iNombreItemsRestants>iNombrePlacesRestantes) { factN = factP = factN_P = 1; for (iCompteur=2;iCompteur<iNombreItemsRestants;iCompteur++) factN *= iCompteur; for (iCompteur=2;iCompteur<iNombrePlacesRestantes;iCompteur++) factP *= iCompteur; for (iCompteur=2;iCompteur<=(iNombreItemsRestants-iNombrePlacesRestantes);iCompteur++) factN_P *= iCompteur; iCNP = factN / (factP * factN_P); } // Sinon cas iNombreItemsRestants == iNombrePlacesRestantes : else iCNP = 1; if (iIndiceRepartition < iCNP) { tRepartitionItems[ iIndiceItem ] = true; iNombrePlacesRestantes--; } else iIndiceRepartition -= iCNP; iIndiceItem++; iNombreItemsRestants--; } if (iNombrePlacesRestantes==iNombrePlaces) return null; else return tRepartitionItems; } /** set minimum support * @param fMinSupp Minimum Support value */ public void SpecifierSupportMinimal(float fMinSupp) { m_fMinSupp = fMinSupp; } public float ObtenirSupportMinimal() { return m_fMinSupp; } /**Write Frequents List*/ public String EcrireListeFrequents() { String sTexteListeFrequents = null; int iTailleMaxItemSets = 0; int iIndiceListesItemSets = 0; int iNombreItemSets = 0; int iIndiceItemSet = 0; ArrayList listeItemSets = null; ItemSet itemset = null; sTexteListeFrequents = ""; iTailleMaxItemSets = m_listeListeItemSets.size(); for (iIndiceListesItemSets=0; iIndiceListesItemSets<iTailleMaxItemSets; iIndiceListesItemSets++) { listeItemSets = (ArrayList)m_listeListeItemSets.get(iIndiceListesItemSets); iNombreItemSets = listeItemSets.size(); for (iIndiceItemSet=0; iIndiceItemSet<iNombreItemSets; iIndiceItemSet++) { itemset = (ItemSet)listeItemSets.get(iIndiceItemSet); if ( itemset.m_iSupport >= (int)(m_fMinSupp*(float)m_iNombreTransactions) ) { sTexteListeFrequents += itemset.EcrireItemSet(m_iNombreTransactions, true); sTexteListeFrequents += "\n"; } } if (iNombreItemSets > 0) sTexteListeFrequents += "\n"; } return sTexteListeFrequents; } /** * Remove Not Frequent Sets * @param iIndiceListe index of the ListItemSet */ void RetirerNonFrequentsDeListeItemSets(int iIndiceListe) { ArrayList listeItemSets = null; ArrayList listeItemSetsTemp = null; ItemSet itemSet = null; int iIndiceItemSet = 0; int iNombreItemSets = 0; listeItemSets = (ArrayList)m_listeListeItemSets.get(iIndiceListe); listeItemSetsTemp = new ArrayList(); iNombreItemSets = listeItemSets.size(); for (iIndiceItemSet=0; iIndiceItemSet<iNombreItemSets; iIndiceItemSet++) { itemSet = (ItemSet)listeItemSets.get(iIndiceItemSet); // On ne conserve que les itemSets fr�quents : if ( itemSet.m_iSupport >= (int)(m_fMinSupp*(float)m_iNombreTransactions) ) listeItemSetsTemp.add(itemSet); } // On remplace l'ancienne liste par la nouvelle : m_listeListeItemSets.set(iIndiceListe, listeItemSetsTemp); } // Retire tous les itemsets qui ne satisfont pas les conditions donn�es par l'utilsateur // dans le tableau de filtrage : public void ElaguerItemsetsSelonFiltre() { ArrayList listeItemSets = null; ArrayList listeItemSetsTemp = null; ItemSet itemSet = null; int iIndiceListeItemSets = 0; int iNombreListesItemSets = 0; int iIndiceItemSet = 0; int iNombreItemSets = 0; iNombreListesItemSets = m_listeListeItemSets.size(); for (iIndiceListeItemSets=0; iIndiceListeItemSets<iNombreListesItemSets; iIndiceListeItemSets++) { listeItemSets = (ArrayList)m_listeListeItemSets.get(iIndiceListeItemSets); listeItemSetsTemp = new ArrayList(); iNombreItemSets = listeItemSets.size(); for (iIndiceItemSet=0; iIndiceItemSet<iNombreItemSets; iIndiceItemSet++) { itemSet = (ItemSet)listeItemSets.get(iIndiceItemSet); if (itemSet != null) if (m_contexteResolution.EstItemSetValide(itemSet)) listeItemSetsTemp.add(itemSet); } // On remplace l'ancienne liste par la nouvelle : m_listeListeItemSets.set(iIndiceListeItemSets, listeItemSetsTemp); } } /**Generate new item sets*/ public boolean GenererNouvelleListeItemSets() { ArrayList nouvelleListe = null; ArrayList precedenteListe = null; int iSupportItem = 0; int iIndiceListe = 0; int iNombreAttributsQual = 0; int iIndiceAttributQual = 0; ItemSet itemSet = null; ItemQualitative item = null; AttributQualitative attributQual = null; iIndiceListe = m_listeListeItemSets.size(); iNombreAttributsQual = m_listeAttributsQual.size(); // On r�initialise les pointeurs de comptage des itemsets, qui mettaient en relation // toute valeur d'un attribut avec l'ensemble des itemsets qui le contenaient : for (iIndiceAttributQual = 0; iIndiceAttributQual < iNombreAttributsQual; iIndiceAttributQual++) { attributQual = (AttributQualitative)m_listeAttributsQual.get(iIndiceAttributQual); attributQual.ReinitialiserListeLiensItemSets(); } nouvelleListe = new ArrayList(); // Itemsets de taille 1 : if (iIndiceListe == 0) { item = m_tableItems.ObtenirPremierItem(); while (item != null) { if ( m_contexteResolution.ObtenirTypePrisEnCompteItem(item.m_attributQual.m_sNomAttribut, item.ObtenirIdentifiantTexteItem()) != ResolutionContext.PRISE_EN_COMPTE_ITEM_NULLE_PART ) { itemSet = new ItemSet(1); itemSet.SpecifierItem(item); iSupportItem = item.m_attributQual.ObtenirSupportItem(item.m_iIndiceValeur); itemSet.SpecifierSupport( iSupportItem ); item.m_attributQual.AjouterLienVersItemSet(item.m_iIndiceValeur, itemSet); nouvelleListe.add(itemSet); } item = (ItemQualitative)(item.m_itemSuivant); } } // Combinaisons d'items : else { int iIndiceParcours1 = 0, iIndiceParcours2 = 0; int iNombreItemSets = 0; int iTailleNouveauxItemSets = 0; int iNombreItemsIdentiques = 0; int iIndiceItem = 0; boolean bContinuerParcours = false; ItemSet itemSet1 = null, itemSet2 = null; bContinuerParcours = true; // On �pure la liste des (K-1)-itemSets de ceux qui ne sont pas fr�quents : RetirerNonFrequentsDeListeItemSets(iIndiceListe-1); // On g�n�re la liste des K-itemSets � partir de la pr�c�dente contenant les (K-1)-itemSets fr�quents : precedenteListe = (ArrayList)m_listeListeItemSets.get(iIndiceListe-1); iNombreItemSets = precedenteListe.size(); iTailleNouveauxItemSets = iIndiceListe + 1; iNombreItemsIdentiques = iIndiceListe - 1; iIndiceParcours1=0; while ( bContinuerParcours && (iIndiceParcours1<iNombreItemSets) ) { itemSet1 = (ItemSet)precedenteListe.get(iIndiceParcours1); for (iIndiceParcours2=iIndiceParcours1+1;iIndiceParcours2<iNombreItemSets;iIndiceParcours2++) { itemSet2 = (ItemSet)precedenteListe.get(iIndiceParcours2); if (itemSet1.EstGenerateurCandidatAvec(itemSet2)) { // On doit aussi v�rifier que les 2 dernier items (ceux qui sont diff�rents // l'un de l'autre) ne correspondent pas � des valeurs issues d'un // m�me attribut de la BD (les valeurs d'un m�me attribut sont exclusives). // Il n'est pas utile de les comparer aux items communs // puisque par "r�cursion" les (K-1)-itemSet sont // d�j� constitu�es d'items r�pondant � cette imp�rative. if ( !itemSet1.m_listeItems[iNombreItemsIdentiques].m_attributQual.equals( itemSet2.m_listeItems[iNombreItemsIdentiques].m_attributQual) ) { itemSet = new ItemSet(iTailleNouveauxItemSets); // Le nouvel itemSet est constitu� des k-2 premiers items communs aux deux // (K-1)-itemSets g�n�rateurs... : for (iIndiceItem=0;iIndiceItem<iNombreItemsIdentiques;iIndiceItem++) { item = itemSet1.m_listeItems[iIndiceItem]; itemSet.SpecifierItem(item); item.m_attributQual.AjouterLienVersItemSet(item.m_iIndiceValeur, itemSet); } // ... auxquels on ajoute les deux items qui ne sont pas en commun : item = itemSet1.m_listeItems[iNombreItemsIdentiques]; itemSet.SpecifierItem(item); item.m_attributQual.AjouterLienVersItemSet(item.m_iIndiceValeur, itemSet); item = itemSet2.m_listeItems[iNombreItemsIdentiques]; itemSet.SpecifierItem(item); item.m_attributQual.AjouterLienVersItemSet(item.m_iIndiceValeur, itemSet); itemSet.SpecifierSupport(0); nouvelleListe.add(itemSet); } } } iIndiceParcours1++; if (m_traitementExterne != null) bContinuerParcours = m_traitementExterne.ExecuterTraitementExterne(); } // On effectue une nouvelle passe de lecture de la BD afin de calculer les nouveaux supports : int iIndiceTransaction = 0; int iNombreTransactions = 0; iNombreAttributsQual = m_listeAttributsQual.size(); iIndiceAttributQual = 0; attributQual = null; // Lecture ligne par ligne... iNombreTransactions = m_gestionnaireBD.ObtenirNombreLignes(); iIndiceTransaction = 0; if (bContinuerParcours) for (iIndiceTransaction=0; iIndiceTransaction<iNombreTransactions; iIndiceTransaction++) { // ... puis attribut par attribut : for (iIndiceAttributQual=0;iIndiceAttributQual<iNombreAttributsQual;iIndiceAttributQual++) { attributQual = (AttributQualitative)m_listeAttributsQual.get(iIndiceAttributQual); if (attributQual!=null) attributQual.ComptabiliserOcurrenceValeur(iIndiceTransaction, attributQual.m_colonneDonnees.m_tIDQualitatif[iIndiceTransaction]); } } } if (!nouvelleListe.isEmpty()) { m_listeListeItemSets.add(nouvelleListe); return true; } else return false; } /** * Frequent recover * @param iTailleFrequent Frequent size * @param iIndiceFrequent Frequent index * @return an Item Set */ public ItemSet RecupererFrequent(int iTailleFrequent, int iIndiceFrequent) { int iDimensionMax = 0; int iNombreFrequents = 0; ArrayList listeItemSets = null; iDimensionMax = m_listeListeItemSets.size(); if ( (iTailleFrequent<=0) || (iTailleFrequent>iDimensionMax) ) return null; listeItemSets = (ArrayList)m_listeListeItemSets.get( (iTailleFrequent-1) ); iNombreFrequents = listeItemSets.size(); if ( (iIndiceFrequent<0) || (iIndiceFrequent>=iNombreFrequents) ) return null; return (ItemSet)listeItemSets.get(iIndiceFrequent); } // Recherche parmi la liste des fr�quents l'itemset contenant les items pass�s en param�tre : /** * Search through the list of the frquents itemset containing items in passs paramtre * @param items An array of Qualitative item */ public ItemSet RechercherFrequent(ItemQualitative [] items) { int iTailleFrequent = 0; int iDimensionMax = 0; ArrayList listeItemSets = null; ItemSet itemSet = null; boolean bItemSetTrouve = false; int iNombreItemSets = 0; int iIndiceItemSet = 0; ItemQualitative item = null; int iIndiceItem = 0; boolean bItemTrouveDansItemSet = false; int iIndiceItemDansItemSet = 0; iTailleFrequent = items.length; iDimensionMax = m_listeListeItemSets.size(); if ( (iTailleFrequent<=0) || (iTailleFrequent>iDimensionMax) ) return null; listeItemSets = (ArrayList)m_listeListeItemSets.get( (iTailleFrequent-1) ); iNombreItemSets = listeItemSets.size(); iIndiceItemSet = 0; itemSet = null; bItemSetTrouve = false; while ( (!bItemSetTrouve) && (iIndiceItemSet<iNombreItemSets) ) { itemSet = (ItemSet)listeItemSets.get(iIndiceItemSet); // On v�rifie si chaque item est pr�sent dans l'itemset : iIndiceItem = 0; bItemSetTrouve = true; while ( (bItemSetTrouve) && (iIndiceItem<iTailleFrequent) ) { item = items[iIndiceItem]; // On recherche la pr�sence de l'item dans l'itemset : bItemTrouveDansItemSet = false; iIndiceItemDansItemSet = 0; while ( (!bItemTrouveDansItemSet) && (iIndiceItemDansItemSet<iTailleFrequent) ) { bItemTrouveDansItemSet = item.equals( itemSet.m_listeItems[iIndiceItemDansItemSet] ); iIndiceItemDansItemSet++; } bItemSetTrouve = bItemTrouveDansItemSet; iIndiceItem++; } iIndiceItemSet++; } if (bItemSetTrouve) return itemSet; else return null; } /** * Obtain quantitative attributes * @param iIndiceQuant Index of the quantitative attribute * @return Quantitative attribute */ public AttributQuantitative ObtenirAttributQuantitatif(int iIndiceQuant) { if ( (iIndiceQuant>=0) && (iIndiceQuant<m_listeAttributsQuant.size()) ) return (AttributQuantitative)m_listeAttributsQuant.get(iIndiceQuant); else return null; } public int ObtenirNombreAttributsQuantitatifs() { if (m_listeAttributsQuant==null) return 0; else return m_listeAttributsQuant.size(); } /** * Obtaining quantitative attributes by Name * @param sNomAttributQuant * @return quantitative attribute */ public AttributQuantitative ObtenirAttributQuantitatifDepuisNom(String sNomAttributQuant) { AttributQuantitative attribut = null; int iNombreAttributsQuant = 0; int iIndiceAttributQuant = 0; if (sNomAttributQuant == null) return null; iNombreAttributsQuant = m_listeAttributsQuant.size(); attribut = null; iIndiceAttributQuant = 0; while ( (attribut==null) && (iIndiceAttributQuant<iNombreAttributsQuant) ) { attribut = (AttributQuantitative)m_listeAttributsQuant.get(iIndiceAttributQuant); if (attribut != null) if ( !sNomAttributQuant.equals(attribut.ObtenirNom()) ) attribut = null; iIndiceAttributQuant++; } return attribut; } /** * Get Attribute From Name Qualitative * @param sNomAttributQual Name of Quanlitative Attribute * @return Qualitative attribute */ public AttributQualitative ObtenirAttributQualitatifDepuisNom(String sNomAttributQual) { AttributQualitative attribut = null; int iNombreAttributsQual = 0; int iIndiceAttributQual = 0; if (sNomAttributQual == null) return null; iNombreAttributsQual = m_listeAttributsQual.size(); attribut = null; iIndiceAttributQual = 0; while ( (attribut==null) && (iIndiceAttributQual<iNombreAttributsQual) ) { attribut = (AttributQualitative)m_listeAttributsQual.get(iIndiceAttributQual); if (attribut != null) if ( !sNomAttributQual.equals(attribut.ObtenirNom()) ) attribut = null; iIndiceAttributQual++; } return attribut; } /** * Return Qualitative Item from AttributQualitatif * @param attribut Quanlitative Attribute * @param iIndiceValeur Index * @return Qualitative Item */ public ItemQualitative ObtenirItem(AttributQualitative attribut, short iIndiceValeur) { ItemQualitative item = null; boolean bItemTrouve = false; bItemTrouve = false; item = m_tableItems.ObtenirPremierItem(); while ( (!bItemTrouve) && (item != null) ) { // On teste l'�galit� de l'attribut puis celle de l'item lui-meme : if ( (Object)item.m_attributQual == (Object)attribut ) bItemTrouve = ( item.m_iIndiceValeur == iIndiceValeur ); if (!bItemTrouve) item = (ItemQualitative)(item.m_itemSuivant); } return item; } }