Skip to content

Commit

Permalink
Keep "build interpretable names" parameter in expert mode only
Browse files Browse the repository at this point in the history
Probleme: le naming des variables khiops n?est pas compatible avec bigquerry
- Required. The field name. The name must contain only letters (a-z, A-Z), numbers (0-9), or underscores (_),
  and must start with a letter or underscore. The maximum length is 300 characters.
- Quel est le besoin precisement ?
  - Stocker le resultat de recodage Khiops dans une table big query
    (si on utilise un dictionnaire Khiops uniquement pour produire un score, ce n?est pas un probleme)
  - Le renommage des variables est en theorie possible depuis pykhiops, mais uniquement pour les variables terminales.
    Si des variables sont impliquees dans des formules, la propagation du renommage devient complexe et hasardeuse.

Solution envisagee dans Khiops
- Ajout d'une option dans Khiops pour generer des noms de variables non interpretables (ex : "MultiTableFeature_<Index>")
  - nouveau champ de "Advanced predictor parameters", "Build interpretable names" (true par defaut)
  - impact doc et pykhiops a prevoir
- noms de variables concernes
  - variables construites pour multi-tables, arbres, texte, paires
  - variable des predicteur (ex: les probas par classe cible)
- nombreux impacts
  - generer un libelle de variable associe aux variable construites, reprenant leur nom interpretable
    - pour les dictionaires khiops
    - pour les rapport json, pour avoir a ce libelle depuis l'outil de visualisation
    - variables impactes: mutli-table et text features, paires, variables du classifier de type prob<class>...
  - les rapports d'analyse ne sont plus facilement exploitables par l'outil de viusualisation
  - les arbres, et les paires, exploitent desormais des variables non interpretables
  - imapcts pour la gestion du nommage non interpretables
    - deplacement des methodes Set|GetInterpretableNames de KDConstructionDomain vers KWClass
    - parametrage des nom de variables des KWAttributeSubsetStats via des methodes Set|GetSortNameIndex
    - nouvelles methodes BuildInterpretableName, BuildNonInterpretableName, GetInterpretableName dans
      la hierachie de classe KWDataPreparationStats
  - impact non prevu plus grave: les resultats d'analyse ne sont pas les meme
    - en effet, les arbres par exemple exploitent des sous-ensemble de variables aleatoire
    - ceux sont sont biaises par les fort level, et repose sur un tri prealable des variables informatives
      par level decroissant, puis en cas d'agalite par nom de variable
    - le changement de nom des variable perturbe ce tri des variables, et les arbres construits ne sont plus le meme
    - solution potentielle
      - garder en interne un tri des varaiable base selon leur nom interpretable, qui ne depend pas du nom effectif des variables
        via une reimplementation de la methode CompareName
      - impact sur les paires de variables non evalue
      - complexe a gere, et a maintenir
      - solution potentielle exploitant le libvelle des variables construites
        - mais il faut gere les variables initiales differement, car pour celle-ci, on garde leur nom initial, et par leur libelle
      - solution comportement des risques d'instabilite, et/ou de contraintes fortes sur l'evolutivite du code
- ABANDON de la solution
  - rapport cout-risque-benefice trop desavantageux
  - solution simple alternative possible (cf. ci-dessous)

Solution d'ingenierie retenue
- Utiliser le "Deploy model" de Khiops
  - exporter la base saans ligne d'entete, pour ne pas avoir de probleme de noms de variablkes
    - tous les soft peuvent importer un fichier tabulaire sans en-tete
    - sinon, on peut rajouter par script une ligne d'entete Var1 Var2...
  - utiliser le "Build deployed dictionary" pour avoir 'association entre les variables exportee par rang et leur type et nom d'origine
    - facie a recuperer ensuite par script
- solution sans impact sur khiops
  - pas meme une case a cocher de type "Export interpretable names" dans la feneterv"Deploy model"
