IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Microsoft Business Intelligence avec librairies numériques

Logo Visual Numerics


précédentsommaire

VI. Annexes

VniClusterMetadata.cs

Expose les caractéristiques de l'algorithme ClusterKMeans.

 
Sélectionnez
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using Microsoft.SqlServer.DataMining.PluginAlgorithms;
namespace VNI
{
    /* doit créer un numéro GUID en exécutant
    * Tools->Create GUID puis utilise Copier-Coller ici
    * Ne copiez que le numéro unique et ignorez les autres
    * nombres
    */
    [ComVisible(true)]
    [Guid("9BC1DB7D-52B9-46aa-9469-FF7B5A2B3F88")]
    [MiningAlgorithmClass(typeof(VniClusterKMeansAlgorithm))]
    public class VniClusterMetadata : AlgorithmMetadataBase
    {
        // Paramètres
        protected MiningParameterCollection parameters;
        // modélisation de registre
        internal static MiningModelingFlag
        MainAttributeFlag = MiningModelingFlag.CustomBase + 1;
        /* initialisation de collecte de paramètres */
        public VniClusterMetadata()
        {
            parameters = DeclareParameters();
        }
        static public MiningParameterCollection DeclareParameters()
        {
            MiningParameterCollection parameters
            = new MiningParameterCollection();
            MiningParameter param;
            // Exemple de population complète d'un paramètre dans le
            // constructeur
            param = new MiningParameter(
            "CLUSTER_COUNT",
            "Number of Clusters",
            "3",
            "(0.0, ...)",
            true,
            true,
            typeof(System.Int32));
            parameters.Add(param);
            // Exemple de population d'un paramètre après construction
            // Quand on utilise ce constructeur, les réglages suivants
            // sont générés :
            // - isRequired = false
            // - isExposed = true
            // - description = ""
            // - defaultValue = ""
            // - valueEnum = ""
            // parameters.Add(param);
            return parameters;
        }
        public override string GetDisplayName()
        {
            return "VNI Cluster K Means";
        }
        public override string GetServiceName()
        {
            return "VNI_ClusterKMeans";
        }
        public override string GetServiceDescription()
        {
            // Description d'Arma
            return "computes K-means (centroid) Euclidean metric clusters for an input" +
            "data starting with initial estimates of the K cluster means.";
        }
        /* la valeur d'énumération de type service retournée par cette fonction
         * décrit la classe d'algorithmes qui inclut votre algorithme, s'il existe.
         * Par exemple, des classes populaires d'algorithmes incluent Association * Rules, Classification, and Clustering.
         * L'exemple retourne ServiceTypeOther, parce qu'il n'appartient
         * réellement à aucune de ces classes. 
         *
         */
        public override PlugInServiceType GetServiceType()
        {
            return PlugInServiceType.ServiceTypeClustering;
        }
        /* La chaîne type de visionneuse retournée par cette fonction indique les
         * outils dont l'objet visionneuse devrait afficher le contenu des
         * modèles entraînés avec votre algorithme. Si le contenu de votre
         * algorithme est similaire au contenu d'algorithmes incorporés, vous
         * pouvez utiliser l'une des chaînes prédéfinies (commentées). Vous
         * pouvez aussi construire votre propre visionneuse personnalisée et
         * retourner son identifiant. Pour tout détail sur comment faire cela,
         * cf. "Un tutoriel pour construire une visionneuse plug-in" sur
         * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnsql90/html/TutConPIV.asp
        */
        public override string GetViewerType()
        {
            //return MiningViewerType.MicrosoftAssociationRules;
            //return MiningViewerType.MicrosoftCluster;
            //return MiningViewerType.MicrosoftNaiveBayesian;
            //return MiningViewerType.MicrosoftNeuralNetwork;
            //return MiningViewerType.MicrosoftSequenceCluster;
            //return MiningViewerType.MicrosoftTimeSeries;
            //return MiningViewerType.MicrosoftTree;
            //return string.Empty;
            return MiningViewerType.MicrosoftCluster;
        }
        /* Ceci n'est pas utilisé par le AS mais exposé dans le rowset MINING_ALGORITHMS */
        public override MiningScaling GetScaling()
        {
            return MiningScaling.Medium;
        }
        /* utilisé par le rowset mining_algorithm */
        public override MiningTrainingComplexity GetTrainingComplexity()
        {
            return MiningTrainingComplexity.Low;
        }
        public override MiningPredictionComplexity GetPredictionComplexity()
        {
            return MiningPredictionComplexity.Low;
        }
        public override MiningExpectedQuality GetExpectedQuality()
        {
            return MiningExpectedQuality.Low;
        }
        /* Un algorithme supporte les dimensions de data mining si le contenu des
         * modèles entraînés avec cet algorithme peut être organisé comme une
         * dimension de data mining.
         * Cet exemple retourne false.
        */
        public override bool GetSupportsDMDimensions()
        {
            return false;
        }
        /* Le support pour les opérations drill-through est décrit au chapitre 10
         * de ce document.*/
        public override bool GetSupportsDrillThrough()
        {
            return false;
        }
        public override bool GetDrillThroughMustIncludeChildren()
        {
            return false;
        }
        /* Retourne true si votre modèle traite le case ID comme une variable
         * séparée.*/
        /* Cet exemple retourne false.*/
        public override bool GetCaseIdModeled()
        {
            return false;
        }
        /*
        * Ceci informe le serveur des statistiques qu'il faut construire avant de
        * lancer l'entraînement d'algorithme. les champs d'énumération
        * MarginalRequirements peuvent décrire toutes les statistiques
        * (cas les plus courants), les statistiques pour attributs d'entrée
        * seulement, pour attributs de sortie seulement, ou aucune statistique du
        * tout.
        */
        public override MarginalRequirements GetMarginalRequirements()
        {
            return MarginalRequirements.AllStats;
        }
        /*
        * Cette méthode retourne les types de contenu qui sont supportés par cet
        * algorithme pour attributs d'entrée.
        * Tous les types courants sont supportés par le plug-in managé.
        */
        public override MiningColumnContent[] GetSupInputContentTypes()
        {
            MiningColumnContent[] arInputContentTypes = new MiningColumnContent[]
{
MiningColumnContent.Discrete,
MiningColumnContent.Continuous,
MiningColumnContent.Discretized,
MiningColumnContent.NestedTable,
MiningColumnContent.Key
};
            return arInputContentTypes;
        }
        /* Cette méthode retourne les types de contenu qui sont supportés par cet
        * algorithme pour les attributs prévisibles. Tous les types courants sont
        * supportés par le plug-in managé.
        */
        public override MiningColumnContent[] GetSupPredictContentTypes()
        {
            MiningColumnContent[] arPredictContentTypes = new MiningColumnContent[]
{
MiningColumnContent.Discrete,
MiningColumnContent.Continuous,
MiningColumnContent.Discretized,
MiningColumnContent.NestedTable,
MiningColumnContent.Key
};
            return arPredictContentTypes;
        }
        /* Cette méthode retourne la liste des fonctions standards Data Mining
        * Extensions (DMX) supportées par cet algorithme. La plupart des
        * fonctions standards peuvent être supportées sans aucun effort du
        * développeur, une fois que la fonction AlgorithmBase.Predict est
        * implémentée correctement.
        */
        public override SupportedFunction[] GetSupportedStandardFunctions()
        {
            SupportedFunction[] arFuncs = new SupportedFunction[] {
// Fonctions générales de prédiction
SupportedFunction.PredictSupport,
SupportedFunction.PredictHistogram,
SupportedFunction.PredictProbability,
SupportedFunction.PredictAdjustedProbability,
 
SupportedFunction.PredictAssociation,
SupportedFunction.PredictStdDev,
SupportedFunction.PredictVariance,
SupportedFunction.RangeMax,
SupportedFunction.RangeMid,
SupportedFunction.RangeMin,
SupportedFunction.DAdjustedProbability,
SupportedFunction.DProbability,
SupportedFunction.DStdDev,
SupportedFunction.DSupport,
SupportedFunction.DVariance,
// fonctions liées au contenu
SupportedFunction.IsDescendent,
SupportedFunction.PredictNodeId,
SupportedFunction.IsInNode,
SupportedFunction.DNodeId,
// fonctions spécifiques du cluster
SupportedFunction.Cluster,
SupportedFunction.ClusterDistance,
SupportedFunction.ClusterPredictHistogram,
SupportedFunction.ClusterProbability,
SupportedFunction.PredictCaseLikelihood,
SupportedFunction.DCluster,
};
            return arFuncs;
        }
        /* Cette méthode effectue une validation du jeu d'attributs avant de lancer
        * l'entraînement.
        * Par exemple, cette méthode peut garantir qu'au moins un attribut est
        * prévisible, dans un algorithme de classification.
        */
        public override void ValidateAttributeSet(AttributeSet attributeSet)
        {
            uint nCount = attributeSet.GetAttributeCount();
            int mainAttrs = 0;
            int inputAttrs = 0;
            for (uint nIndex = 0; nIndex < nCount; nIndex++)
            {
                bool thisAttIsInput = false;
                if ((attributeSet.GetAttributeFlags(nIndex) & AttributeFlags.Input) != 0)
                {
                    inputAttrs++;
                    thisAttIsInput = true;
                }
                MiningModelingFlag[] modelingFlags = attributeSet.GetModelingFlags(nIndex);
                for (int flagIndex = 0; flagIndex < modelingFlags.Length; flagIndex++)
                {
                    if (modelingFlags[flagIndex] == MainAttributeFlag)
                    {
                        if (!thisAttIsInput)
                        {
                            string strMessage = string.Format(
                            "{0} ne peut être appliqué qu'à un attribut d'entrée",
                            GetModelingFlagName(MainAttributeFlag));
                            throw new System.Exception(strMessage);
                        }
                        mainAttrs++;
                    }
                }
            }
        }
        public override AlgorithmBase CreateAlgorithm(ModelServices model)
        {
            return new VniClusterKMeansAlgorithm();
        }
        public override MiningParameterCollection GetParametersCollection()
        {
            if (parameters == null)
            {
                DeclareParameters();
            }
            return parameters;
        }
        public override object ParseParameterValue(
        int parameterIndex,
        string parameterValue)
        {
            // Cette fonction devrait retourner un objet contenant la valeur du
            // paramètre
            // NOTE!! Le type de l'objet doit correspondre exactement au type déclaré 
            // du paramètre paramIndex
            object retVal = null;
            if (parameterIndex == 0)
            {
                // Ceci est une valeur pour PARAM1, qui est Int32,
                // voyez l'implémentation de DeclareParameters
                int dVal = System.Convert.ToInt32(parameterValue);
                retVal = dVal;
            }
            /* else if (parameterIndex == 1)
            {
            // Ceci est une valeur pour PARAM2, qui est String,
            // voyez l'implémentation de DeclareParameters
            string strVal = parameterValue;
            retVal = strVal;
            }*/
            else
            {
                throw new System.ArgumentOutOfRangeException("paramIndex");
            }
            return retVal;
        }
        /* Principal registre d'attribut ou tout registre personnalisé*/
        public override MiningModelingFlag[] GetSupModelingFlags()
        {
            MiningModelingFlag[] arModelingFlags = new MiningModelingFlag[1];
            arModelingFlags[0] = MainAttributeFlag;
            // new MiningModelingFlag[] {
            // MainAttributeFlag
            // };
            return arModelingFlags;
        }
        /* nom du principal registre d'attribut ou tout registre personnalisé*/
        public override string GetModelingFlagName(MiningModelingFlag flag)
        {
            if (flag == MainAttributeFlag)
            {
                return "VNI_MAIN";
            }
            else
            {
                throw new System.Exception("Unknown VNI modeling flag : " +
                flag.ToString());
            }
        }
    }
}

