[SSAS] Data Mining avec PowerPivot

Cela fait quelques temps que je voulais parler de l’intégration de deux features de SSAS liées à Excel: le Data Mining et PowerPivot, ou comment utiliser des données issues de PowerPivot avec les addins Excel de Data Mining (Table Tools et Data Mining Addin, sortis en 2007).

L’excellent Kasper de Jonge a sorti un super webcast résumant bien la technique. Le doublonnage d’informations n’étant pas mon dada je vais juste me contenter de vous donner la vidéo et de résumer le contenu pour les non anglophones.

Ceci dit – certes je suis un peu overbooké mais j’ai le temps de pondre un peu de réflexion – j’ai eu l’idée une petite feature qu’il a sûrement oublié d’aborder en fin d’article: combiner les expressions PowerPivot avec du DMX grâce aux fonctions Excel type DMPREDICT.

Alors voici l’objet:

Les addins Data Mining ne fonctionnent pas – encore? – sur des PivotTables (si vous avez fait du VSTO vous savez sûrement que la PivotTable est un objet très « à part » dans le modèle d’Excel), donc le but de l’affaire est de faire un Convert to formula d’une PivotTable d’analyse (qui va la convertir en sheet « Classique »), les expressions venant du cube étant alors spécifiées en tant que fonction CUBEMEMBER/CUBEVALUE qui prennent en paramètre des expressions « MDX » (notez les guillemets).

Dès lors utiliser les addins ne posent plus aucun problème, puisque vous êtes confrontés à des données « brutes », dont l’originie PowerPivotesque ne gène nullement l’analyse. A vous les « Analyze Key Influencers » et autres joyeusetés. Nota bene bene bene: les addins DM ne sont dispos qu’en… 32 bits donc oubliez le PowerPivot 64bits sur Excel 64bits. Espérons que cela changera…

Le tout petit rajout…

Bon en gros vous savez sûrement qu’il est possible d’appeller du DMX indirectement depuis une sheet Excel, basiquement cela a déjà été décrit par Bogdan Crivat (dont le départ chez Predixion fera aussi l’objet d’un post lorsque-j’aurai-plus-de-temps) dans ce post et qui peut être résumé ainsi:

La fonction Excel DMPREDICT permet de faire une requête de prédiction de type « simple » sur un modèle de mining dans Excel, elle a ce pattern:

DMPREDICT
(
« NomDeMaConnexionSSAS »,

« NomDeMonModele »,
« NomDeMaSortieDeModele »,
« NomParametre1 », « ValeurParametre1 »,
…,
« NomParametreN », »ValeurParametreN »
)

Il est donc parfaitement possible d’effectuer une requête DMX sur des données issues de PowerPivot et mises à plat en mode convert to formulas… et donc de marier DAX et DMX…

[TD 2010] Webcasts

Les Webcasts des TechDays 2010 sont en ligne à cette adresse: http://www.microsoft.com/france/vision/mstechdays10/. Pour ma petite personne vous trouverez ci-dessous les deux sessions que j’ai eu le plaisir d’animer:

Celle sur la mise en place de cross-selling sur les sites e-commerce:

http://www.microsoft.com/france/vision/mstechdays10/Webcast-iframe.aspx?EID=1fa11288-4b1a-491a-a372-0a73f0e82dab

Et celle sur le CEP avec StreamInsight:

http://www.microsoft.com/france/vision/mstechdays10/Webcast-iframe.aspx?EID=da22183d-b064-4567-9cf8-d1bcb4a914f0

A bientôt et bon visionnage!

Local Mining Models depuis des modèles serveur

Je me suis une fois posé cette question simple: est il possible, à la manière d’un CREATE GLOBAL CUBE, de créer des modèles de mining locaux stockés dans des .cub (destinés à des applications embarquées) depuis des modèles serveur déjà développés.

Les applications seraient énormes pour des terminaux mobiles déconnectés, dont on mettrait à jour périodiquement un petit modèle d’analyse généré en central.

