Filtrer les données avec Envision

Filtrer les données avec Envision










Accueil » Ressources » Ici

Toute analyse commerciale repose sur des données filtrées. Envision permet de filtrer vos données de façon approfondie, grâce aux conditions where et when, qui peuvent être utilisées pour filtrer les données manipulées par tout un bloc du script ou par une instruction individuelle. Le présent article est une présentation pratique de ces concepts.


Un script d'illustration

Une fois encore, commençons avec l'échantillon de données qui devrait être accessible à l'adresse /sample dans votre compte Lokad. Le script ci-dessous est modérément complexe et illustre certaines possibilités de filtre disponibles dans Envision. Si vous ne l'avez encore fait, nous vous recommandons de tout d'abord lire Faire des calculs avec Envision, avant de consulter les informations du présent article.
read "/sample/Lokad_Items.tsv"
read "/sample/Lokad_Orders.tsv" as Orders

show label "Filtering and Aggregating with Envision" a1f1 tomato

oend := max(Orders.Date)

when date > oend - 365
LastYearQty = sum(Orders.Quantity)
where StockOnHand + StockOnOrder > LastYearQty
show table "Overstocked items, +1 year of stock" a2f3 tomato with 
Id
Name
StockOnHand + StockOnOrder as "Stock"
LastYearQty

where Orders.NetAmount > 1000
show table "Large transactions over $1000" a4f5 tomato with 
Id
Name 
Orders.Date 
Orders.Quantity
Orders.NetAmount
Orders.Client

when date >= monday(oend) - 52 * 7 & date < monday(oend)
Week.sold := sum(Orders.NetAmount)
show linechart "Sold by week{$}" a6f7 tomato with Week.sold

Nous recommandons de copier-coller ce script dans votre compte Lokad et de l'exécuter une fois afin de visualiser le tableau de bord qui en résulte. Si tout fonctionne correctement, vous devriez voir les mêmes éléments que ci-dessous.

Image

Les blocs filtrés

Lorsque l'on souhaite travailler sur des données historiques qui ont moins d'un an, par exemple, beaucoup de calculs doivent être effectués. Dans une telle situation, le filtre « seulement de l'année passée » doit s'appliquer à tous les calculs. Pour cette raison, dans Envision, les filtres s'appliquent en général à toutes les données manipulées par un bloc de code. L'extrait de script ci-dessous illustre deux blocs filtrés imbriqués. Le premier commence à la ligne 1 avec une condition when et il est suivi d'un second bloc qui commence à la ligne 3 avec une condition where.
when date > oend - 365
LastYearQty = sum(Orders.Quantity)
where StockOnHand + StockOnOrder > LastYearQty
show table "Overstocked items, +1 year of stock" a2f3 tomato with
Id
Name
StockOnHand + StockOnOrder as "Stock"
LastYearQty
Envision est un langage qui prend en compte les espaces en début de ligne. Un ensemble de lignes qui commencent par le même nombre d'espaces est appelé un « bloc de code », ces blocs peuvent être imbriqués, c’est-à-dire qu'un bloc peut en contenir un autre.

Si c'est la première fois que vous rencontrez un tel modèle de programmation, cela peut vous paraître un peu déconcertant. Mais, dans la pratique, l'éditeur Envision vous aide beaucoup : lorsque vous appuyez sur Entrée à la fin d'une ligne qui contient une condition, la ligne suivante est automatiquement indentée avec deux espaces.

Note aux développeurs : la gestion des espaces est similaire à celle utilisée en Python. Cette approche est bien appropriée à Envision qui cherche à proposer une syntaxe concise pour manipuler des données. Puisqu'il n'y a pas de boucle ni de saut dans Envision, le niveau d'indentation est rarement supérieur à 3, ce qui reste raisonnable.

Un bloc filtré commence avec une condition — informations détaillées à ce sujet ci-dessous — qui peut être vraie ou fausse pour chaque ligne de chaque table. Au sein du bloc, seules les lignes qui remplissent la condition initiale sont manipulées, les autres en sont exclues. La condition when correspond à un filtre temporel et s'applique à toutes les tables indexées avec une colonne Date. La condition where est généralement utilisée pour filtrer les articles et s'applique aux tables indexées avec une colonne Id.

Une fois un bloc commencé, seules les lignes de données qui remplissent la condition sont gardées. Tout le reste fonctionne normalement, et toutes les commandes envisageables en dehors d'un bloc peuvent y être incluses. Il est notamment possible de définir un second filtre au sein d'un bloc. Il s'agit d'une « imbrication ». Dans l'exemple ci-dessus, le bloc where, qui commence à la ligne 3, est imbriqué dans le bloc when, qui lui commence à la ligne 1.

Créer une condition