VniClusterKmeansAlgorithm.cs

Cette classe implémente des tâches spécifiques de l'algorithme.

 
Sélectionnez
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SqlServer.DataMining.PluginAlgorithms;
using VNI;
using System.Diagnostics;
using Imsl.Stat;
using Imsl.Math;
using System.Collections;
/* L'algorithme shell plug-in fonctionne de la façon suivante :
* - Pendant l'entraînement, il traverse tous les cas une fois et envoie des
* notifications de traitement.
* - Le contenu ne se compose que du nombre de cas et de la durée du
* traitement.
* Ces informations ne constituent pas des modèles utiles, mais c'est un
* exemple assez simple de comment utiliser les objets de persistance.
* - Le contenu a un noeud unique, étiqueté "All", qui a les statistiques
d'entraînement fixées comme distribution nodale.
* - La prédiction ignore les entrées et se base seulement sur les statistiques
* d'entraînement fixées.
*/
namespace VNI
{
    /// <summary>
    /// Persistence
    /// </summary>
    enum VNIClusterPersistenceMarker
    {

        MainAttribute,
        Parameters,
        ClusterCount,
        ClusterDescription,
        ClusterDistribution
    }
    /// <summary>
    /// énumération contenant des délimitateurs dans le contenu
    /// persisté
    /// </summary>
    enum MyPersistenceTag
    {
        ShellAlgorithmContent,
        NumberOfCases
    };
    public class MyCaseProcessor : ICaseProcessor
    {
        protected VniClusterKMeansAlgorithm algo;
        public MyCaseProcessor(VniClusterKMeansAlgorithm algo)
        {
            this.algo = algo;
        }
        public void ProcessCase(long caseID, MiningCase inputCase)
        {
            // Cherche une annulation toutes les 100 rangées
            // Lance aussi une notification de traitement toutes les 100 rangées pour éviter de surcharger le tracerowset
            if (caseID % 100 == 0)
            {
                algo.Context.CheckCancelled();
                algo.trainingProgress.Progress();
            }
            algo.trainingProgress.Current++;
            // C'est la condition de clustering triviale, voyez le sommet du // fichier pour les détails
            //int destinationCluster = algo.InternalClusterMembership(inputCase);

            // Obtention du l'appartenance au cluster
            switch (algo.ProcessingPhase)
            {
                case VniClusterKMeansAlgorithm.MainProcessingPhase:
                    algo.vniStore.addCase(inputCase);
                    //algo.Clusters[destinationCluster].PushCase(inputCase);
                    break;
                //case VniClusterKMeansAlgorithm.UpdateSupportPhase:
                //algo.Clusters[destinationCluster].UpdateStats(inputCase);
                //algo.vniStore.fillClusters(algo.Clusters);
                // break;
            }
        }
    }
    public class VniClusterKMeansAlgorithm : AlgorithmBase
    {
        // Paramètres de mining. Saisit les paramètres d'entraînement avec
        // leurs valeurs.
        protected MiningParameterCollection algorithmParams;
        // notifications de trace pendant le traitement
        public TaskProgressNotification trainingProgress;
        // "principal" attribut (utilisé en partition)
        protected System.UInt32 MainAttribute;
        protected double MainMean; // moyenne de l'attribut principal, s'il est continu
        protected bool MainContinuous; // vrai si l'attribut principal est continu
        // Représentation interne de cluster
        public InternalCluster[] Clusters;
        public int ProcessingPhase = 0;
        public const int MainProcessingPhase = 1;
        public const int UpdateSupportPhase = 2;
        public const int FinalPhase = 3;
        public VNIStore vniStore;
        // maintenant, fixez-le à 3 mais passez un paramètre pour déterminer le nombre de clusters
        public int num_clusters = 0;
        public VniClusterKMeansAlgorithm()
        {
            algorithmParams = VNI.VniClusterMetadata.DeclareParameters();
            MainAttribute = 0;
            MainContinuous = false;
            MainMean = 0.0;
            vniStore = new VNIStore(this);
        }
        // Annulation facultative : on n'est PAS OBLIGE d'annuler ceci.
        // L'implémentation base.Initialize ne fait rien, aussi n'est-il pas
        // nécessaire de l'invoquer
        protected override void Initialize()
        {
            // Initialise les paramètres avec les valeurs par défaut
            this.algorithmParams["CLUSTER_COUNT"].Value = 3;
        }
        /*
        a. La valeur spécifiée par l'utilisateur en déploiement.
        b. la valeur par défaut (si aucune n'a été spécifiée par l'utilisateur pendant l'entraînement).
        c. La meilleure valeur détectée automatiquement (heuristiquement) par l'algorithme pour le jeu d'entraînement actuel.
        */
        protected override object GetTrainingParameterActualValue(int paramOrdinal)
        {
            return algorithmParams[paramOrdinal].Value;
        }
        public void ProcessCase(long caseId, MiningCase currentCase)
        {
            // Assurze-vous que le traitement n'a pas été annulé
            this.Context.CheckCancelled();
            // Augmente la valeur actuelle de la notification de trace
            trainingProgress.Current++;
            if (caseId % 100 == 0)
            {
                // lance la trace tous les 100 cas, pour éviter tout
                // impact sur les performances

                trainingProgress.Progress();
            }
            // utilise MiningCase ici pour l'entraînement
        }
        /* Load/Save content est utilisé pour la persistance des modèles détectés */
        protected override void LoadContent(PersistenceReader reader)
        {
            // Charge l'attribut principal
            reader.OpenScope((PersistItemTag)VNIClusterPersistenceMarker.MainAttribute);
            reader.GetValue(out this.MainAttribute);
            reader.GetValue(out this.MainContinuous);
            reader.GetValue(out this.MainMean);
            reader.CloseScope();
            // Charge les paramètres
            reader.OpenScope((PersistItemTag)VNIClusterPersistenceMarker.Parameters);
            foreach (MiningParameter param in this.algorithmParams)
            {
                string name;
                reader.GetValue(out name);
                if (name != param.Name)
                {
                    throw new System.Exception("Corrupted file -- unrecognized parameter name : " + name);
                }
                if (param.Name == "CLUSTER_COUNT")
                {
                    int dVal = 0;
                    reader.GetValue(out dVal);
                    param.Value = dVal;
                }
                /*if (param.Name == "PARAM2")
                {
                string sVal;
                reader.GetValue(out sVal);
                param.Value = sVal;
                }*/
            }
            reader.CloseScope();

            // Charge les clusters
            reader.OpenScope((PersistItemTag)VNIClusterPersistenceMarker.ClusterCount);
            int clusterCount = 0;
            reader.GetValue(out clusterCount);
            reader.CloseScope();
            Clusters = new InternalCluster[clusterCount];
            for (int nIndex = 0; nIndex < clusterCount; nIndex++)
            {
                Clusters[nIndex] = new InternalCluster(this);
                Clusters[nIndex].ClusterID = (ulong)nIndex;
                Clusters[nIndex].Description = BuildClusterDescription(nIndex);
                Clusters[nIndex].Load(ref reader);
            }
        }
        protected override void SaveContent(PersistenceWriter writer)
        {
            // Sauvegarde l'attribut principal
            writer.OpenScope((PersistItemTag)VNIClusterPersistenceMarker.MainAttribute);
            writer.SetValue(this.MainAttribute);
            writer.SetValue(this.MainContinuous);
            writer.SetValue(this.MainMean);
            writer.CloseScope();
            // Sauvegarde les valeurs des paramètres connus
            writer.OpenScope((PersistItemTag)VNIClusterPersistenceMarker.Parameters);
            foreach (MiningParameter param in this.algorithmParams)
            {
                writer.SetValue(param.Name);
                if (param.Name == "CLUSTER_COUNT")
                {
                    int nVal = System.Convert.ToInt32(param.Value);
                    writer.SetValue(nVal);
                }
            }
            writer.CloseScope();

            // Sauvegarde les clusters
            writer.OpenScope((PersistItemTag)VNIClusterPersistenceMarker.ClusterCount);
            writer.SetValue(Clusters.Length);
            writer.CloseScope();
            for (int iIndex = 0; iIndex < Clusters.Length; iIndex++)
            {
                Clusters[iIndex].Save(ref writer);
            }
        }
        protected override AlgorithmNavigationBase GetNavigator(
        bool forDMDimensionContent)
        {
            return new AlgorithmNavigator(this, forDMDimensionContent);
        }
        private void PrepareForProcessing(int numClusters)
        {
            /*////////////////////////////////////////////////////////
            * Détecte l'attribut principal
            * Cherche l'attribut d'entrée qui a le registre MainAttributeFlag
            */
            UInt32 nAtt = 0;
            MainAttribute = AttributeSet.Unspecified;
            for (nAtt = 0; nAtt < this.AttributeSet.GetAttributeCount(); nAtt++)
            {
                MiningModelingFlag[] flags = this.AttributeSet.GetModelingFlags(nAtt);
                for (int flagIndex = 0; flagIndex < flags.Length; flagIndex++)
                {
                    if (flags[flagIndex] == VniClusterMetadata.MainAttributeFlag)
                    {
                        MainAttribute = nAtt;
                        Debug.Assert((AttributeSet.GetAttributeFlags(nAtt) & AttributeFlags.Input) != 0);
                        break;
                    }
                }
            }
            if (MainAttribute == AttributeSet.Unspecified)
            {

                for (nAtt = 0; nAtt < this.AttributeSet.GetAttributeCount(); nAtt++)
                {
                    if ((AttributeSet.GetAttributeFlags(nAtt) & AttributeFlags.Input) != 0)
                    {
                        MainAttribute = nAtt;
                    }
                }
            }
            Debug.Assert(MainAttribute != AttributeSet.Unspecified);
            MainContinuous = (AttributeSet.GetAttributeFlags(MainAttribute) & AttributeFlags.Continuous) !=
            0;
            if (MainContinuous)
            {
                // Extraît la moyenne
                AttributeStatistics stats = this.MarginalStats.GetAttributeStats(MainAttribute);
                // gardez à l'esprit que, pour les attributs continus, le premier état manque et le deuxième état contient la moyenne de l'attribut
                Debug.Assert(stats.StateStatistics.Count == 2);
                Debug.Assert(stats.StateStatistics[1].Value.IsDouble);
                MainMean = stats.StateStatistics[1].Value.Double;
            }
            // Utilisez trainingParams et les statistiques marginales ici pour en déduire le meilleur nombre de clusters
            // Cet exemple le fixe This sample à 2
            Clusters = new InternalCluster[numClusters];
            for (int nIndex = 0; nIndex < numClusters; nIndex++)
            {
                // crée les clusters
                Clusters[nIndex] = new InternalCluster(this);
                // fixe les propriétés id du noeud interne
                Clusters[nIndex].ClusterID = (ulong)nIndex;
                // Généralement, le cluster devrait construire sa propre description
                // Dans ce cas, l'algorithme connaît l'attribut principal, par
                // conséquent il construira la description
                Clusters[nIndex].Description = BuildClusterDescription(nIndex);
            }

        }
        // Généralement, le cluster devrait construire sa propre description
        // Dans ce cas, l'algorithme connaît l'attribut principal, par
        // conséquent il construira la description
        private string BuildClusterDescription(int nIndex)
        {
            string strRet = string.Empty;
            //retourne "VNI Cluster " + nIndex.ToString();
            string attName = AttributeSet.GetAttributeDisplayName(MainAttribute, false);
            if (MainContinuous)
            {
                StateValue sVal = new StateValue();
                sVal.SetDouble(MainMean);
                object val = AttributeSet.UntokenizeAttributeValue(MainAttribute, sVal);
                if (nIndex == 0)
                {
                    strRet = string.Format("{0} < {1}", attName, "99999");
                }
                else
                {
                    strRet = string.Format("{0} >= {1} OR {0} = Manquant", attName, val.ToString());
                }
            }
            else
            {
                StateValue sVal = new StateValue();
                sVal.SetIndex(1);
                object val = AttributeSet.UntokenizeAttributeValue(MainAttribute, sVal);
                if (nIndex == 0)
                {
                    strRet = string.Format("{0} = {1}", attName, val.ToString());
                }
                else
                {
                    strRet = string.Format("{0} NOT = {1}", attName, val.ToString());
                }
            }
            return strRet;
        }