La réponse au problème est oui, d’où ce post, modulo un petit peu de travail. J’ai fait le boulot sous SSIS pour plus de clarté mais l’intégralité peut se faire depuis du code .NET.

1) Récupérer le script ASSL de création du modèle serveur

Dans une script task, un brin d’AMO suffit à récupérer ce script, grâce à l’objet Scripter utilisé par l’ami Management Studio.

 // Connexion au serveur
Server svr = new Server();
svr.Connect(---);

//Recuperation de la MiningStructure
MajorObject[] source = new MajorObject[1];
source[0] = (MajorObject)svr.Databases["Adventure Works DW 2008 EE"].MiningStructures["Targeted Mailing"];

//Instanciation d'un scripter
Scripter scr = new Scripter();
XmlWriterSettings settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;

//Ecriture en mémoire depuis un XMLWriter
StringBuilder sb = new StringBuilder();
XmlWriter writer = XmlWriter.Create(sb,settings);
scr.ScriptCreate(source, writer, true);
writer.Flush();
writer.Close();
svr.Disconnect();

//Affectation de la variable;
Dts.Variables["TempXMLAHolder"].Value = sb.ToString();
Dts.TaskResult = (int)ScriptResults.Success;

2) Retravailler le XMLA avec XPath

Le XMLA généré n’est pas très utilisable: il comprend encore des bindings aux DSV de la source, ainsi que des noms d’objets invalides. Un peu de DOM/XPath suffit à retravailler tout cela modulo la connaissance basique de XMLA.
De plus les modèles de mining embarqués ne supportent que les algos de clustering et de decision trees (les algos 2000), il faut donc supprimer les autres.

 string xmla = Dts.Variables["TempXMLAHolder"].Value.ToString();
string asDbName = Dts.Variables["SsasDatabaseName"].Value.ToString();

//Chargement du doc XML
XmlDocument doc = new XmlDocument();
doc.Load(new StringReader(xmla));
XmlNamespaceManager mgr = new XmlNamespaceManager(doc.NameTable);
mgr.AddNamespace("Ns", @"http://schemas.microsoft.com/analysisservices/2003/engine");

//Changement de la base de données
doc.SelectSingleNode("/Ns:Create/Ns:ParentObject/Ns:DatabaseID", mgr).InnerText = asDbName;

//Suppression du binding de la MS à la DSV
XmlNode n = doc.SelectSingleNode("/Ns:Create/Ns:ObjectDefinition/Ns:MiningStructure/Ns:Source", mgr);
n.ParentNode.RemoveChild(n);

//Suppression des MiningModels non conformes
XmlNodeList l = doc.SelectNodes("/Ns:Create/Ns:ObjectDefinition/Ns:MiningStructure/Ns:MiningModels/Ns:MiningModel", mgr);
string algo = string.Empty;
for (int i = 0; i ; i++)
{
algo = l[i].ChildNodes[2].InnerText;
if (algo != "Microsoft_Decision_Trees" && algo != "Microsoft_Clustering")
{
bool b = true;
Dts.Events.FireInformation(0,
string.Empty,
"Le modèle doit être de type MDT ou MC, modèle de type " + algo + " supprimé.",
string.Empty,
0, ref b);
l[i].ParentNode.RemoveChild(l[i]);
}
}
Dts.Variables["TempXMLAHolder"].Value = doc.OuterXml;
Dts.TaskResult = (int)ScriptResults.Success;

3) Créer un cube local et appliquer l’ASSL dessus

Ceci fait il ne reste qu’à créer un cube local, grâce à la petite ruse de Chris Webb.
Puis à appliquer le script XMLA créé à ce cube (une simple AdomdCommand XMLA du script issu du Scripter AMO et retravaillé en XML).

On dispose alors… de modèles de mining dans un cube local!

4) Entrainer le modèle local