- solution facile a mettre en oeuvre
- solution generique, permettant d'exporter n'importer quel fichier tabulaire d'origine (genere par Khiops ou non)

Nettoyage du code suite a un debut d'implementation de la solution envisagee
- la solution envisagee a commence a etre codee, mais on aboutit a une impasse
- on garde neanmoins quelques modifications, qui ameliorent le code existant
- Impacts
  - DTDecisionTreeNodeSplit::CompareName
    - implementation desormais avec GetAttributeStats()->CompareName, pour se baser sur le tri des AttributeStats
  - KWDataPreparationAttributeCompareSortValue
    - implementation desormais avec GetAttributeStats()->CompareName, pour se baser sur le tri des AttributeStats
  - KWSelectedDataGridReport::GetSortName
    - base desormais sur la methode ExportVariableNames des DataGridStats
  - KDClassBuilder::BuildIndexedAttributeName: prefixe "MultiTableFeature_"
  - KDTextFeatureConstruction::BuildIndexedAttributeName: prefix "TextFeature_"
  - KDConstructionDomain::Set|GetInterpretableNames: commentaire explicite sur les limites de ce parametre
  - KDConstructionDomain.dd (et la GUI generee)
    - supression du champ InterpretableNames de l'interface
  - KWModelingSpec.dd (et la GUI generee)
     - ajout du champ InterpretableNames, pour avoir un parametre commun aux feature multi-tables et texte
  - KWModelingAdvancedSpec.dd (et la GUI generee)
    - ajout du champ InterpretableNames
    - visible uniquement en mode expert
  - KWLearningProblem::BuildConstructedClass: parametrage du construction domaine pour les InterpretableNames

Autres corrections
- KWAttributeStats: correction des assertions pour l'ecriture des "parts" dans le cas non supervise
  • Loading branch information