        public int InternalClusterMembership(MiningCase mcase)
        {
            /* Vérifie les erreurs pour faire que mCase ait les mêmes attributs que les attributs de cluster entraîné
            */
            int member = -1;
            double[] varr = new double[this.AttributeSet.GetAttributeCount()];
            bool mcontinue = mcase.MoveFirst();
            while (mcontinue)
            {
                UInt32 attribute = mcase.Attribute;
                StateValue value = mcase.Value;
                if (value.IsDouble) /*continu */
                {
                    varr[attribute] = value.Double;
                    //attrList.Add(value.Double);
                }
                /* pour toute colonne discrète, il y aura un index
                * représentant un état. Par exemple, une colonne avec
                * des valeurs A,B,C aura 3 indices
                * A=1, B=2, c=3
                */
                if (value.IsIndex) /*discrète */
                {
                    varr[attribute] = value.Double;
                    //attrList.Add((double)value.Index);
                }
                if (value.IsMissing) /* missing values */
                {
                    //attrList.Add(null);
                }
                mcontinue = mcase.MoveNext();
            }
            // double[] vals = (double[])attrList.ToArray(typeof(double));
            // utilise la distance euclidienne pour calculer le cluster
            // On présume que le cas d'entrée a autant d'attributs que le
            // modèle entraîné.
            double[,] centers = this.vniStore.getCenters();
            double[] distance = new double[Clusters.Length];
            double esum = 0.0;

            for (int i = 0; i < distance.Length; i++)
            {
                esum = 0.0;
                for (int j = 0; j < varr.Length; j++)
                {
                    esum += (varr[j] - centers[i, j]) * (varr[j] - centers[i, j]);
                }
                distance[i] = Math.Sqrt(esum);
            }
            double[] distcopy = new double[distance.Length];
            Array.Copy(distance, distcopy, distance.Length);
            Array.Sort(distcopy);
            for (int m = 0; m < distance.Length; m++)
            {
                if (distcopy[0] == distance[m])
                {
                    member = m;
                    break;
                }
            }
            return member;
        }
        /// <summary>
        /// Méthode de pseudo-clustering
        /// Retourne 0 pour le premier cluster, 1 pour le deuxième
        /// </summary>
        /*public int InternalClusterMembership(MiningCase inputCase)
        {
        int nRet = 1;
        bool bContinue = inputCase.MoveFirst();
        while (bContinue)
        {
        if (inputCase.Attribute == MainAttribute)
        {
        if (MainContinuous)
        {
        // Safety check
        Debug.Assert(inputCase.Value.IsDouble || inputCase.Value.IsMissing);
        if (inputCase.Value.IsDouble && (inputCase.Value.Double < MainMean))
        {
 
        // Appartient au premier cluster
        nRet = 0;
        }
        }
        else
        {
        // Contrôle de sécurité
        Debug.Assert(inputCase.Value.IsIndex || inputCase.Value.IsMissing);
        if (inputCase.Value.IsIndex && (inputCase.Value.Index == 1))
        {
        // Appartient au premier cluster
        nRet = 0;
        }
        }
        break;
        }
        else
        {
        bContinue = inputCase.MoveNext();
        }
        }
        return nRet;
        }*/
        /* Début du traitement de Cas. L'objet PushCaseSet nous permet
        * d'interagir avec CaseProcessor
        */
        protected override void InsertCases(PushCaseSet caseSet, MiningParameterCollection trainingParams)
        {
            // Initialise le jeu de cluster interne et les paramètres
            LoadTrainingParameters(trainingParams);
            /* obtient le nombre de clusters spécifié par l'utilisateur */
            num_clusters = (int)GetTrainingParameterActualValue(0);
            if (num_clusters == 0)
            {
                throw new System.ArgumentOutOfRangeException("num_clusters");
            }
            // préparation du traitement (2 clusters)
            PrepareForProcessing(num_clusters);
            // passe à la phase 1

            ProcessingPhase = MainProcessingPhase;
            // Boucle d'entraînement principale
            while (ProcessingPhase != FinalPhase)
            {
                // Crée un objet de notification de progression de tâche pour envoyer des évènements de trace
                trainingProgress = this.Model.CreateTaskNotification();
                trainingProgress.Total = (int)this.MarginalStats.GetTotalCasesCount();
                trainingProgress.Current = 0;
                switch (ProcessingPhase)
                {
                    case MainProcessingPhase:
                        trainingProgress.Format = "MainProcessingPhase: processing {0} out of {1}";
                        bool bSuccess = true;
                        try
                        {
                            trainingProgress.Start();
                            MyCaseProcessor processor = new MyCaseProcessor(this);
                            caseSet.StartCases(processor);
                        }
                        catch
                        {
                            bSuccess = false;
                            throw;
                        }
                        finally
                        {
                            trainingProgress.End(bSuccess);
                        }
                        break;
                    case UpdateSupportPhase:
                        trainingProgress.Format = "Updating support: processing {0} out of {1}";
                        this.vniStore.fillClusters(this.Clusters);
                        break;
                }
                // passe à la phase de traitement suivante
                ProcessingPhase++;
            }
            // Traitement terminé, appelle PostProcess sur chaque cluster

            for (int nIndex = 0; nIndex < Clusters.Length; nIndex++)
            {
                Clusters[nIndex].UpdateStats();
            }
        }
        private void LoadTrainingParameters(MiningParameterCollection trainingParams)
        {
            // Copie les valeurs des paramètres dans cette collection de paramètres
            foreach (MiningParameter param in trainingParams)
            {
                if (this.algorithmParams[param.Name] != null)
                {
                    this.algorithmParams[param.Name].Value = param.Value;
                }
            }
        }
        protected override void Predict(MiningCase inputCase, PredictionResult predictionResult)
        {
            // Prédiction signifie
            // - déterminer le bon cluster
            // - effectuer la prédiction de cluster
            int nCaseCluster = InternalClusterMembership(inputCase);
            Clusters[nCaseCluster].Predict(ref predictionResult);
        }
        protected override ClusterMembershipInfo[] ClusterMembership(
        long caseID,
        MiningCase inputCase,
        string targetCluster)
        {
            // Lance une notification de progression
            Model.EmitSingleTraceNotification("ClusterMembership ... ");
            int clIndex = InternalClusterMembership(inputCase);
            string caption = Clusters[clIndex].Caption;
            ClusterMembershipInfo[] ret = null;
            if (targetCluster.Length > 0)
            {
                int cltargetCluster = -1;

                for (int nIndex = 0; nIndex < Clusters.Length; nIndex++)
                {
                    if (Clusters[nIndex].Caption.CompareTo(targetCluster) == 0)
                    {
                        cltargetCluster = nIndex;
                        break;
                    }
                }
                if (cltargetCluster == -1)
                    return null;
                ret = new ClusterMembershipInfo[1];
                ret[0] = new ClusterMembershipInfo();
                ret[0].Caption = Clusters[cltargetCluster].Caption;
                ret[0].ClusterId = Clusters[cltargetCluster].ClusterID;
                ret[0].Distance = (cltargetCluster == clIndex) ? 0.0 : 1.0;
                ret[0].Membership = 1.0 - ret[0].Distance;
                ret[0].NodeUniqueName = Clusters[cltargetCluster].NodeUniqueName;
                return ret;
            }
            ret = new ClusterMembershipInfo[Clusters.Length];
            for (int nIndex = 0; nIndex < Clusters.Length; nIndex++)
            {
                ret[nIndex] = new ClusterMembershipInfo();
                ret[nIndex].Caption = Clusters[nIndex].Caption;
                ret[nIndex].ClusterId = Clusters[nIndex].ClusterID;
                ret[nIndex].Distance = (nIndex == clIndex) ? 0.0 : 1.0;
                ret[nIndex].Membership = 1.0 - ret[nIndex].Distance;
                ret[nIndex].NodeUniqueName = Clusters[nIndex].NodeUniqueName;
            }
            return ret;
        }
        protected override double CaseLikelihood(
        long caseID, MiningCase inputCase, bool normalized)
        {
            // cet exemple ne calcule la distance de cluster,
            // aussi tous les cases sont-ils équiprobables
            return 1.0;

        }
    }
}