Mais il reste encore à les entraîner. Inutile de préciser que les tâches SSIS classiques sont inopérantes. Elles envoient des erreurs exotiques aidant à comprendre que leur usage devra être contourné.
Pour l’alimentation je suis passé par un paramètre DMX de type DataTable dans un INSERT INTO MINING STRUCTURE comme expliqué par Jamie McLennan dans un de ses posts pré-départ. Cette DataTable est dérivée du très oldschool ADO Recordset de SSIS – beuark – dans un script dédié. Modulo l’ordonnancement des colonnes pour la jointure naturelle voilà un modèle entraîné.

4) Action!

Il suffit alors de l’utiliser, en ADOMD.NET avec une chaîne de connexion pointant sur le fichier .cub en tant que Data Source et voici la « belle » application:


Le package complet est disponible ici et vous pouvez le tester. Il ressemble à cela:


En espérant avoir suscité quelques scénarii de mining embarqué…

A bientôt!

Réentrainement incrémental dans Analysis Services Data Mining

Une question qui m’est assez souvent posée: la possibilité ou non de procédéer à un apprentissage incrémental dans Analysis Services.
La réponse est nativement non contrairement au fait qu’en AMO les modèles disposent d’une propriété AllowIncrementalInsert qui peut être à true…
C’est un objectif à terme mais aujourd’hui ce n’est pas le cas.

Il faut donc ruser et dans ce type de problématique SSIS est encore une fois votre ami.

L’idée générale est d’activer le DrillThrough dans le modèle considéré et à chaque apprentissage de disposer de deux sources unionées:
– Les nouvelles données récupérées via une OLE DB Source
– Les anciennes données récupérées via une source OLE DB sur AS, avec une requêtre DMX du style

SELECT * FROM [Modèle].CASES

Voilà n’hésitez pas pour toute question.
A bientôt!

[SSAS] Utiliser les viewers Data Mining dans un BackOffice Winforms

Petit post très court pour donner des idées. Pour intégrer les viewers de modèles de Data Mining disponibles dans Visual Studio au sein d’Excel, les développeurs de Redmond ne les ont pas recodés. Ils ont simplement profité du fait que ceux ci sont disponibles en tant que composants Winforms et que vous pouvez faire de même, à savoir les réutiliser dans vos applications.
Il suffit pour cela de les ajouter à la Toolbox Winforms, en allant chercher l’assembly Microsoft.AnalysisServices.Viewer.dll qui doit se trouver dans le dossier Common7\IDE\PrivateAssemblies de votre installation de Visual Studio.

A vous les jolis backoffices!
A bientôt!

[SSAS] L’opérateur UNION manquant en DMX

Il vous est peut être arrivé de vouloir intégrer un Forecast généré avec Analysis Services Data Mining dans une application. C’est très joli à présenter, et ça l’est encore plus au sein d’un rapport Reporting Services.

Malheureusement, l’instruction PredictTimeSeries() qui gouverne la sortie d’un modèle de type TimeSeries ne permet que d’effectuer des sorties de données passées OU futures mais pas les deux mixées… Or l’ami Reporting Services ne supporte qu’un DataSet par DataRegion donc impossible de réaliser nativement une belle courbe avec le réel suivi du forecast…

Jamie Mc Lennan l’architecte du produit, propose sur son blog de réaliser une SP managée pour rempalcer PredictTimeSeries. Solution efficace et que j’ai déjà testé, mais qui masque à mon avis un problème de DMX, le manque d’opérateur UNION en n’adressant qu’une seule problématique induite.

En codant un petit bout de C# on arrive pourtant facilement à obtenir un pseudo opérateur union parfaitement fonctionnel, d’abord en écrivant une méthode d’exécution de code DMX renvoyée sous forme de DataTable:

private DataTable ExecuteQuery(string query)
{
using (AdomdCommand cmd = new AdomdCommand(query))
{
AdomdDataReader dr = cmd.ExecuteReader();
DataTable destinationDt = new DataTable();
DataTable schemaDt = dr.GetSchemaTable();
foreach (DataRow schemaDr in schemaDt.Rows)
{
destinationDt.Columns.Add((string)schemaDr["ColumnName"], (Type)schemaDr["DataType"]);
}

DataRow currentDr = null;
while (dr.Read())
{
currentDr = destinationDt.NewRow();
for (int i = 0; i < dr.FieldCount; i++)
{
currentDr[i] = dr[i];
}
destinationDt.Rows.Add(currentDr);
}
}
return destinationDt;
}