Une condition est une expression qui peut être vraie ou fausse. La notion de filtre repose sur la composition des conditions qui sont évaluées avec les données d'entrée et éventuellement les résultats de calculs intermédiaires. Il est possible de créer des conditions évoluées dans Envision, comme le montre le script qui suit :
when date >= monday(oend) - 52 * 7 & date < monday(oend)
  Week.sold := sum(Orders.NetAmount)
  show linechart "Sold by week{$}" a6f7 tomato with Week.sold
Dans cet extrait, l'opérateur and indique que les deux expressions à gauche et à droite de l'opérateur doivent être vraies. Les opérateurs logiques utilisables dans Envision sont : and, or and not. De plus, les nombres peuvent être comparés avec des opérateurs numériques : == (égalité), != (inégalité), <= (inférieur ou égal), >= (supérieur ou égal), < (inférieur), > (supérieur). L'extrait ci-dessous illustre comment ces opérateurs peuvent être combinés et évalués.
a := 1 > 10 // faux
b := not a // vrai
c := a | b // vrai
d := a & b // faux
e := 10 >= 3 | 5 > 7 // vrai
show table "Conditions" with a, b, c, d, e
Lorsqu'un filtre de bloc est imbriqué dans un autre, la logique d'un opérateur and s'applique entre les conditions des deux filtres.

Dans l'exemple ci-dessus, vous avez peut-être remarqué la syntaxe monday(end). C'est un appel de la fonction monday. Pour n'importe quelle date, cette fonction renvoie le dernier lundi avant la date indiquée en argument (incluse). Si l'argument est un lundi, la fonction renvoie la même date.

Cette fonction Monday() est utilisée pour définir une période composée de semaines complètes (et non partielles). En effet, lorsque l'on effectue un regroupement à la semaine, seules les semaines complètes doivent être prises en compte sinon la première et la dernière valeur seraient très basses puisque calculées sur des semaines incomplètes.

Filtrer les tables par date

Envision permet de filtrer les tables avec des conditions temporelles de façon approfondie. Le script ci-dessus filtre toutes les lignes qui ont plus d'un an. Détaillons les commandes concernées.
oend := max(Orders.Date)
when date > oend - 365
  LastYearQty = sum(Orders.Quantity)
Envision traite les dates comme des nombres entiers de jours depuis le 1er janvier 2001. Ceci offre de nombreux avantages dont la possibilité d'effectuer des opérations arithmétiques sur les dates. Par exemple, en soustrayant 7 à une date, on atteint la semaine précédente, tandis qu'en soustrayant 365, on atteint (approximativement) la date de l'année précédente.

Le mot-clé date a aussi un fonctionnement spécial. De façon implicite, la variable date correspond à toutes les tables qui contiennent une colonne Date. Puisqu'une seule table est manipulée ici, la table Orders, c'est comme si nous écrivions Orders.Date > oend - 365. Cependant, la syntaxe date est non seulement plus précise mais elle s'applique à toutes les tables concernées en une fois. Si, au lieu de chercher les quantités vendues, nous nous étions intéressés aux quantités achetées, le script aurait été le suivant :
read "/sample/Lokad_PurchaseOrders.tsv" as PO // chargement des commandes d'achat

// coupure

when date > oend - 365
  LastYearQty = sum(PO.Quantity)

Filtrer les articles

Envision offre également la possibilité de filtrer les articles, ce qui est utilisé fréquemment pour exclure certains produits, certains sites, certaines catégories, etc. Le script en haut de la présente page illustre comment le périmètre peut être limité à des articles dont le stock peut être qualifié de mort. Les lignes de code concernées sont les suivantes :
where StockOnHand + StockOnOrder > LastYearQty
show table "Overstocked items, +1 year of stock" a2f3 tomato with
Id
Name
StockOnHand + StockOnOrder as "Stock"
LastYearQty
Le mot-clé where est suivi d'une condition. Celle-ci s'applique aux trois vecteurs qui appartiennent implicitement à la table Items. En effet, c'est la seule table à laquelle il est possible de faire référence sans indiquer son nom en préfixe du nom d'une variable. Par exemple, il faut écrire Orders.NetAmount et pas simplement NetAmount pour faire référence à la table Orders. Ici, la condition doit être comprise ainsi : n'inclure que les articles pour lesquels la somme du stock disponible et du stock en commande est supérieure au nombre d'unités vendues l'année passée.

Une fois qu'une condition est définie pour la table Items, toutes les tables qui contiennent une colonne Id — un identifiant qui fait référence aux articles, conformément aux conventions Envision — sont filtrées de la même façon. Ce fonctionnement est identique pour les filtres temporels, dont nous avons parlé précédemment. En effet, une fois que les articles sont filtrés, il est inutile de garder des ventes ou des achats qui ne sont pas rattachés aux articles sélectionnés mais à des articles exclus du périmètre.

Les vecteurs nouvellement calculés sont impactés par le filtre qui s'applique aux articles, comme l'illustre ce petit script.
where StockOnHand > 5
  GreaterThanFive = "yes"
  show table "Hello" with Name, GreaterThanFive // CORRECT!