AlgorithmNavigator.cs

Expose les modèles détectés par l'algorithme ClusterKMeans.

 
Sélectionnez
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SqlServer.DataMining.PluginAlgorithms;
using VNI;
namespace VNI
{
    class AlgorithmNavigator : AlgorithmNavigationBase
    {
        VniClusterKMeansAlgorithm algorithm;
        bool forDMDimension;
        int currentNode;
        public AlgorithmNavigator(VniClusterKMeansAlgorithm currentAlgorithm, bool dmDimension)
        {
            algorithm = currentAlgorithm;
            forDMDimension = dmDimension;
            currentNode = 0;
        }
        protected override bool MoveToNextTree()
        {
            // Arbre unique pour cet algorithme
            return false;
        }
        protected override int GetCurrentNodeId()
        {
            return currentNode;
        }
        protected override bool ValidateNodeId(int nodeId)
        {

            return (nodeId >= 0 && nodeId <= algorithm.Clusters.Length);
        }
        protected override bool LocateNode(int nodeId)
        {
            // Le seul noeud valide est 0
            if (!ValidateNodeId(nodeId))
                return false;
            currentNode = nodeId;
            return true;
        }
        protected override int GetNodeIdFromUniqueName(string nodeUniqueName)
        {
            int nNode = System.Convert.ToInt32(nodeUniqueName);
            return nNode;
        }
        protected override string GetUniqueNameFromNodeId(int nodeId)
        {
            return nodeId.ToString("D3");
        }
        protected override uint GetParentCount()
        {
            switch (currentNode)
            {
                case 0:
                    return 0;
                default:
                    return 1;
            }
        }
        protected override void MoveToParent(uint parentIndex)
        {
            currentNode = 0;
        }
        protected override int GetParentNodeId(uint parentIndex)
        {

            return 0;
        }
        protected override uint GetChildrenCount()
        {
            switch (currentNode)
            {
                case 0:
                    return (uint)algorithm.Clusters.Length;
                default:
                    return 0;
            }
        }
        protected override void MoveToChild(uint childIndex)
        {
            if (currentNode == 0)
            {
                currentNode = (int)(childIndex + 1);
            }
        }
        protected override int GetChildNodeId(uint childIndex)
        {
            if (currentNode == 0)
            {
                return (int)(childIndex + 1);
            }
            return -1;
        }
        protected override NodeType GetNodeType()
        {
            // Root est un modèle, tout le reste est un cluster
            if (currentNode == 0)
                return NodeType.Model;
            else
                return NodeType.Cluster;
        }
        protected override string GetNodeUniqueName()
        {
            return GetUniqueNameFromNodeId(currentNode);
        }
        protected override uint[] GetNodeAttributes()
        {
            // Il n'y a pas d'association entre un noeud et un attribut
            return null;// new uint[] { 1, 2 };
        }
        protected override double GetDoubleNodeProperty(NodeProperty property)
        {
            double dRet = 0;
            double dTotalSupport = algorithm.MarginalStats.GetTotalCasesCount();
            double dNodeSupport = 0.0;
            switch (currentNode)
            {
                case 0:
                    dNodeSupport = dTotalSupport;
                    break;
                default:
                    dNodeSupport = algorithm.Clusters[currentNode - 1].Support;
                    break;
            }
            switch (property)
            {
                case NodeProperty.Support:
                    dRet = dNodeSupport;
                    break;
                case NodeProperty.Score:
                    dRet = 0;
                    break;
                case NodeProperty.Probability:
                    dRet = dNodeSupport / dTotalSupport;
                    break;
                case NodeProperty.MarginalProbability:
                    dRet = dNodeSupport / dTotalSupport;
                    break;
            }

            return dRet;
        }
        protected override string GetStringNodeProperty(NodeProperty property)
        {
            string strRet = "";
            switch (property)
            {
                case NodeProperty.Caption:
                    {
                        // IMPORTANT : L'en-tête d'un noeud peut être modifié par
                        // admin avec une déclaration telle que
                        // UPDATE Model.CONTENT SET NODE_CAPTION = 'Some cluster label'
                        // WHERE NODE_UNIQUE_NAME = '000001'
                        // Le listing des changements est immédiatement sauvegardé
                        // dans le modèle. Voici comment y accéder via model
                        // services
                        strRet = algorithm.Model.FindNodeCaption(GetNodeUniqueName());
                        if (strRet.Length == 0)
                        {
                            // si c'est vide, ça ne figure pas dans le listing
                            // génère la description
                            switch (currentNode)
                            {
                                case 0:
                                    strRet = "All";
                                    break;
                                default:
                                    strRet = algorithm.Clusters[currentNode - 1].Caption;
                                    break;
                            }
                        }
                    }
                    break;
                case NodeProperty.ConditionXml:
                    // La condition pour qu'un cas corresponde à un noeud doit être
                    // représentée ici
                    strRet = "";
                    break;
                case NodeProperty.Description:
                    switch (currentNode)
                    {
                        case 0:
                            strRet = "All";
                            break;
                        default:
                            strRet = algorithm.Clusters[currentNode - 1].Description; break;
                    }
                    break;
                case NodeProperty.ModelColumnName:
                    strRet = "";
                    break;
                case NodeProperty.RuleXml:
                    switch (currentNode)
                    {
                        case 0: strRet = "<Rule>All</Rule>"; break;
                        default:
                            strRet = "<Cluster>" + algorithm.Clusters[currentNode - 1].Caption +
                            "</Cluster>";
                            break;
                    }
                    break;
                case NodeProperty.ShortCaption:
                    switch (currentNode)
                    {
                        case 0:
                            strRet = "All";
                            break;
                        default:
                            strRet = algorithm.Clusters[currentNode - 1].Caption;
                            break;
                    }
                    break;
            }
            return strRet;
        }