Qu'il suffit ensuite d'utiliser avec cette méthode:

private DataTable ForgeUnionDMX(params object[] dmxQueries)
{
DataTable t1 = this.ExecuteQuery(dmxQueries[0].ToString());
for (int i = 1; i < dmxQueries.Length; i++)
{
t1.Merge(this.ExecuteQuery(dmxQueries[i].ToString()));
}
return t1;
}

Malheureusement, et c'est le seul point que je n'ai pas réussi à résoudre, il semble qu'Analysis Services soit incapable de reconnaitre les procédures stockées acceptant un paramètre de type params (ParamArray en VB).
Ce n'est donc pas cette méthode qu'il faut exposer mais plutôt autant d'alias qu'on souhaite accepter de paramètres...

public DataTable UnionDMX(string dmxQuery1, string dmxQuery2)
{
return this.ForgeUnionDMX(dmxQuery1, dmxQuery2);
}
public DataTable UnionDMX(string dmxQuery1, string dmxQuery2, string dmxQuery3)
{
return this.ForgeUnionDMX(dmxQuery1, dmxQuery2, dmxQuery3);
}

Sale et dommage, mais inéluctable semble-t-il: Greg Galloway et Darren Gosbell ont fait de même à de nombreux endroits dans le projet ASSP.

Voilà à vous de coller ça dans un projet C# et de l'essayer: vous allez voir c'est très joli et cela constitue un argument assez immédiat en faveur de ce type d'applications

A bientôt.

[Jamie Mc Lennan] Comprendre le nommage des colonnes MDX en DMX

Astuce assez connue par les utilisateurs de DMX – inconnue de beaucoup donc! – mais sans laquelle je n’aurais jamais pu écrire sereinement le bout de code ci dessous. Celle-ci répond à la question suivante: comment deviner le nommage – barbare – des colonnes généré par la mise à plat du MDX, cela lorsque l’on prend un cube comme source de prediction join en DMX?

Tout simplement en faisant une requête comme ceci:

SELECT t.*
FROM [MyModel]
NATURAL PREDICTION JOIN
(
[MyMDXQuery]
) AS t

Le moteur renvoie alors le résultat mis à plat de la requête MDX et le nom des colonnes généré 🙂

Voilà, merci à Jamie et son équipe d’inclure ce genre de trick dans le langage. Vous pouvez (re) lire son papier ici.

A bientôt!

Data Mining et OLAP: Scénario de Cross-Selling

Aux TechDays, il y a bientôt 6 mois, nous avions abordé avec Romuald Coutaud le scénario de Forecasting depuis un cube OLAP, avec insertion des prévisions dans le cube. J’ai eu l’idée d’un scénario alternatif de démonstration de la complémentarité du DataMining et de l’OLAP: l’utilisation d’algorithmes de Cross-Selling en compléments d’un outil d’analyse multidimensionnelle.

L’idée générale est d’ajouter via une action la potentialité pour l’opérateur de voir à la demande, depuis son frontal, pour chaque client une liste d’items à recommander, en passant par le mécanisme de Rowset actions et du DMX.

Pour l’exemple j’ai construit un tout petit cube: c’est un sous-set de celui d’AdventureWorks2008DW: seulement 3 dimensions: Customer, Product et Time (RPD 3 fois) sur la FactInternetSales dont seules les mesures OrderQuantity et SalesAmount on été créées.

Sur ce cube, j’ai construit un MiningModel d’Association Rules, basé sur Customer en Case et Product en Nested – le bridge N-N se faisant implicitement via le groupe de mesures lorsque l’on crée des modèles en source OLAP.