// fin du bloc
show table "Hello" with Name, GreaterThanFive // INCORRECT!
La ligne 5 est erronée parce que le vecteur GreaterThanFive n'est défini que pour les lignes pour lesquelles la condition StockOnHand > 5 est vraie. Donc, même si ce vecteur est correctement défini dans le bloc et peut être utilisé comme en ligne 3, il ne peut être utilisé en dehors du bloc car certaines de ses valeurs seraient indéfinies. Ces situation eut être corrigées en veillant à ce que le vecteur soit défini correctement pour toutes ses valeurs d'article, comme ci-dessous.
GreaterThanFive = "no"
where StockOnHand > 5
  GreaterThanFive = "yes"
  show table "Hello" with Name, GreaterThanFive // CORRECT!
// fin du bloc
show table "Hello" with Name, GreaterThanFive // CORRECT!
Cet extrait commence, à la ligne 1, avec une définition correcte du vecteur GreaterThanFive pour tous les articles. Cette définition est modifiée en ligne 3 pour un sous-ensemble d'articles. Cependant, cette modification ne change rien au fait que le vecteur GreaterThanFive est défini explicitement pour tous les articles et, par conséquent, l'affiche en ligne 6 est maintenant correct.

Filtrer les tables arbitraires

Si les filtres sur les dates et les articles sont utiles, il est parfois nécessaire de filtrer de façon précise une table en particulier. C'est possible avec le mot-clé where, voyons un exemple.
where Orders.NetAmount > 1000
show table "Large transactions over $1000" a4f5 tomato with
Id
Name
Orders.Date
Orders.Quantity
Orders.NetAmount
Orders.Client
Avec ce script, la table Orders est filtrée pour exclure toutes les lignes où la commande est inférieure à 1 000 $. Les lignes de données conservées sont affichées avec show table aux lignes 2 et 3. L'exemple montre comment filtrer une seule table. Ce filtre n'impacte en effet que la table Orders et ne concerne pas les autres tables.

Si un vecteur associé à la table Orders est calculé dans le bloc du filtre, alors ce vecteur ne peut être manipulé qu'au sein du bloc. Nous avons déjà observé ce fonctionnement pour les articles, voyons maintenant comment cela s'applique également aux tables arbitraires.
where Orders.NetAmount > 1000
  Orders.LargeTxn = "yes"
  show table "Large transactions" with Name, Orders.LargeTxn // CORRECT!
// fin du bloc
show table "Large transactions" with Name, Orders.LargeTxn // INCORRECT!
Puisque le vecteur Orders.LargeTxn n'est pas défini pour toutes les lignes de la table Orders, seule la ligne 3 est correcte, la ligne 5 est incorrecte. Comme dans l'exemple précédent, la solution consiste à définir correctement une valeur LargeTxn pour l'ensemble de la table Orders, comme suit :
Orders.LargeTxn = "no"
where Orders.NetAmount > 1000
  Orders.LargeTxn = "yes"
  show table "Large transactions" with Name, Orders.LargeTxn // CORRECT!
// fin du bloc
show table "Large transactions" with Name, Orders.LargeTxn // CORRECT!
De manière générale, Envision permet les fuites en dehors de blocs autant que possible : un vecteur calculé dans un bloc peut être utilisé en dehors de ce bloc, tant que cet usage n'enfreint pas la règle selon laquelle toutes les valeurs du vecteur doivent être définies explicitement lorsque ce dernier est à droite dans une condition.

Conditions en une ligne avec les suffixes de condition

Jusqu'à présent, toutes les conditions que nous avons observées étaient rédigées sous forme de bloc. Envision offre également une syntaxe alternative, plus compacte, que l'on appelle les suffixes de condition. Revenons au calcul des quantités vendues l'année passée.
when date > oend - 365
  LastYearQty = sum(Orders.Quantity)
Ce script peut être réécrit comme suit :
LastYearQty = sum(Orders.Quantity) when date > oend - 365
Le lecteur qui connait les bases de données relationnelles rapprochera cette syntaxe de la façon dont les conditions where sont rédigées en SQL. Dans Envision, c'est principalement un sucre syntaxique pour éviter des blocs d'une ligne lorsqu'une seule instruction est nécessaire après le filtre. where et when peuvent tous deux être ajoutés en tant que suffixes tout à droite d'une instruction.

Les agrégateurs peuvent être filtrés avec les conditions when ou where. Envision offre aussi la possibilité d'ajouter un modificateur else à la condition. L'exemple suivant est incorrect :
oend := max(Orders.Date)
Week.sold := sum(Orders.NetAmount) when date < monday(oend)
show linechart "Sold by week" with Week.sold // WRONG
En effet, Week.sold n'est pas défini sur tout le périmètre car filtré à la deuxième ligne, mais, en ajoutant l'option else, nous définissons Week.sold pour tous les cas :
oend := max(Orders.Date)
Week.sold := sum(Orders.NetAmount) when date < monday(oend) else 0
show linechart "Sold by week" with Week.sold // CORRECT