        protected override AttributeStatistics[] GetNodeDistribution()
        {
            switch (currentNode)
            {
                case 0:
                    {
                        // Pour le noeud racine, retourne les statistiques
                        // marginales de tout le modèle d'extraction
                        int attStats = (int)algorithm.AttributeSet.GetAttributeCount();
                        AttributeStatistics[] marginalStats = new AttributeStatistics[attStats + 2];
                        for (uint nIndex = 0; nIndex < attStats; nIndex++)
                        {
                            marginalStats[nIndex] = algorithm.MarginalStats.GetAttributeStats(nIndex);
                        }
                        // Ajoute des informations supplémentaires dans
                        // NODE_DISTRIBUTION, pas de chaîne
                        AttributeStatistics extraInfo = new AttributeStatistics();
                        extraInfo.Attribute = AttributeSet.Unspecified;
                        StateStatistics state = new StateStatistics();
                        state.ValueType = MiningValueType.Intercept;
                        state.Value.SetDouble(2.0);
                        extraInfo.StateStatistics.Add(state);
                        marginalStats[attStats] = extraInfo;
                        // Ajoute des informations supplémentaires dans
                        // NODE_DISTRIBUTION : valeur et nom d'attribut
                        extraInfo = new AttributeStatistics();
                        extraInfo.Attribute = AttributeSet.Unspecified;
                        extraInfo.NodeId = "Any string here";
                        state = new StateStatistics();
                        state.ValueType = MiningValueType.Other;
                        state.Value.SetIndex(124);
                        extraInfo.StateStatistics.Add(state);
                        marginalStats[attStats + 1] = extraInfo;
                        return marginalStats;
                    }
                default:
                    // pour les noeuds clusters, retourne la distribution du cluster

                    return algorithm.Clusters[currentNode - 1].Distribution;
            }
        }
    }
}

Cluster.cs