Les deux étapes à suivre sont donc:

  1. Création d’une action sur les membres de la dimension Customer
  2. Exécution d’une requête DMX contextuelle sur cette action, et renvoi en rowset des prédictions.

La requête DMX se décompose elle même en deux parties:

  1. Appel de la fonction PredictAssociation qui prend en paramètre la table imbriquée à prédire (ici les futurs produits à acheter)
  2. Jointure du modèle avec deux requêtes MDX: une pour récupérer le client (SHAPE) et une autre pour récupérer les produits achetés par celui-ci (APPEND), ces deux requêtes reliées logiquement par l’ID client (RELATE..ON).

Pour chaque client on obtient donc prédictions de produits intéressants (5 étant la valeur donnée à PredictAssociation).

SELECT FLATTENED PredictAssociation([Products],5)
FROM [CrossSellingByCustomer_MAR]
PREDICTION JOIN
SHAPE
{
SELECT {[Measures].[Order Quantity]} ON 0,
{[Customer].[Customer].&[28187]} ON 1
FROM [OLAPCrossSellingCube]
}
APPEND
(
{
SELECT {[Measures].[Order Quantity]} ON 0,
NON EMPTY {[Customer].[Customer].&[28187]*[Product].[Product].[All].Children} ON ROWS
FROM [OLAPCrossSellingCube]
}
RELATE [[Customer]].[Customer]].[Customer]].[MEMBER_CAPTION]]]
TO [[Customer]].[Customer]].[Customer]].[MEMBER_CAPTION]]]
)
AS n
AS t
ON [CrossSellingByCustomer_MAR].[Products].[Product] =
t.n.[[Product]].[Product]].[Product]].[MEMBER_CAPTION]]]

Il ne reste plus qu’à créer une action de cube, de type Rowset (renvoi de lignes) qui prend en instruction une chaîne de caractères à envoyer au serveur Analysis Services.

Cette action est paramétrée en déclenchement sur les membres de la hiérarchie utilisateur de la dimension Client. Cela signifie que dans un client compatible (Excel, OWC…) tout clic droit sur un membre à ce niveau donnera un menu contextuel permettant de déclencher cette action, et donc d’afficher une boîte modale contenant les prédictions effectuées pour ce membre. Le statement déclenché pour ce faire sera notre instruction DMX, en remplaçant simplement les IDs du client – en dur ci dessus – par celui du membre courant dans la hiérarchie utilisateur, via l’appel à « CurrentMember.UniqueName » (MDX).

Une fois le cube déployé on peut voir que l’action est disponible lorsque l’on browse par la bonne hiérarchie…


Ce qui permet d’afficher les prédictions pour ce membre…


Cela marche évidemment aussi pour Excel:



Quelles sont les applications de ce genre de fonctionnalités? Cela permet de voir le cube non seulement comme outil d’analyse, mais aussi et surtout comme outil non plus passif mais actif pour des interlocuteurs fonctionnels.

Le cube permet d’analyser quelles ont été les ventes (OLAP simple) quelles seront les ventes (OLAP avec données forecastées, tel que montré aux TechDays) mais aussi d’optimiser le processus de vente, en proposant les bonnes offres aux bons prospects, via une méthode éprouvée, le tout de manière intégrée et facile à mettre en oeuvre.

Voilà, en espérant vous donner des idées.

A bientôt!

Déterminer les seuils à risque pour du Churn Analysis binaire en Data Mining

L’analyse du Churn ou de l’attrition d’une base de clients est un problème connu, surtout rencontré dans les industries entretenant une relation d’abonnement avec leur utilisateur: médias, telecom, assurances. En revanche on le retrouve insuffisament cité dans les applications concrètes du mining, alors qu’il est un de ses aspects les plus intéressants. Le principe, comme souvent en statistiques ou en Data mining est assez simple: étudier l’évolution de la base client au jour J dans les jours/mois/années suivantes pour être en mesure d’imaginer si un client donné sera oui ou non amené à cesser sa relation avec la société.