marcboulle committed Dec 15, 2023
1 parent 9bd6c5f commit 9d4b8aa
Show file tree
Hide file tree
Showing 19 changed files with 86 additions and 165 deletions.
10 changes: 5 additions & 5 deletions src/Learning/KDDomainKnowledge/KDClassBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ ALString KDClassBuilder::BuildConstructedAttributeName(const KDConstructedRule*
require(GetConstructionDomain()->LookupConstructionRule(rule->GetName()) != NULL);

// Construction d'un nom "interpretable"
if (KWClass::GetInterpretableNames())
if (GetConstructionDomain()->GetInterpretableNames())
sAttributeName = rule->BuildAttributeName(false);
// Numerotation des variables
else
Expand All @@ -164,7 +164,7 @@ ALString KDClassBuilder::BuildConstructedAttributeBlockName(const KDConstructedR
require(GetConstructionDomain()->LookupConstructionRule(rule->GetName()) != NULL);

// Construction d'un nom "interpretable"
if (KWClass::GetInterpretableNames())
if (GetConstructionDomain()->GetInterpretableNames())
sAttributeName = rule->BuildAttributeName(true);
// Numerotation des variables
else
Expand All @@ -180,7 +180,7 @@ ALString KDClassBuilder::BuildPartitionAttributeName(const KDConstructedPartitio
require(GetConstructionDomain() != NULL);

// Construction d'un nom "interpretable"
if (KWClass::GetInterpretableNames())
if (GetConstructionDomain()->GetInterpretableNames())
sAttributeName = partition->BuildPartitionAttributeName();
// Numerotation des variables
else
Expand All @@ -196,7 +196,7 @@ ALString KDClassBuilder::BuildTablePartitionAttributeBlockName(const KDConstruct
require(GetConstructionDomain() != NULL);

// Construction d'un nom "interpretable"
if (KWClass::GetInterpretableNames())
if (GetConstructionDomain()->GetInterpretableNames())
sAttributeName = partition->BuildTablePartitionAttributeBlockName();
// Numerotation des variables
else
Expand All @@ -212,7 +212,7 @@ ALString KDClassBuilder::BuildPartAttributeName(const KDConstructedPart* part) c
require(GetConstructionDomain() != NULL);

// Construction d'un nom "interpretable"
if (KWClass::GetInterpretableNames())
if (GetConstructionDomain()->GetInterpretableNames())
sAttributeName = part->BuildPartAttributeName();
// Numerotation des variables
else
Expand Down
11 changes: 11 additions & 0 deletions src/Learning/KDDomainKnowledge/KDConstructionDomain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ KDConstructionDomain::KDConstructionDomain()
InitializeStandardConstructionRules();
SelectDefaultConstructionRules();
nSparseBlockMinSize = 0;
bInterpretableNames = true;
bRuleOptimization = true;
bSparseOptimization = true;
bImportAttributeConstructionCosts = false;
Expand All @@ -26,6 +27,16 @@ KDConstructionDomain::~KDConstructionDomain()
odConstructionRules.DeleteAll();
}

boolean KDConstructionDomain::GetInterpretableNames() const
{
return bInterpretableNames;
}

void KDConstructionDomain::SetInterpretableNames(boolean bValue)
{
bInterpretableNames = bValue;
}

boolean KDConstructionDomain::GetRuleOptimization() const
{
return bRuleOptimization;
Expand Down
18 changes: 14 additions & 4 deletions src/Learning/KDDomainKnowledge/KDConstructionDomain.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,19 @@ class KDConstructionDomain : public Object
~KDConstructionDomain();

//////////////////////////////////////////////////////////////
// Parametrage de la construction de variables
//
// La gestion des nom de variables interpretable est parametree de facon
// generique dans la methode KWClass::GetInterpretableNames
// Parametrage experimental de la construction de variables

// Nommage des variables de facon interpretable
// . true (defaut): un nom parlant est cree
// . false: les variables sont nommees par numerotation
// Attention, le renoomage des variables construites a des consequences inattendues
// en entrainant une variation dans l'ordre des variables triees par level decroissant,
// puis par ordre alphabetique des nosm en cas d'egalite
// Comme les les arbres exploitent des sous-ensembles aleatoires de variables bases sur cet ordre
// initial, les arbres construits peuvent differer quand on active cette option
// A ne pas utiliser en exploitation
boolean GetInterpretableNames() const;
void SetInterpretableNames(boolean bValue);

// Optimisation de la classe construite par creation de variables intermediaires (defaut: true)
boolean GetRuleOptimization() const;
Expand Down Expand Up @@ -118,6 +127,7 @@ class KDConstructionDomain : public Object

// Parametres generaux de la construction de variables
int nSparseBlockMinSize;
boolean bInterpretableNames;
boolean bRuleOptimization;
boolean bSparseOptimization;
boolean bImportAttributeConstructionCosts;
Expand Down
6 changes: 3 additions & 3 deletions src/Learning/KDDomainKnowledge/KDTextFeatureConstruction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1124,7 +1124,7 @@ const ALString KDTextFeatureConstruction::BuildMainTextAttributeName(const KDTex
require(textAttributePath->GetAttributePathSize() > 1);

// Construction d'un nom "interpretable"
if (KWClass::GetInterpretableNames())
if (GetConstructionDomain()->GetInterpretableNames())
{
for (i = 0; i < textAttributePath->GetAttributePathSize(); i++)
{
Expand All @@ -1147,7 +1147,7 @@ const ALString KDTextFeatureConstruction::BuildTokenBasedAttributeName(const KWA
require(textAttribute != NULL);

// Construction d'un nom "interpretable"
if (KWClass::GetInterpretableNames())
if (GetConstructionDomain()->GetInterpretableNames())
{
// Construction du nom de variable a partir des caracteristiques du token
sAttributeName = textAttribute->GetName();
Expand All @@ -1174,7 +1174,7 @@ const ALString KDTextFeatureConstruction::BuildTokenBasedAttributeBlockName(cons
require(textAttribute != NULL);

// Construction d'un nom "interpretable"
if (KWClass::GetInterpretableNames())
if (GetConstructionDomain()->GetInterpretableNames())
{
// Construction du nom de variable a partir des caracteristiques du ngram
sAttributeName = textAttribute->GetName();
Expand Down
12 changes: 0 additions & 12 deletions src/Learning/KWData/KWClass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@
//////////////////////////////
// KWClass

boolean KWClass::bInterpretableNames = true;

KWClass::KWClass()
{
bRoot = false;
Expand Down Expand Up @@ -2150,16 +2148,6 @@ ALString KWClass::GetExternalContinuousConstant(Continuous cValue)
return sResult;
}

boolean KWClass::GetInterpretableNames()
{
return bInterpretableNames;
}

void KWClass::SetInterpretableNames(boolean bValue)
{
bInterpretableNames = bValue;
}

KWClass* KWClass::CreateClass(const ALString& sClassName, int nKeySize, int nSymbolNumber, int nContinuousNumber,
int nDateNumber, int nTimeNumber, int nTimestampNumber, int nTimestampTZNumber,
int nTextNumber, int nTextListNumber, int nObjectNumber, int nObjectArrayNumber,
Expand Down
14 changes: 0 additions & 14 deletions src/Learning/KWData/KWClass.h
Original file line number Diff line number Diff line change
Expand Up @@ -423,17 +423,6 @@ class KWClass : public Object
// dans les dictionnaires
static ALString GetExternalContinuousConstant(Continuous cValue);

// Nommage des variables de facon interpretable
// . true (defaut): un nom parlant est cree
// . false: les variables sont nommee par numerotation
// Parametrage global a respecter au mieux par tous les algorithmes creant des variables
// Le cas non interpretable est necessaire pour l'export des nouvelles variables vers des
// base de donnees tres contraintes dans le nommage (uniquemement alphanumerique et '_')
// Dans ce cas, le schema de nom preconise est de type <prefix>_<index>, en memorisant
// la version interpretable du nom dans le libelle de la variable
static boolean GetInterpretableNames();
static void SetInterpretableNames(boolean bValue);

/////////////////////////////////////////
// Fonctionnalites de test

Expand Down Expand Up @@ -627,9 +616,6 @@ class KWClass : public Object
int nFreshness;
int nIndexFreshness;
int nCompileFreshness;

// Parametres general pour la construction de variables
static boolean bInterpretableNames;
};

#include "KWAttribute.h"
Expand Down
67 changes: 5 additions & 62 deletions src/Learning/KWDataPreparation/KWAttributeSubsetStats.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@ KWAttributeSubsetStats::KWAttributeSubsetStats()
{
classStats = NULL;

// Par defaut, on construit des noms interpretables
nSortNameIndex = -1;

// L'indicateur est mis a vrai des que l'attribut cible est ajoute
// dans la liste des attributs
bIsTargetAttributePartitioned = false;
Expand Down Expand Up @@ -259,66 +256,19 @@ boolean KWAttributeSubsetStats::ComputeStats(const KWTupleTable* tupleTable)
return bIsStatsComputed;
}

void KWAttributeSubsetStats::SetSortNameIndex(int nValue)
{
require(nValue >= -1);
nSortNameIndex = nValue;
}

int KWAttributeSubsetStats::GetSortNameIndex() const
{
return nSortNameIndex;
}

const ALString KWAttributeSubsetStats::BuildInterpretableName() const
const ALString KWAttributeSubsetStats::GetSortName() const
{
ALString sInterpretableName;
ALString sSortName;
int i;

// Calcul d'un nom par concatenation des noms des attributs
for (i = 0; i < GetAttributeNumber(); i++)
{
if (i > 0)
sInterpretableName += "`";
sInterpretableName += GetAttributeNameAt(i);
sSortName += "`";
sSortName += GetAttributeNameAt(i);
}
return sInterpretableName;
}

const ALString KWAttributeSubsetStats::BuildNonInterpretableName() const
{
const ALString sPairPrefix = "VariablePair";
const ALString sSubsetPrefix = "VariableSubset";
ALString sNonInterpretableName;
int i;

require(GetAttributeNumber() > 0);
require(GetSortNameIndex() >= 0);

// Cas univarie: on rend l'attribut tel quel
if (GetAttributeNumber() == 1)
sNonInterpretableName == GetAttributeNameAt(0);
// Cas multivarie
{
if (GetAttributeNumber() == 2)
sNonInterpretableName = sPairPrefix;
else
sNonInterpretableName = sSubsetPrefix;
if (GetSortNameIndex() > 0)
{
sNonInterpretableName += "_";
sNonInterpretableName += IntToString(GetSortNameIndex());
}
}
return sNonInterpretableName;
}

const ALString KWAttributeSubsetStats::GetSortName() const
{
if (nSortNameIndex == -1)
return BuildInterpretableName();
else
return BuildNonInterpretableName();
return sSortName;
}

double KWAttributeSubsetStats::GetSortValue() const
Expand All @@ -328,11 +278,6 @@ double KWAttributeSubsetStats::GetSortValue() const
return GetLevel();
}

const ALString KWAttributeSubsetStats::GetInterpretableName() const
{
return BuildInterpretableName();
}

longint KWAttributeSubsetStats::GetUsedMemory() const
{
longint lUsedMemory;
Expand Down Expand Up @@ -1560,7 +1505,6 @@ void PLShared_AttributeSubsetStats::SerializeObject(PLSerializer* serializer, co

// Serialisation des attributs (sauf classStats et oaDataGridStats)
serializer->PutStringVector(&attributeSubsetStats->svAttributeNames);
serializer->PutInt(attributeSubsetStats->nSortNameIndex);
serializer->PutBoolean(attributeSubsetStats->GetTargetAttributePartitioned());
serializer->PutInt(attributeSubsetStats->nMaxCellNumberConstraint);
}
Expand All @@ -1577,7 +1521,6 @@ void PLShared_AttributeSubsetStats::DeserializeObject(PLSerializer* serializer,
// Deserialisation des attributs specifiques
attributeSubsetStats = cast(KWAttributeSubsetStats*, o);
serializer->GetStringVector(&attributeSubsetStats->svAttributeNames);
attributeSubsetStats->nSortNameIndex = serializer->GetInt();
attributeSubsetStats->SetTargetAttributePartitioned(serializer->GetBoolean());
attributeSubsetStats->nMaxCellNumberConstraint = serializer->GetInt();
}
Expand Down
22 changes: 0 additions & 22 deletions src/Learning/KWDataPreparation/KWAttributeSubsetStats.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,29 +56,10 @@ class KWAttributeSubsetStats : public KWDataPreparationStats
// Les attributs doivent etre initialises et leurs stats calculees
boolean ComputeStats(const KWTupleTable* tupleTable) override;

// Parametrage d'un index suffixe de nom de variable (SortName) dans le cas non interpretable
// Valeurs possible
// . -1: nom de variable interpretable (par defaut)
// . 0: nom de variable non-interpretable, sans index
// . >0: nom de variable non-interpretable, avec index en suffixe
void SetSortNameIndex(int nValue);
int GetSortNameIndex() const;

// Construction d'un nom interpretable a partir des nom des variables specifies
// Peut servir a genere ujn libelle en cas de nom de variable non-interpretable
const ALString BuildInterpretableName() const;

// Construction d'un nom non-interpretable a partir des nom des variables specifies et de l'index de nom
const ALString BuildNonInterpretableName() const;

// Redefinition des criteres de tri (le SortValue correspond a l'evaluation de la grille preparee)
// Le SortName est interpretable ou non selon le parametrage d'index du nom de variable
const ALString GetSortName() const override;
double GetSortValue() const override;

// Nom interpretable, potentiellement different du SortName
const ALString GetInterpretableName() const override;

// Memoire utilisee
longint GetUsedMemory() const override;

Expand Down Expand Up @@ -166,9 +147,6 @@ class KWAttributeSubsetStats : public KWDataPreparationStats
// Nom des attributs
StringVector svAttributeNames;

// Index du nom de variable
int nSortNameIndex;

// Specification du type d'apprentissage (partition de la cible ou pas)
// Indique si l'attribut cible fait partie des attributs du subset, et doit donc etre partitionne egalement
// Les cas suivants sont possibles:
Expand Down
13 changes: 0 additions & 13 deletions src/Learning/KWDataPreparation/KWDataPreparationBivariateTask.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -341,8 +341,6 @@ boolean KWDataPreparationBivariateTask::MasterAggregateResults()
boolean KWDataPreparationBivariateTask::MasterFinalize(boolean bProcessEndedCorrectly)
{
boolean bOk = true;
KWAttributePairStats* attributePairStats;
int i;

require(masterClassStats != NULL);

Expand All @@ -361,17 +359,6 @@ boolean KWDataPreparationBivariateTask::MasterFinalize(boolean bProcessEndedCorr
// Tri par nom, pour assurer la reproductibilite de l'ordre des resultats
oaMasterOutputAttributePairStats->SetCompareFunction(KWLearningReportCompareSortName);
oaMasterOutputAttributePairStats->Sort();

// Parametetrage si necessaire de noms de paires non interpretables
if (not KWClass::GetInterpretableNames())
{
for (i = 0; i < oaMasterOutputAttributePairStats->GetSize(); i++)
{
attributePairStats =
cast(KWAttributePairStats*, oaMasterOutputAttributePairStats->GetAt(i));
attributePairStats->SetSortNameIndex(i + 1);
}
}
}
return bOk;
}
Expand Down
6 changes: 0 additions & 6 deletions src/Learning/KWDataPreparation/KWLearningReport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -585,12 +585,6 @@ double KWDataPreparationStats::GetSortValue() const
return 0;
}

const ALString KWDataPreparationStats::GetInterpretableName() const
{
require(IsStatsComputed());
return GetSortName();
}

void KWDataPreparationStats::CleanDataPreparationResults()
{
if (preparedDataGridStats != NULL)
Expand Down
3 changes: 0 additions & 3 deletions src/Learning/KWDataPreparation/KWLearningReport.h
Original file line number Diff line number Diff line change
Expand Up @@ -180,9 +180,6 @@ class KWDataPreparationStats : public KWLearningReport
// comme dans le cas du DeltaLevel pour les paires
double GetSortValue() const override;

// Nom interpretable, par defaut egal a SortName
virtual const ALString GetInterpretableName() const;

/////////////////////////////////////////////////////////
// Structure des couts dans le cas de traitement MODL

Expand Down
7 changes: 7 additions & 0 deletions src/Learning/KWLearningProblem/KWLearningProblem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,13 @@ boolean KWLearningProblem::BuildConstructedClass(KWLearningSpec* learningSpec, K
check(kwcClass);
assert(kwcClass == KWClassDomain::GetCurrentDomain()->LookupClass(GetClassName()));

// Parametrage des noms interpretables, commune a tous les types de construction de variable
GetAnalysisSpec()
->GetModelingSpec()
->GetAttributeConstructionSpec()
->GetConstructionDomain()
->SetInterpretableNames(GetAnalysisSpec()->GetModelingSpec()->GetInterpretableNames());

// Initialisation de la construction de variables multi-tables
multiTableFeatureConstruction.SetLearningSpec(learningSpec);
multiTableFeatureConstruction.SetConstructionDomain(
Expand Down
Loading

0 comments on commit 9d4b8aa

Please sign in to comment.