Un objet utilisé pour représenter le modèle détecté (cluster).

 
Sélectionnez
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using Microsoft.SqlServer.DataMining.PluginAlgorithms;
using System.Collections;
namespace VNI
{
    // Représentation interne d'un cluster
    // Une instance de cette classe représentera un cluster détecté par
    // l'algorithme plug-in.
    public class InternalCluster
    {
        private string nodeUniqueName;
        private string description;
        /* Chaque cluster maintiendra la distribution des attributs pour
        * tous les cas d'entraînement qui finissent dans ce cluster.
        */
        private AttributeStatistics[] clusterDistribution;
        public VNIPatternAttribute[] vniatts;
        /* référence vers l'objet Algorithm qui a détecté ce cluster */
        private VniClusterKMeansAlgorithm algo;
        // ID interne du cluster
        private int clusterID;
        private int casesCount;
        ArrayList clusterValues;
        public InternalCluster(VniClusterKMeansAlgorithm parent)
        {
            algo = parent;

            // Alloue de l'espace pour toutes les statistiques
            // ainsi que pour le cluster Prediction
            clusterDistribution = new AttributeStatistics[algo.AttributeSet.GetAttributeCount()];
            /* pour chaque modèle, nous trouvons dans les données qu'il y
            * aura des attributs qui appartiennent à ces modèles.
            * VNIPatternattribute garde la trace de chaque attribut dans le
            * modèle et ses valeurs et statistiques
            */
            vniatts = new VNIPatternAttribute[algo.AttributeSet.GetAttributeCount()];
            for (uint nIndex = 0; nIndex < algo.AttributeSet.GetAttributeCount(); nIndex++)
            {
                //////////////////////////////////////
                // Distribution pour ce cluster
                clusterDistribution[nIndex] = new AttributeStatistics();
                vniatts[nIndex] = new VNIPatternAttribute();
                // détermine le nombre d'états
                uint statCount = algo.AttributeSet.GetAttributeStateCount(nIndex);
                // détermine si l'attribut est continu
                bool bContinuous = (algo.AttributeSet.GetAttributeFlags(nIndex) &
                AttributeFlags.Continuous) != 0;
                clusterDistribution[nIndex].Attribute = nIndex;
                clusterDistribution[nIndex].Support = 0;
                clusterDistribution[nIndex].Min = 0.0;
                clusterDistribution[nIndex].Max = 0.0;
                clusterDistribution[nIndex].NodeId = string.Empty;
                clusterDistribution[nIndex].Probability = 0.0;
                for (int nStatIndex = 0; nStatIndex < statCount; nStatIndex++)
                {
                    StateStatistics stateStat = new StateStatistics();
                    if (nStatIndex == 0)
                        stateStat.Value.SetMissing();
                    else
                    {
                        if (bContinuous)
                        {

                            Debug.Assert(nStatIndex == 1);
                            stateStat.Value.SetDouble(0.0);
                        }
                        else
                            stateStat.Value.SetIndex((uint)nStatIndex);
                    }
                    stateStat.Probability = 0.0;
                    stateStat.AdjustedProbability = 0.0;
                    stateStat.ProbabilityVariance = 0.0;
                    stateStat.Support = 0.0;
                    stateStat.Variance = 0.0;
                    clusterDistribution[nIndex].StateStatistics.Add(stateStat);
                }
            }
        }
        // Fait entrer les cas dans le cluster
        // Pour les attributs discrets, il suffit d'incrémenter le
        // support d'état
        // Pour les attributs continus, incrémentez le support d'état et
        // actualisez Min et Max
        // Additionnez temporairement les valeurs dans le champ de
        // valeurs AttributeStatistics
        public void PushCase(MiningCase inputCase)
{
bool bContinue = inputCase.MoveFirst();
casesCount++;
while (bContinue)
{
UInt32 attribute = inputCase.Attribute;
StateValue stateVal = inputCase.Value;
AttributeStatistics attStat = this.clusterDistribution[attribute];
bool bContinuous = (algo.AttributeSet.GetAttributeFlags(attribute) &
AttributeFlags.Continuous) != 0;
if (bContinuous)
{
Debug.Assert(attStat.StateStatistics.Count == 2);
// Attribut continu
bool first = attStat.StateStatistics[1].Support == 0.0;
 
if (stateVal.IsMissing)
{
attStat.StateStatistics[0].Support += 1.0;
}
else
{
Debug.Assert(stateVal.IsDouble);
double thisValue = stateVal.Double;
double dSumSoFar = attStat.StateStatistics[1].Value.Double;
// Incrémente le support pour l'état non
manquant
attStat.StateStatistics[1].Support += 1.0;
attStat.StateStatistics[1].Value.SetDouble(dSumSoFar + thisValue);
// Le support non manquant pour l'attribut est également incrémenté
attStat.Support += 1.0;
if (first)
{
attStat.Min = thisValue;
attStat.Max = thisValue;
}
else
{
if (attStat.Min > thisValue)
attStat.Min = thisValue;
if (attStat.Max < thisValue)
attStat.Max = thisValue;
}
}
}
else
{
// attribut discret
if (stateVal.IsMissing)
{
attStat.StateStatistics[0].Support += 1.0;
}
else
{
// Incrémente le support pour l'état non manquant
Debug.Assert(stateVal.IsIndex);
 
attStat.StateStatistics[stateVal.Index].Support += 1.0;
// et aussi pour l'attribut
attStat.Support += 1.0;
}
}
bContinue = inputCase.MoveNext();
}
}
        public void UpdateStats()
{
// détermine le nombre d'états
//casesCount = algo.vniStore.getCaseCount();
for (int i = 0; i < this.clusterDistribution.Length; i++)
{
uint statCount = algo.AttributeSet.GetAttributeStateCount((uint)i);
AttributeStatistics attStat = this.clusterDistribution[i];
bool bContinuous = (algo.AttributeSet.GetAttributeFlags((uint)i) &
AttributeFlags.Continuous) != 0;
if (bContinuous)
{
casesCount = this.vniatts[i].getCount();
attStat.StateStatistics[1].Support = 0.0;
Debug.Assert(attStat.StateStatistics.Count == 2);
double ExistingSupport = this.vniatts[i].getCount();
attStat.StateStatistics[1].Support = ExistingSupport;
/* sum of values in the cluster */
attStat.StateStatistics[1].Value.SetDouble(vniatts[i].getSum());
attStat.StateStatistics[1].Variance = vniatts[i].getVariance();
attStat.Support = ExistingSupport;
attStat.Min = vniatts[i].getMin();
attStat.Max = vniatts[i].getMax();
//double ExistingSupport = attStats.StateStatistics[1].Support;
//double sumValues = attStats.StateStatistics[1].Value.Double;
//double dExistingMiu = sumValues / this.casesCount;
// Fixe la valeur pour un état existant. C'est Miu (SUM/ExistingSupport)
 
attStat.StateStatistics[1].Value.SetDouble(vniatts[i].getSum() / ExistingSupport);
// Fixe Prob/AdjProb pour l'état existant
attStat.StateStatistics[1].Probability = (ExistingSupport + 1.0) / (ExistingSupport +
attStat.StateStatistics.Count);
// Lisse adjustProb
attStat.StateStatistics[1].AdjustedProbability =
attStat.StateStatistics[1].Probability;
// Fixe Prob/AdjProb pour un état manquant ??
double MissingSupport = attStat.StateStatistics[0].Support;
attStat.StateStatistics[0].Probability = (MissingSupport + 1.0) / (ExistingSupport +
attStat.StateStatistics.Count);
// Lisse adjustProb
attStat.StateStatistics[0].AdjustedProbability =
attStat.StateStatistics[0].Probability;
// Fixe Prob/AdjProb pour tout l'attribut
attStat.Probability = attStat.StateStatistics[1].Probability;
attStat.AdjustedProbability = attStat.StateStatistics[1].AdjustedProbability;
}
else /* discrete */
{
/* divise encore le support suivant des vars discrètes
* red =1 , blue = 2, green =3. Décide combien de reds,
* blues ou greens il y a dans un cluster
*/
ArrayList vals = this.vniatts[i].getDataValues();
int max = (int)vniatts[i].getMax();
/* démarrage d'états discrets à 1 */
for (int k = 1; k <= max; k++)
{
/*boucle à travers toutes les valeurs de vniatts pour régler le support en fonction de la valeur*/
foreach (Object attrobj in vals)
{
/* null signifie valeur manquante */
if (attrobj != null)
{
if (k == (int)(double)attrobj)
{
Page 40
attStat.StateStatistics[(uint)k].Support += 1.0;
attStat.Support += 1.0;
}
}
}
}
// attribut discret, détecte l'état le plus populaire et calcule les probabilités
double ExistingSupport = 0.0;
for (uint nStateIndex = 0; nStateIndex < statCount; nStateIndex++)
{
double dStateSupport = attStat.StateStatistics[nStateIndex].Support;
attStat.StateStatistics[nStateIndex].Probability = (dStateSupport + 1.0) /
(this.casesCount + statCount);
attStat.StateStatistics[nStateIndex].AdjustedProbability =
attStat.StateStatistics[nStateIndex].Probability;
if (nStateIndex > 0)
ExistingSupport += dStateSupport;
}
// fixe les statistiques globales d'attribut
attStat.Probability = (ExistingSupport + statCount - 1.0) / (ExistingSupport +
statCount);
attStat.AdjustedProbability = attStat.Probability;
}
}
}
        // Actualisation des statistiques
        // Rien à faire pour discret ou pour continu manquant
        // Pour continu, nécessite de calculer StdDev et Variance
        // Variance = SUM( Xi - Miu)^2 / N
        // Nous avons SUM( Xi) dans Value, d'où Miu = Value/N
        // Ici nous incrémentons la Variance avec (Xi - Miu)^2/N
        // donc, nous actualisons Value
        public void UpdateStats(MiningCase inputCase)
        {
            // Actualisation des statistiques

            bool bContinue = inputCase.MoveFirst();
            while (bContinue)
            {
                UInt32 attribute = inputCase.Attribute;
                StateValue stateVal = inputCase.Value;
                AttributeStatistics attStat = this.clusterDistribution[attribute];
                bool bContinuous = (algo.AttributeSet.GetAttributeFlags(attribute) &
                AttributeFlags.Continuous) != 0;
                if (bContinuous)
                {
                    if (!stateVal.IsMissing)
                    {
                        double ExistingSupport = attStat.StateStatistics[1].Support;
                        double Miu = attStat.StateStatistics[1].Value.Double / ExistingSupport;
                        double thisValue = stateVal.Double;
                        attStat.StateStatistics[1].Variance += ((thisValue - Miu) * (thisValue - Miu) /
                        ExistingSupport);
                    }
                }
                bContinue = inputCase.MoveNext();
            }
        }
        // Post-traitement des clusters pour les attributs continus :
        // - état manquant : rien à faire
        // - état non manquant : Value est actuellement SUM(Xi), divise par le support existant pour obtenir Miu
        // - décide l'état le plus probable, manquant ou existant, pour prédiction
        // - copie la probabilité existante, variance, etc. dans les statistiques de l'attribut
        // pour les attributs discrets :
        // - détecte l'état le plus probable pour prédiction
        // - calcule la probabilité d'attribut (ExistingSupport/NumCases)
        public void PostProcess()
        {
            for (uint nIndex = 0; nIndex < algo.AttributeSet.GetAttributeCount(); nIndex++)
            {
                // détermine le nombre d'états
                uint statCount = algo.AttributeSet.GetAttributeStateCount(nIndex);
                // détermine si l'attribut est continu
                bool bContinuous = (algo.AttributeSet.GetAttributeFlags(nIndex) &
                AttributeFlags.Continuous) != 0;
                AttributeStatistics attStats = this.clusterDistribution[nIndex];
                if (bContinuous)
                {
                    double ExistingSupport = attStats.StateStatistics[1].Support;
                    double sumValues = attStats.StateStatistics[1].Value.Double;
                    double dExistingMiu = sumValues / this.casesCount;
                    // Fixe la valeur pour un état existant. C'est Miu (SUM/ExistingSupport)
                    attStats.StateStatistics[1].Value.SetDouble(dExistingMiu);
                    // Fixe Prob/AdjProb pour un état existant
                    attStats.StateStatistics[1].Probability = (ExistingSupport + 1.0) / (this.casesCount +
                    attStats.StateStatistics.Count);
                    // Lisse adjustProb
                    attStats.StateStatistics[1].AdjustedProbability =
                    attStats.StateStatistics[1].Probability;
                    // Fixe Prob/AdjProb pour un état manquant
                    double MissingSupport = attStats.StateStatistics[0].Support;
                    attStats.StateStatistics[0].Probability = (MissingSupport + 1.0) / (this.casesCount +
                    attStats.StateStatistics.Count);
                    // Lisse adjustProb
                    attStats.StateStatistics[0].AdjustedProbability =
                    attStats.StateStatistics[0].Probability;
                    // Fixe Prob/AdjProb pour tout l'attribut
                    attStats.Probability = attStats.StateStatistics[1].Probability;
                    attStats.AdjustedProbability = attStats.StateStatistics[1].AdjustedProbability;
                }
                else
                {
                    // attribut discret, détecte l'état le plus populaire et calcule les probabilités
                    double ExistingSupport = 0.0;
                    for (uint nStateIndex = 0; nStateIndex < statCount; nStateIndex++)
                    {
                        double dStateSupport = attStats.StateStatistics[nStateIndex].Support;
                        attStats.StateStatistics[nStateIndex].Probability = (dStateSupport + 1.0) /
                        (this.casesCount + statCount);
                        attStats.StateStatistics[nStateIndex].AdjustedProbability =
                        attStats.StateStatistics[nStateIndex].Probability;
                        if (nStateIndex > 0)
                            ExistingSupport += dStateSupport;
                    }
                    // Fixe les statistiques globales de l'attribut
                    attStats.Probability = (ExistingSupport + statCount - 1.0) / (this.casesCount +
                    statCount);
                    attStats.AdjustedProbability = attStats.Probability;
                }
            }
        }
        public string NodeUniqueName
        {
            get
            {
                return nodeUniqueName;
            }
        }
        public ulong ClusterID
        {
            get
            {
                return (ulong)clusterID;
            }
            set
            {
                clusterID = (int)value;
                // Le nom de noeud unique est 1-based, 0 est la racine
                nodeUniqueName = (clusterID + 1).ToString("D3");
            }
        }
        public string Description
        {
            get
            {
                return description;
            }
            set
            {
                description = value;
            }
        }
        public string Caption
        {
            get
            {
                return "Cluster " + (clusterID + 1).ToString();
            }
        }
        public int Support
        {
            get
            {
                return casesCount;
            }
        }
        public void Load(ref PersistenceReader reader)
        {
            // Charge informations sur le cluster
            reader.OpenScope((PersistItemTag)VNIClusterPersistenceMarker.ClusterDescription);
            reader.GetValue(out nodeUniqueName);
            reader.GetValue(out description);
            reader.GetValue(out clusterID);
            reader.GetValue(out casesCount);
            int distLength = 0;
            reader.GetValue(out distLength);
            reader.CloseScope();
            clusterDistribution = new AttributeStatistics[distLength];
            for (int nIndex = 0; nIndex < distLength; nIndex++)
            {
                // Sauvegarde chaque dist
                reader.OpenScope((PersistItemTag)VNIClusterPersistenceMarker.ClusterDistribution);
                clusterDistribution[nIndex] = new AttributeStatistics();
                AttributeStatistics attStats = clusterDistribution[nIndex];
                double dVal;
                uint uVal;
                reader.GetValue(out dVal); attStats.AdjustedProbability = dVal;
                reader.GetValue(out uVal); attStats.Attribute = uVal;
                reader.GetValue(out dVal); attStats.Max = dVal;
                reader.GetValue(out dVal); attStats.Min = dVal;
                reader.GetValue(out dVal); attStats.Probability = dVal;
                reader.GetValue(out dVal); attStats.Support = dVal;
                int statCount;
                reader.GetValue(out statCount);
                for (int nState = 0; nState < statCount; nState++)
                {
                    StateStatistics stateStat = new StateStatistics();
                    reader.GetValue(out dVal); stateStat.AdjustedProbability = dVal;
                    reader.GetValue(out dVal); stateStat.Probability = dVal;
                    reader.GetValue(out dVal); stateStat.ProbabilityVariance = dVal;
                    reader.GetValue(out dVal); stateStat.Support = dVal;
                    reader.GetValue(out dVal); stateStat.Variance = dVal;
                    bool bIsMissing = false;
                    reader.GetValue(out bIsMissing);
                    if (bIsMissing)
                    {
                        stateStat.Value.SetMissing();
                    }
                    else
                    {
                        bool bIsIndex = false;
                        reader.GetValue(out bIsIndex);
                        if (bIsIndex)
                        {
                            uint indexVal;
                            reader.GetValue(out indexVal);
                            stateStat.Value.SetIndex(indexVal);
                        }
                        else
                        {
                            double dblVal;
                            reader.GetValue(out dblVal);
                            stateStat.Value.SetDouble(dblVal);
                        }
                    }
                    attStats.StateStatistics.Add(stateStat);
                }
            }
        }
        public void Save(ref PersistenceWriter writer)
        {
            // Sauvegarde les informations sur le cluster
            writer.OpenScope((PersistItemTag)VNIClusterPersistenceMarker.ClusterDescription);
            writer.SetValue(nodeUniqueName);
            writer.SetValue(description);
            writer.SetValue(clusterID);
            writer.SetValue(casesCount);
            writer.SetValue(clusterDistribution.Length);
            writer.CloseScope();
            for (int nIndex = 0; nIndex < clusterDistribution.Length; nIndex++)
            {
                // Sauvegarde chaque dist
                writer.OpenScope((PersistItemTag)VNIClusterPersistenceMarker.ClusterDistribution);
                AttributeStatistics attStats = clusterDistribution[nIndex];
                writer.SetValue(attStats.AdjustedProbability);
                writer.SetValue(attStats.Attribute);
                writer.SetValue(attStats.Max);
                writer.SetValue(attStats.Min);
                writer.SetValue(attStats.Probability);
                writer.SetValue(attStats.Support);
                writer.SetValue(attStats.StateStatistics.Count);
                for (int nState = 0; nState < attStats.StateStatistics.Count; nState++)
                {
                    StateStatistics stateStat = attStats.StateStatistics[(uint)nState];
                    writer.SetValue(stateStat.AdjustedProbability);
                    writer.SetValue(stateStat.Probability);
                    writer.SetValue(stateStat.ProbabilityVariance);

                    writer.SetValue(stateStat.Support);
                    writer.SetValue(stateStat.Variance);
                    writer.SetValue(stateStat.Value.IsMissing);
                    if (!stateStat.Value.IsMissing)
                    {
                        writer.SetValue(stateStat.Value.IsIndex);
                        if (stateStat.Value.IsIndex)
                        {
                            writer.SetValue(stateStat.Value.Index);
                        }
                        else
                        {
                            writer.SetValue(stateStat.Value.Double);
                        }
                    }
                }
            }
        }
        // Predict : retourne la prédiction la plus probable dans ce cluster
        public void Predict(ref PredictionResult predictionResult)
        {
            // predictionResult contient les options de prédiction et devrait être
            // rempli avec les valeurs/statistiques prédites
            AttributeGroup outputAttrs = predictionResult.OutputAttributes;
            outputAttrs.Reset();
            uint nAtt = AttributeSet.Unspecified;
            while (outputAttrs.Next(out nAtt))
            {
                // Vérfie périodiquement si le traitement a été annulé
                algo.Context.CheckCancelled();
                // Construit la prédiction
                AttributeStatistics attStats = new AttributeStatistics();
                if (predictionResult.IncludeNodeId)
                {
                    attStats.NodeId = this.NodeUniqueName;
                }

                attStats.Attribute = nAtt;
                attStats.Min = clusterDistribution[nAtt].Min;
                attStats.Max = clusterDistribution[nAtt].Max;
                attStats.Support = clusterDistribution[nAtt].Support;
                attStats.Probability = clusterDistribution[nAtt].Probability;
                attStats.AdjustedProbability = clusterDistribution[nAtt].AdjustedProbability;
                uint nStatesCount = (uint)clusterDistribution[nAtt].StateStatistics.Count;
                for (uint index = 0; index < nStatesCount; index++)
                {
                    StateStatistics clusterStateStat = clusterDistribution[nAtt].StateStatistics[index];
                    StateStatistics stateStat = new StateStatistics();
                    stateStat.AdjustedProbability = clusterStateStat.AdjustedProbability;
                    stateStat.Probability = clusterStateStat.Probability;
                    stateStat.Support = clusterStateStat.Support;
                    stateStat.Variance = clusterStateStat.Variance;
                    stateStat.ProbabilityVariance = clusterStateStat.ProbabilityVariance;
                    stateStat.Value = clusterStateStat.Value;
                    attStats.StateStatistics.Add(stateStat);
                }
                predictionResult.AddPrediction(attStats);
            }
        }
        public AttributeStatistics[] Distribution
        {
            get
            {
                return clusterDistribution;
            }
        }
        public void addValues(ArrayList values)
        {
            clusterValues = values;
        }
        public ArrayList getValues()
        {
            return clusterValues;

        }
        public VNIPatternAttribute[] getVNIAtts()
        {
            return vniatts;
        }
    }
}