La question semble donc en premier lieu binaire. En réalité personne n’est intéressé par le fait qu’un client résiliera un jour son abonnement: à terme tout le monde le fera contraint ou forcé ! Il y a donc un fort aspect temporel: la vraie question est donc plutôt:

Un client présent depuis t jours quittera-t-il la base avant d’avoir atteint t+n?

Le principal problème business est de déterminer ce n. De préférence il doit s’agir d’une date importante dans la vie du client: seuil de rentabilité, fin d’une promotion… On peut aussi le déterminer en analysant l’évolution de la base client existante pour déterminer les n intéressants.

La variable t de ma question est appellée dans la littérature – anglo-saxonne comme souvent – la tenure: c’est la période de temps depuis laquelle le client est en relation avec la société. Grâce à cet indicateur on peut analyser l’évolution d’une population inscrite au jour J.


Il est parfaitement logique que cette courbe ait une allure asymptotique vers 0: à terme tous les clients inscrits en J résilieront… C’est l’aspect commun de toute base de clients. Mais on peut aussi avec cet indicateur, « photographier » la base comme étant constituée d’une multitude de tenure différentes de cardinalités diverses, dont l’analyse peut révéler des tenures à risque qui aideront à trouver les bons modèles à construire. En calculant pour chaque tenure le risque, c’est à dire la proportion de personnes ayant atteint cette tenure avant de résilier, qui se calcule comme-ceci:

C’est l’ensemble des personnes de tenure t ayant résilié sur l’ensemble des personnes de tenure >t (ayant « survécu à la tenure t »).

On obtient une courbe, très intéressante, pouvant avoir cette allure:


Ici on voit l’allure générale des résiliations:

  • Au bout de 60 jours d’impayés dans cette société, le contrat est résilié: le pic à 60 est donc du au clients n’ayant jamais payé
  • Au bout de 90 jours c’est la fin de la promotion sur le forfait: ce second pic correspond aux personnes résiliant avant le passage au prix maximum.

On comprend donc que l’analyse du risque par tenure permet de diagnostiquer des passages risqués, et donc de construire des modèles de mining binaires, répondant à la question de la survie à certains intervalles: T60 ou T90 ici.

A bientôt!


PS: Cependant il est important de concevoir que ces deux steps concernent en réalité deux directions assez diamétralement opposées:

  • la direction financière, qui souhaitent limiter l’attirance exercée par la société sur de potentiels mauvais payeurs, d’où l’intérêt de prédire la population résiliant à T60.
  • les directions commerciale et marketing, qui souhaitent elles conserver le plus possible leur base client et vérifier l’impact des campagnes et donc souhaitent utiliser les résultats de modèles du type de T90 ci-dessus.

Cette distinction entre churn « subi » et churn choisi est importante car on adresse par essence des domaines fonctionnels diamétralement opposés, et des problématiques antagonistes.

[SSAS] Support du PMML dans Analysis Services

J’ai parlé il y a quelques jours de la possibilité d’utiliser ADAPA pour consommer des modèles PMML. On m’a alors posé la question de la nature du support de PMML dans SSAS 2008. Voici ce qui est possible en import et en export.

Export

La clause à utiliser est SELECT * FROM [Model].PMML qui va alors réaliser un export du modèle. Attention! D’une part cela n’est supporté que sur les modèles de Clustering et de Decision Trees, et d’autre part le format n’est pas du PMML 3 (comme DB2DWE ou SPSS) mais du 2.1 comme SAS. Ce qui bride quelque peu le type de représentation possible dans ces deux modèles (PMML 2 ne supporte pas les types date par exemple).

Import

C’est l’instruction CREATE MINING MODEL FROM PMML [pmml] qui réalisera l’import, le PMML doit être entre simple quotes, et toute quote contenue dans celui ci doit être doublée. De plus il doit être SIMILAIRE dans la représentation à un Clustering ou un MDT pour appeller l’un des deux reader disponibles.

Dans les cas complexes, écrire un algorithme plugin faisant office de reader est une chose qui semble réalisable… je vais me pencher là dessus.

A bientôt!