VniStore.cs

Cette classe aide aux traductions de données entre Analysis Services et la routine IMSL cluster K Means.

 
Sélectionnez
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using Microsoft.SqlServer.DataMining.PluginAlgorithms;
using System.Collections;
using Imsl.Stat;
using Imsl.Math;
namespace VNI
{
    /* Ceci est une classe d'aide qui vous aidera à traduire les données
    * entre Analysis Services et les bibliothèques IMSL C#
    */
    public class VNIStore
    {
        private ArrayList caseList;
        /* référence vers l'objet Algorithm qui a détecté ce cluster */
        private VniClusterKMeansAlgorithm algo;
        private ClusterKMeans kmean;
        private double[,] cases;
        private double[,] centers;
        public VNIStore(VniClusterKMeansAlgorithm parent)
        {
            caseList = new ArrayList();
            algo = parent;
        }
        /* Fonction à exécuter. Cela dépend du choix de l'utilisateur à
        * partir de la liste des algorithmes disponibles
        */

        private void execute(String function, int cluster_count)
        {
            int m = 0;
            int seeds_inc = caseList.Count / cluster_count;
            ArrayList list = translateData(0);
            cases = (double[,])list[0];
            double[,] cluster_seeds = new double[3, ((double[])caseList[0]).Length];
            for (int i = 0; i < cluster_count; i++)
            {
                for (int j = 0; j < ((double[])caseList[0]).Length; j++)
                {
                    cluster_seeds[m, j] = cases[i * seeds_inc, j];
                }
                m++;
            }
            kmean = new ClusterKMeans(cases, cluster_seeds);
            // Traduit les données en ce qui est attendu par la fonction
            // Initialement, nous utilisons ClusterKMeans.
        }
        public void addCase(MiningCase mcase)
        {
            ArrayList attrList = new ArrayList();
            double[] varr = new double[algo.AttributeSet.GetAttributeCount()];
            bool mcontinue = mcase.MoveFirst();
            while (mcontinue)
            {
                /* utiliser attribute pour indexer dans les valeurs correctes*/
                UInt32 attribute = mcase.Attribute;
                StateValue value = mcase.Value;
                if (value.IsDouble) /*continous */
                {
                    varr[attribute] = value.Double;
                    //attrList.Add(value.Double) ;
                }
                /* pour toutes les colonnes discrètes, il y aura un index
                * représentant un état. Par exemple, une colonne avec les
                * valeurs A,B,C aura 3 indices
                * A=1, B=2, C=3
                */
                if (value.IsIndex) /*discrete */
                {

                    varr[attribute] = value.Index;
                    //attrList.Add((double)value.Index);
                }
                if (value.IsMissing) /* missing values */
                {
                    //varr[attribute] = ;
                    //attrList.Add(null);
                }
                mcontinue = mcase.MoveNext();
            }
            caseList.Add(varr);
        }
        /* traduit ArrayList des cas d'entrées en des ensembles pour des
        * structures pour la routine IMSL C#.
        * Retourne un Arraylist d'un élément qui contient l'ensemble/objet
        * qui doit être utilisé par la routine C#.
        * 0 : utilise la CaseList pour calculer la dimension de l'ensemble
        * 1-8 : utilise la CaseList et la crée en dimensions variant de 1 à * 8
        * 9 : utilisation pour données spéciales.
        * *
        */
        private ArrayList translateData(int dim)
        {
            switch (dim)
            {
                case 0:
                    return getArrayFromCaseList();
                //break;
                case 1:
                case 2:
                case 3:
                case 4:
                case 5:
                case 6:
                case 7:
                case 8:
                case 9:
                    break;
            }

            return null;
        }
        private ArrayList getArrayFromCaseList()
        {
            int rows = caseList.Count;
            if (caseList.Count == 0) return null;
            double[] attrlist;
            /* Vérifiez le premier élément. Il devrait y avoir une autre
            * arraylist avec une taille égale au nombre d'attributs dans
            * MiningCase.
            * En d'autres termes, si le tableau a 10 rangées et 5 colonnes,
            * alors cet ensemble doit avoir 5 éléments.
            *
            */
            /* Maintenant, créez un ensemble 2d dans ce code, mais nous
            * devrions avoir des objets qui convertissent cette datalist en
            * 2D, 3D, structure, etc. qui sont nécessaires à la routine CNL. * Il peut exister une classe parente qui traite de la
            * conversation principale puis certaines sous-classes qui
            * effectuent des conversions spécifiques de certaines tâches
            */
            double[,] data = new double[caseList.Count, ((double[])caseList[0]).Length];
            for (int i = 0; i < caseList.Count; i++)
            {
                attrlist = (double[])caseList[i];
                for (int j = 0; j < attrlist.Length; j++)
                {
                    /* null signifie valeur manquante */
                    data[i, j] = (double)attrlist[j];
                }
            }
            ArrayList rlist = new ArrayList();
            rlist.Add(data);
            return rlist;
        }
        public void fillClusters(InternalCluster[] clusters)
        {
            execute("ClusterKMeans", algo.num_clusters);
            centers = kmean.Compute();
            int[] cmember = kmean.GetClusterMembership();
            int[] nc = kmean.GetClusterCounts();
            // élimine les valeurs de cluster pour chaque cluster

            // fondamentalement, initialise les modèles avec leurs valeurs
            // initiales
            // cela servira à initialiser les statistiques d'attributs
            // utilisées dans la prédiction.
            for (int i = 0; i <= nc.Length; i++)
            {
                // [] indices = new int[nc[i]];
                // int m = 0;
                for (int j = 0; j < cmember.Length; j++)
                {
                    if (cmember[j] == i + 1)
                    {
                        double[] data = (double[])caseList[j];
                        /* ajoute des valeurs pour chaque attribut */
                        for (int m = 0; m < data.Length; m++)
                        {
                            clusters[i].vniatts[m].addDataValues(data[m]);
                            clusters[i].vniatts[m].setCount(nc[i]);
                        }
                    }
                }
            }
            /* initialise les statistiques pour chaque cluster selon les attributs */
            for (int i = 0; i < nc.Length; i++)
            {
            }
        }
        public double[,] getCenters()
        {
            return centers;
        }
        public int getCaseCount()
        {
            return caseList.Count;
        }
    }
}

VniPatternAttribute.cs

Cette classe sert à représenter un attribut dans le motif détecté. Un motif peut consister en un ou plusieurs attributs.

 
Sélectionnez
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
namespace VNI
{
    /* Microsoft possède le concept de Cas. Par exemple, un tableau de DB est
    * un cas. L'enregistrement dans le Cas ou le tableau sont appelés jeu
    * d'attributs. Chaque colonne dans un Case ou un tableau est appelé
    * attribut. En data mining, le travail consiste à trouver des modèles
    * dans vos données. Un motif est constitué de jeux d'attributs.
    * Par exemple, en analyse de cluster, nous pourrions trouver 3 clusters,
    * et chaque cluster aura différents jeux d'attributs.
    * Pour chaque attribut dans le modèle, il nous faut initialiser quelques
    * statistiques de base (min, max, variance, etc.)
    * Cette classe gardera trace des statistiques de base
    */
    public class VNIPatternAttribute
    {
        ArrayList dataValues;
        int count = 0;
        public VNIPatternAttribute()
        {
            dataValues = new ArrayList();
        }
        public double getMin()
        {
            if (dataValues.Count > 0)
            {
                double[] vals = (double[])dataValues.ToArray(typeof(double));
                Array.Sort(vals);
                return vals[0];
            }
            return 0;
        }
        public double getSum()
        {
            double sum = 0.0;
            foreach (Object attrobj in dataValues)
            {
                /* null signifie valeur manquante */
                if (attrobj != null)
                {
                    sum += (double)attrobj;
                }
            }
            return sum;
        }
        public double getMax()
        {
            if (dataValues.Count > 0)
            {
                double[] vals = (double[])dataValues.ToArray(typeof(double));
                Array.Sort(vals);
                return vals[vals.Length - 1];
            }
            return 0;
        }
        public double getVariance()
        {
            double variance = 0.0;
            if (getCount() == 0)
            {
                return 0;
            }
            double ExistingSupport = getCount();
            double Miu = this.getSum() / ExistingSupport;
            foreach (Object attrobj in dataValues)
            {
                /* null signifie valeur manquante */
                if (attrobj != null)
                {
                    double thisValue = (double)attrobj;
                    variance += (thisValue - Miu) * (thisValue - Miu);
                }
            }
            return variance / ExistingSupport;
        }

        public void addDataValues(double value)
        {
            dataValues.Add(value);
        }
        public int getCount()
        {
            return count;
        }
        public void setCount(int count)
        {
            this.count = count;
        }
        public ArrayList getDataValues()
        {
            return dataValues;
        }
    }
}

précédentsommaire

Copyright © 2008 Visual Numerics. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Droits de diffusion permanents accordés à Developpez LLC.