Récupération d’enregistrements similaires avec des fonctions d’ordre supérieur
Utilisez les fonctions d’ordre supérieur de Data Distiller pour résoudre divers cas d’utilisation courants. Pour identifier et récupérer des enregistrements similaires ou associés d’un ou plusieurs jeux de données, utilisez le filtre, la transformation et la réduction des fonctions comme décrit dans ce guide. Pour savoir comment utiliser des fonctions d’ordre supérieur pour traiter des types de données complexes, consultez la documentation sur la gestion des types de données de tableau et de mappage.
Utilisez ce guide pour identifier les produits provenant de différents jeux de données présentant une similarité significative de leurs caractéristiques ou attributs. Cette méthodologie fournit des solutions pour : déduplication des données, liaison d’enregistrements, systèmes de recommandation, récupération d’informations et analyse de texte, entre autres.
Le document décrit le processus d’implémentation d’une jointure par analogie, qui utilise ensuite les fonctions d’ordre supérieur de Data Distiller pour calculer la similarité entre des jeux de données et les filtrer selon des attributs sélectionnés. Des fragments de code SQL et des explications sont fournis pour chaque étape du processus. Le workflow met en oeuvre des jointures par similarité à l’aide de la mesure de similarité Jaccard et de la segmentation en jetons à l’aide des fonctions d’ordre supérieur de Data Distiller. Ces méthodes sont ensuite utilisées pour identifier et récupérer des enregistrements similaires ou associés d’un ou plusieurs jeux de données basés sur une mesure de similarité. Les sections clés du processus incluent : segmentation en unités lexicales à l’aide de fonctions d’ordre supérieur, la jointure croisée d’éléments uniques, le calcul de similarité Jaccard et le }filtrage basé sur les seuils.
Conditions préalables
Avant de poursuivre ce document, vous devez connaître les concepts suivants :
-
Une similarité join est une opération qui identifie et récupère des paires d'enregistrements d'une ou plusieurs tables en fonction d'une mesure de similarité entre les enregistrements. Les principales exigences pour une jointure par analogie sont les suivantes :
- Mesure de similarité : une jointure par analogie repose sur une mesure ou une mesure de similarité prédéfinie. Ces mesures incluent : la similarité Jaccard, la similarité cosinale, la distance d’édition, etc. La mesure dépend de la nature des données et du cas d’utilisation. Cette mesure quantifie le degré de similarité ou de dissimilarité de deux enregistrements.
- Seuil : un seuil de similarité est utilisé pour déterminer quand les deux enregistrements sont considérés comme suffisamment similaires pour être inclus dans le résultat de la jointure. Les enregistrements avec un score de similarité supérieur au seuil sont considérés comme des correspondances.
-
L’index Jaccard similarity, ou la mesure Jaccard similarity, est une statistique permettant d'évaluer la similarité et la diversité d'ensembles d'échantillons. Il est défini comme la taille de l’intersection divisée par la taille de l’union des ensembles d’échantillons. La mesure similarité Jaccard est comprise entre zéro et un. Une similitude Jaccard de zéro indique qu’il n’y a aucune similitude entre les ensembles, et une similitude Jaccard de un indique que les ensembles sont identiques.
-
Les fonctions d’ordre supérieur dans Data Distiller sont des outils dynamiques intégrés qui traitent et transforment les données directement dans les instructions SQL. Ces fonctions polyvalentes éliminent la nécessité de plusieurs étapes dans la manipulation des données, en particulier lorsque traite de types complexes tels que des tableaux et des cartes. En améliorant l’efficacité des requêtes et en simplifiant les transformations, des fonctions d’ordre supérieur contribuent à une analyse plus agile et à une meilleure prise de décision dans divers scénarios commerciaux.
Commencer
Le SKU de Data Distiller est nécessaire pour exécuter les fonctions d’ordre supérieur sur vos données Adobe Experience Platform. Si vous ne possédez pas le SKU de Data Distiller, contactez votre représentant du service client Adobe pour plus d’informations.
Établir une similarité establish-similarity
Ce cas pratique nécessite une mesure de similarité entre des chaînes de texte qui peuvent être utilisées ultérieurement pour établir un seuil de filtrage. Dans cet exemple, les produits des jeux A et B représentent les mots de deux documents.
La mesure de similarité Jaccard peut être appliquée à un large éventail de types de données, y compris des données texte, des données catégoriques et des données binaires. Il est également adapté au traitement en temps réel ou par lots, car il peut être efficace sur le plan du calcul pour calculer les jeux de données volumineux.
Les ensembles de produits A et B contiennent les données de test pour ce workflow.
- Jeu de produits A :
{iPhone, iPad, iWatch, iPad Mini} - Jeu de produits B :
{iPhone, iPad, Macbook Pro}
Pour calculer la similarité Jaccard entre les ensembles de produits A et B, recherchez d’abord l’ intersection (éléments communs) des ensembles de produits. Dans ce cas, {iPhone, iPad}. Recherchez ensuite l’ union (tous les éléments uniques) des deux ensembles de produits. Dans cet exemple, {iPhone, iPad, iWatch, iPad Mini, Macbook Pro}.
Enfin, utilisez la formule de similarité Jaccard : J(A,B) = A∪B / A∩B pour calculer la similarité.
J = distance de Jaccard
A = définie 1
B = définie 2
La similitude Jaccard entre les ensembles de produits A et B est 0.4. Cela indique un degré modéré de similitude entre les mots utilisés dans les deux documents. Cette similarité entre les deux ensembles définit les colonnes de la jointure par similarité. Ces colonnes représentent des informations, ou des caractéristiques associées aux données, qui sont stockées dans un tableau et utilisées pour effectuer des calculs de similarité.
Calcul de la carte par paires avec similarité de chaînes pairwise-similarity
Pour comparer plus précisément les similitudes entre les chaînes, la similarité au niveau des paires doit être calculée. La similarité par paires divise les objets hautement dimensionnels en objets dimensionnels plus petits pour la comparaison et l’analyse. Pour ce faire, une chaîne de texte est divisée en unités ou en parties plus petites (jetons). Il peut s’agir de lettres individuelles, de groupes de lettres (comme des syllabes) ou de mots entiers. La similarité est calculée pour chaque paire de jetons entre chaque élément du jeu A et chaque élément du jeu B. Cette segmentation fournit une base pour les comparaisons analytiques et computationnelles, les relations et les informations à tirer des données.
Pour le calcul des similarités au niveau des paires, cet exemple utilise des bigrammes de caractères (jetons de deux caractères) pour comparer une correspondance de similarité entre les chaînes de texte des produits des jeux A et B. Un bi-gramme est une séquence consécutive de deux éléments ou éléments dans une séquence ou un texte donné. Vous pouvez généraliser ceci en n-grammes.
Cet exemple suppose que la casse n’a pas d’importance et que les espaces ne doivent pas être pris en compte. Selon ces critères, les ensembles A et B présentent les deux grammes suivants :
Jeu de produits A bi-grammes :
- iPhone (5) : "ip", "ph", "ho", "on", "ne"
- iPad (3) : "ip", "pa", "ad"
- iWatch (5) : "iw", "wa", "at", "tc", "ch"
- iPad Mini (7) : "ip", "pa", "ad", "dm", "mi", "in", "ni"
bi-grammes de la visionneuse de produits B :
- iPhone (5) : "ip", "ph", "ho", "on", "ne"
- iPad (3) : "ip", "pa", "ad"
- Macbook Pro (9) : "Ma", "ac", "cb", "bo", "oo", "ok", "kp", "pr", "ro"
Ensuite, calculez le coefficient de similarité Jaccard pour chaque paire :
Création des données de test avec SQL create-test-data
Pour créer manuellement un tableau de test pour les ensembles de produits, utilisez l’instruction SQL CREATE TABLE .
CREATE TABLE featurevector1 AS SELECT *
FROM (
SELECT 'iPad' AS ProductName
UNION ALL
SELECT 'iPhone'
UNION ALL
SELECT 'iWatch'
UNION ALL
SELECT 'iPad Mini'
);
SELECT * FROM featurevector1;
Les descriptions suivantes fournissent une ventilation du bloc de code SQL ci-dessus :
- Ligne 1 :
CREATE TEMP TABLE featurevector1 AS: cette instruction crée une table temporaire nomméefeaturevector1. En règle générale, les tables temporaires ne sont accessibles que dans la session en cours et sont automatiquement déposées à la fin de la session. - Ligne 1 et 2 :
SELECT * FROM (...): cette partie du code est une sous-requête utilisée pour générer les données insérées dans la tablefeaturevector1.
Dans la sous-requête, plusieurs instructionsSELECTsont combinées à l’aide de la commandeUNION ALL. Chaque instructionSELECTgénère une ligne de données avec les valeurs spécifiées pour la colonneProductName. - Ligne 3 :
SELECT 'iPad' AS ProductName: génère une ligne avec la valeuriPaddans la colonneProductName. - Ligne 5 :
SELECT 'iPhone': génère une ligne avec la valeuriPhonedans la colonneProductName.
L’instruction SQL crée un tableau comme illustré ci-dessous :
ProductNamePour créer le second vecteur de fonctionnalité, utilisez l’instruction SQL suivante :
CREATE TABLE featurevector2 AS SELECT *
FROM (
SELECT 'iPad' AS ProductName
UNION ALL
SELECT 'iPhone'
UNION ALL
SELECT 'Macbook Pro'
);
SELECT * FROM featurevector2;
Conversion des données data-transformation
Dans cet exemple, plusieurs actions doivent être effectuées pour comparer précisément les visionneuses. Tout d’abord, les espaces blancs sont supprimés des vecteurs de fonctionnalités, puisqu’il est supposé qu’ils ne contribuent pas à la mesure de similarité. Ensuite, tous les doublons présents dans le vecteur de fonctionnalité sont supprimés lorsqu’ils perdent le traitement informatique. Ensuite, les jetons de deux caractères (bi-grammes) sont extraits des vecteurs de fonctionnalités. Dans cet exemple, elles se chevauchent.
Les sections suivantes illustrent les transformations de données prérequises telles que le dédoublonnage, la suppression d’espaces et la conversion en minuscules avant de lancer le processus de segmentation en unités lexicales.
Déduplication deduplication
Ensuite, utilisez la clause DISTINCT pour supprimer les doublons. Il n’existe aucun doublon dans cet exemple, mais il s’agit d’une étape importante pour améliorer la précision de toute comparaison. Le code SQL nécessaire est affiché ci-dessous :
SELECT DISTINCT(ProductName) AS featurevector1_distinct FROM featurevector1
SELECT DISTINCT(ProductName) AS featurevector2_distinct FROM featurevector2
Suppression des espaces blancs whitespace-removal
Dans l’instruction SQL suivante, les espaces sont supprimés des vecteurs de fonctionnalités. La partie replace(ProductName, ' ', '') AS featurevector1_nospaces de la requête extrait la colonne ProductName de la table featurevector1 et utilise la fonction replace(). La fonction REPLACE remplace toutes les occurrences d’un espace (’ ’) par une chaîne vide (’). Cela supprime effectivement tous les espaces des valeurs ProductName. Le résultat comporte un alias featurevector1_nospaces.
SELECT DISTINCT(ProductName) AS featurevector1_distinct, replace(ProductName, ' ', '') AS featurevector1_nospaces FROM featurevector1
Les résultats sont présentés dans le tableau ci-dessous :
L’instruction SQL et ses résultats sur le deuxième vecteur de fonctionnalité sont présentés ci-dessous :
| code language-sql |
|---|
|
Les résultats s’affichent comme suit :
| table 0-row-3 1-row-3 2-row-3 3-row-3 layout-auto | ||
|---|---|---|
| featurevector2_distinct | featurevector2_nospaces | |
| 1 | iPad | iPad |
| 2 | Macbook Pro | MacbookPro |
| 3 | iPhone | iPhone |
Convertir en minuscules lowercase-conversion
Ensuite, le code SQL est amélioré pour convertir les noms de produits en minuscules et supprimer les espaces. La fonction inférieure (lower(...)) est appliquée au résultat de la fonction replace(). La fonction lower convertit en minuscules tous les caractères des valeurs ProductName modifiées. Cela garantit que les valeurs sont en minuscules, quelle que soit leur casse d’origine.
SELECT DISTINCT(ProductName) AS featurevector1_distinct, lower(replace(ProductName, ' ', '')) AS featurevector1_transform FROM featurevector1;
Le résultat de cette instruction est le suivant :
L’instruction SQL et ses résultats sur le deuxième vecteur de fonctionnalité sont présentés ci-dessous :
| code language-sql |
|---|
|
Les résultats s’affichent comme suit :
| table 0-row-3 1-row-3 2-row-3 3-row-3 layout-auto | ||
|---|---|---|
| featurevector2_distinct | featurevector2_transform | |
| 1 | iPad | ipad |
| 2 | Macbook Pro | macbookpro |
| 3 | iPhone | iphone |
Extraction de jetons à l’aide de SQL tokenization
L’étape suivante est la segmentation en unités lexicales ou le fractionnement de texte. La Tokenization est le processus consistant à prendre du texte et à le diviser en termes individuels. Cela implique généralement de diviser des phrases en mots. Dans cet exemple, les chaînes sont ventilées en bi-grammes (et n-grammes de plus grand ordre) en extrayant des jetons à l’aide de fonctions SQL telles que regexp_extract_all. Les doublons doivent être générés pour une segmentation efficace.
Le code SQL a été amélioré de manière à utiliser regexp_extract_all. regexp_extract_all(lower(replace(ProductName, ' ', '')), '.{2}', 0) AS tokens: Cette partie de la requête traite davantage les valeurs ProductName modifiées créées à l’étape précédente. Elle utilise la fonction regexp_extract_all() pour extraire toutes les sous-chaînes qui ne se chevauchent pas de un à deux caractères des valeurs ProductName modifiées et en minuscules. Le modèle d’expression régulière .{2} correspond à des sous-chaînes de deux caractères de longueur. La partie regexp_extract_all(..., '.{2}', 0) de la fonction extrait ensuite toutes les sous-chaînes correspondantes du texte d’entrée.
SELECT DISTINCT(ProductName) AS featurevector1_distinct, lower(replace(ProductName, ' ', '')) AS featurevector1_transform,
regexp_extract_all(lower(replace(ProductName, ' ', '')) , '.{2}', 0) AS tokens
FROM featurevector1;
Les résultats sont présentés dans le tableau ci-dessous :
| table 0-row-4 1-row-4 2-row-4 3-row-4 4-row-4 layout-auto | |||
|---|---|---|---|
| featurevector1_distinct | featurevector1_transform | jetons | |
| 1 | iPad Mini | ipadmini | {"ip","ad","mi","ni"} |
| 2 | iPad | iPad | {"ip","ad"} |
| 3 | iWatch | iWatch | {"iw","at", "ch"} |
| 4 | iPhone | iPhone | {"ip","ho","ne"} |
Pour améliorer davantage la précision, le code SQL doit être utilisé pour créer des jetons qui se chevauchent. Par exemple, la chaîne "iPad" ci-dessus ne contient pas le jeton "pa". Pour corriger ce problème, déplacez l’opérateur de recherche en amont (à l’aide de substring) d’une étape et générez les bigrammes.
Tout comme l’étape précédente, regexp_extract_all(lower(replace(substring(ProductName, 2), ' ', '')), '.{2}', 0): extrait des séquences de deux caractères du nom du produit modifié, mais commence par le deuxième caractère à l’aide de la méthode substring pour créer des jetons qui se chevauchent. Ensuite, dans les lignes 3 à 7 (array_union(...) AS tokens), la fonction array_union() combine les tableaux de séquences de deux caractères obtenus par les deux extractions d’expression régulière. Cela permet de s’assurer que le résultat contient des jetons uniques provenant de séquences qui ne se chevauchent pas et qui se chevauchent.
SELECT DISTINCT(ProductName) AS featurevector1_distinct,
lower(replace(ProductName, ' ', '')) AS featurevector1_transform,
array_union(
regexp_extract_all(lower(replace(ProductName, ' ', '')), '.{2}', 0),
regexp_extract_all(lower(replace(substring(ProductName, 2), ' ', '')), '.{2}', 0)
) AS tokens
FROM featurevector1;
Les résultats sont présentés dans le tableau ci-dessous :
| table 0-row-4 1-row-4 2-row-4 3-row-4 4-row-4 layout-auto | |||
|---|---|---|---|
| featurevector1_distinct | featurevector1_transform | jetons | |
| 1 | iPad Mini | ipadmini | {"ip","ad","mi","ni","pa","dm","in"} |
| 2 | iPad | iPad | {"ip","ad","pa"} |
| 3 | iWatch | iWatch | {"iw","at","ch","wa","tc"} |
| 4 | iPhone | iPhone | {"ip","ho","ne","ph","on"} |
Cependant, l’utilisation de substring comme solution au problème présente des limites. Si vous deviez créer des jetons à partir du texte en fonction de trois grammes (trois caractères), il faudrait utiliser deux substrings pour effectuer deux recherches en amont afin d’obtenir les décalages requis. Pour produire 10 grammes, vous avez besoin de neuf expressions substring. Cela ferait gonfler le code et cela deviendrait intenable. L’utilisation d’expressions régulières simples n’est pas appropriée. Une nouvelle approche est nécessaire.
Ajuster à la longueur du nom du produit length-adjustment
Le SQl peut être amélioré grâce aux fonctions de séquence et de longueur. Dans l’exemple suivant, sequence(1, length(lower(replace(ProductName, ' ', ''))) - 3) génère une séquence de nombres de un à la longueur du nom de produit modifié moins trois. Par exemple, si le nom du produit modifié est "ipadmini" avec une longueur de huit caractères, il génère des nombres de un à cinq (huit à trois).
L’instruction ci-dessous extrait des noms de produits uniques, puis décompose chaque nom en séquences de caractères (jetons) de quatre longueurs de caractères, à l’exclusion des espaces et les présente sous la forme de deux colonnes. Une colonne affiche les noms uniques des produits et l’autre les jetons générés.
SELECT
DISTINCT(ProductName) AS featurevector1_distinct,
transform(
sequence(1, length(lower(replace(ProductName, ' ', ''))) - 3),
i -> substring(lower(replace(ProductName, ' ', '')), i, 4)
) AS tokens
FROM
featurevector1;
Les résultats sont présentés dans le tableau ci-dessous :
| table 0-row-3 1-row-3 2-row-3 3-row-3 4-row-3 layout-auto | ||
|---|---|---|
| featurevector1_distinct | jetons | |
| 1 | iPad Mini | {"ipad","padm","admi","dmin","mini"} |
| 2 | iPad | {"ipad"} |
| 3 | iWatch | {"iwat","watc","atch"} |
| 4 | iPhone | {"ipho","phon","hone"} |
Vérification de la longueur du jeton définie ensure-set-token-length
Des conditions supplémentaires peuvent être ajoutées à l’instruction pour s’assurer que les séquences générées ont une longueur spécifique. L’instruction SQL suivante développe la logique de génération de jeton en rendant la fonction transform plus complexe. L’instruction utilise la fonction filter dans transform pour s’assurer que les séquences générées ont une longueur de six caractères. Il gère les cas où cela n’est pas possible en attribuant des valeurs NULL à ces positions.
SELECT
DISTINCT(ProductName) AS featurevector1_distinct,
transform(
filter(
sequence(1, length(lower(replace(ProductName, ' ', ''))) - 5),
i -> i + 5 <= length(lower(replace(ProductName, ' ', '')))
),
i -> CASE WHEN length(substring(lower(replace(ProductName, ' ', '')), i, 6)) = 6
THEN substring(lower(replace(ProductName, ' ', '')), i, 6)
ELSE NULL
END
) AS tokens
FROM
featurevector1;
Les résultats sont présentés dans le tableau ci-dessous :
| table 0-row-3 1-row-3 2-row-3 3-row-3 4-row-3 layout-auto | ||
|---|---|---|
| featurevector1_distinct | jetons | |
| 1 | iPad Mini | {"ipadmi","padmin","admini"} |
| 2 | iPad | |
| 3 | iWatch | {"iwatch"} |
| 4 | iPhone | {"iphone"} |
Exploration des solutions à l’aide des fonctions d’ordre supérieur de Data Distiller higher-order-function-solutions
Les fonctions d’ordre supérieur sont des constructions puissantes qui vous permettent de mettre en oeuvre une "programmation" comme la syntaxe dans Data Distiller. Ils peuvent être utilisés pour itérer une fonction sur plusieurs valeurs d’un tableau.
Dans le contexte de Data Distiller, les fonctions d’ordre supérieur sont idéales pour créer des n-grammes et itérer sur des séquences de caractères.
La fonction reduce, en particulier lorsqu’elle est utilisée dans des séquences générées par transform, permet d’obtenir des valeurs cumulatives ou des agrégats, qui peuvent être essentiels dans divers processus d’analyse et de planification.
Par exemple, dans l’instruction SQl ci-dessous, la fonction reduce() agrège des éléments dans un tableau à l’aide d’un agrégateur personnalisé. Il simule une boucle for pour créer les sommes cumulées de tous les nombres entiers de un à cinq. 1, 1+2, 1+2+3, 1+2+3+4, 1+2+3+4.
SELECT transform(
sequence(1, 5),
x -> reduce(
sequence(1, x),
0, -- Initial accumulator value
(acc, y) -> acc + y -- Higher-order function to add numbers
)
) AS sum_result;
Voici une analyse de l’instruction SQL :
-
La ligne 1 :
transformapplique la fonctionx -> reducesur chaque élément généré dans la séquence. -
Ligne 2 :
sequence(1, 5)génère une séquence de nombres de un à cinq. -
Ligne 3 :
x -> reduce(sequence(1, x), 0, (acc, y) -> acc + y)effectue une opération de réduction pour chaque élément x de la séquence (de 1 à 5).- La fonction
reduceprend une valeur d’accumulateur initiale de 0, une séquence de 1 à la valeur actuelle dexet une fonction d’ordre supérieur(acc, y) -> acc + ypour ajouter les nombres. - La fonction d'ordre supérieur
acc + yaccumule la somme en ajoutant la valeur actuelleyà l'accumulateuracc.
- La fonction
-
Ligne 8 :
AS sum_resultrenomme la colonne obtenue en tant que sum_result.
Pour résumer, cette fonction d’ordre supérieur prend deux paramètres (acc et y) et définit l’opération à effectuer, qui dans ce cas ajoute y à l’accumulateur acc. Cette fonction d’ordre supérieur est exécutée pour chaque élément de la séquence pendant le processus de réduction.
La sortie de cette instruction est une seule colonne (sum_result) qui contient les sommes cumulées de nombres comprises entre 1 et 5.
La valeur des fonctions d’ordre supérieur value-of-higher-order-functions
Cette section analyse une version abrégée d’une instruction SQL à trois grammes afin de mieux comprendre la valeur des fonctions d’ordre supérieur dans Data Distiller pour créer des n-grammes plus efficacement.
L’instruction ci-dessous fonctionne sur la colonne ProductName de la table featurevector1. Elle produit un ensemble de sous-chaînes de trois caractères dérivées des noms de produits modifiés dans le tableau, à l’aide de positions obtenues à partir de la séquence générée.
SELECT
transform(
sequence(1, length(lower(replace(ProductName, ' ', ''))) - 2),
i -> substring(lower(replace(ProductName, ' ', '')), i, 3)
)
FROM
featurevector1
Voici une analyse de l’instruction SQL :
-
Ligne 2 :
transformapplique une fonction d’ordre supérieur à chaque entier de la séquence. -
La ligne 3 :
sequence(1, length(lower(replace(ProductName, ' ', ''))) - 2)génère une séquence d’entiers entre1et la longueur du nom du produit modifié moins deux.length(lower(replace(ProductName, ' ', '')))calcule la longueur deProductNameaprès l'avoir fait en minuscules et après avoir supprimé des espaces.- 2soustrait deux de la longueur pour s’assurer que la séquence génère des positions de départ valides pour les sous-chaînes de 3 caractères. Si vous soustrayez 2, vous aurez suffisamment de caractères après chaque position de départ pour extraire une sous-chaîne de 3 caractères. La fonction de sous-chaîne ici fonctionne comme un opérateur de recherche en amont.
-
Ligne 4 :
i -> substring(lower(replace(ProductName, ' ', '')), i, 3)est une fonction d’ordre supérieur qui fonctionne sur chaque entieride la séquence générée.- La fonction
substring(...)extrait une sous-chaîne de 3 caractères de la colonneProductName. - Avant d’extraire la sous-chaîne,
lower(replace(ProductName, ' ', ''))convertit lesProductNameen minuscules et supprime les espaces pour garantir la cohérence.
- La fonction
La sortie est une liste de sous-chaînes de trois caractères, extraites des noms de produits modifiés, en fonction des positions spécifiées dans la séquence.
Filtrer les résultats filter-results
La fonction filter, avec les transformations de données suivantes, permet une extraction plus précise et plus affinée des informations pertinentes à partir des données de texte. Cela vous permet d’obtenir des informations, d’améliorer la qualité des données et de faciliter de meilleurs processus de prise de décision.
La fonction filter de l’instruction SQL suivante sert à affiner et à limiter la séquence de positions dans la chaîne à partir de laquelle les sous-chaînes sont extraites à l’aide de la fonction de transformation suivante.
SELECT
transform(
filter(
sequence(1, length(lower(replace(ProductName, ' ', ''))) - 6),
i -> i + 6 <= length(lower(replace(ProductName, ' ', '')))
),
i -> CASE WHEN length(substring(lower(replace(ProductName, ' ', '')), i, 7)) = 7
THEN substring(lower(replace(ProductName, ' ', '')), i, 7)
ELSE NULL
END
)
FROM
featurevector1;
La fonction filter génère une séquence de positions de départ valides dans le ProductName modifié et extrait les sous-chaînes d’une longueur spécifique. Seules les positions de départ permettant d’extraire une sous-chaîne de sept caractères sont autorisées.
La condition i -> i + 6 <= length(lower(replace(ProductName, ' ', ''))) garantit que la position de départ i plus 6 (la longueur de la sous-chaîne de sept caractères souhaitée moins une) ne dépasse pas la longueur du ProductName modifié.
L’instruction CASE est utilisée pour inclure ou exclure de manière conditionnelle des sous-chaînes en fonction de leur longueur. Seules les sous-chaînes de sept caractères sont incluses ; les autres sont remplacées par NULL. Ces sous-chaînes sont ensuite utilisées par la fonction transform pour créer une séquence de sous-chaînes à partir de la colonne ProductName de la table featurevector1.
Calcul de la jointure croisée d’éléments uniques sur deux vecteurs de fonctionnalités cross-join-unique-elements
Identifier les différences ou les incohérences entre les deux jeux de données en fonction d’une transformation spécifique des données est un processus courant pour maintenir la précision des données, améliorer la qualité des données et assurer la cohérence entre les jeux de données.
Cette instruction SQL ci-dessous extrait les noms de produits uniques présents dans featurevector2, mais pas dans featurevector1 après avoir appliqué les transformations.
SELECT lower(replace(ProductName, ' ', '')) FROM featurevector2
EXCEPT
SELECT lower(replace(ProductName, ' ', '')) FROM featurevector1;
EXCEPT, vous pouvez également utiliser UNION et INTERSECT en fonction de votre cas d’utilisation. Vous pouvez également tester les clauses ALL ou DISTINCT pour voir la différence entre l’inclusion de toutes les valeurs et le renvoi uniquement des valeurs uniques pour les colonnes spécifiées.Les résultats sont présentés dans le tableau ci-dessous :
| table 0-row-2 1-row-2 layout-auto | |
|---|---|
| lower(replace(ProductName, ', '')) | |
| 1 | macbookpro |
Effectuez ensuite une jointure croisée pour combiner les éléments des deux vecteurs de fonctionnalités afin de créer des paires d’éléments à des fins de comparaison. La première étape de ce processus est de créer un vecteur à jetons.
Un vecteur à jetons est une représentation structurée de données de texte dans laquelle chaque mot, expression ou unité de signification (jeton) est converti en un format numérique. Cette conversion permet aux algorithmes de traitement de langage naturel de comprendre et d’analyser les informations textuelles.
Le SQl ci-dessous crée un vecteur à jetons.
CREATE TABLE featurevector1tokenized AS SELECT
DISTINCT(ProductName) AS featurevector1_distinct,
transform(
filter(
sequence(1, length(lower(replace(ProductName, ' ', ''))) - 1),
i -> i + 1 <= length(lower(replace(ProductName, ' ', '')))
),
i -> CASE WHEN length(substring(lower(replace(ProductName, ' ', '')), i, 2)) = 2
THEN substring(lower(replace(ProductName, ' ', '')), i, 2)
ELSE NULL
END
) AS tokens
FROM
(SELECT lower(replace(ProductName, ' ', '')) AS ProductName FROM featurevector1);
SELECT * FROM featurevector1tokenized;
Les résultats sont présentés dans le tableau ci-dessous :
| table 0-row-3 1-row-3 2-row-3 3-row-3 4-row-3 layout-auto | ||
|---|---|---|
| featurevector1_distinct | jetons | |
| 1 | ipadmini | {"ip","pa","ad","dm","mi","in","ni"} |
| 2 | ipad | {"ip","pa","ad"} |
| 3 | iwatch | {"iw","wa","at","tc","ch"} |
| 4 | iphone | {"ip","ph","ho","on","ne"} |
Répétez ensuite le processus pour featurevector2 :
CREATE TABLE featurevector2tokenized AS
SELECT
DISTINCT(ProductName) AS featurevector2_distinct,
transform(
filter(
sequence(1, length(lower(replace(ProductName, ' ', ''))) - 1),
i -> i + 1 <= length(lower(replace(ProductName, ' ', '')))
),
i -> CASE WHEN length(substring(lower(replace(ProductName, ' ', '')), i, 2)) = 2
THEN substring(lower(replace(ProductName, ' ', '')), i, 2)
ELSE NULL
END
) AS tokens
FROM
(SELECT lower(replace(ProductName, ' ', '')) AS ProductName FROM featurevector2
);
SELECT * FROM featurevector2tokenized;
Les résultats sont présentés dans le tableau ci-dessous :
| table 0-row-3 1-row-3 2-row-3 3-row-3 layout-auto | ||
|---|---|---|
| featurevector2_distinct | jetons | |
| 1 | ipadmini | {"ip","pa","ad"} |
| 2 | macbookpro | {"ma","ac","cb","bo","oo","ok","kp","pr","ro"} |
| 3 | iphone | {"ip","ph","ho","on","ne"} |
Une fois les deux vecteurs segmentés en unités terminées, vous pouvez désormais créer la jointure croisée. Ceci est illustré dans le SQL ci-dessous :
SELECT
A.featurevector1_distinct AS SetA_ProductNames,
B.featurevector2_distinct AS SetB_ProductNames,
A.tokens AS SetA_tokens1,
B.tokens AS SetB_tokens2
FROM
featurevector1tokenized A
CROSS JOIN
featurevector2tokenized B;
Voici un résumé de l’interface utilisateur graphique utilisée pour créer la jointure croisée :
- Ligne 2 :
A.featurevector1_distinct AS SetA_ProductNamessélectionne la colonnefeaturevector1_distinctde la tableAet lui attribue un aliasSetA_ProductNames. Cette section de SQL génère une liste de noms de produits distincts du premier jeu de données. - Ligne 4 :
A.tokens AS SetA_tokens1sélectionne la colonnetokensde la table ou de la sous-requêteAet lui attribue un aliasSetA_tokens1. Cette section de SQL génère une liste de valeurs segmentées en unités lexicales associées aux noms de produits du premier jeu de données. - Ligne 8 : l’opération
CROSS JOINcombine toutes les combinaisons possibles de lignes des deux jeux de données. En d’autres termes, il associe chaque nom de produit et ses jetons associés à partir de la première table (A) à chaque nom de produit et à ses jetons associés à partir de la seconde table (B). Cela génère un produit cartésien des deux jeux de données, où chaque ligne de la sortie représente une combinaison d’un nom de produit et de ses jetons associés à partir des deux jeux de données.
Les résultats sont présentés dans le tableau ci-dessous :
| table 0-row-5 1-row-5 2-row-5 3-row-5 4-row-5 5-row-5 6-row-5 7-row-5 8-row-5 9-row-5 10-row-5 11-row-5 12-row-5 layout-auto | ||||
|---|---|---|---|---|
| * | SetA_ProductNames | SetB_ProductNames | SetA_tokens 1 | SetB_tokens 2 |
| 1 | ipadmini | ipad | {"ip","pa","ad","dm","mi","in","ni"} | {"ip","pa","ad"} |
| 2 | ipadmini | macbookpro | {"ip","pa","ad","dm","mi","in","ni"} | {"ma","ac","cb","bo","oo","ok","kp","pr","ro"} |
| 3 | ipadmini | iphone | {"ip","pa","ad","dm","mi","in","ni"} | {"ip","ph","ho","on","ne"} |
| 4 | ipad | ipad | {"ip","pa","ad"} | {"ip","pa","ad"} |
| 5 | ipad | macbookpro | {"ip","pa","ad"} | {"ma","ac","cb","bo","oo","ok","kp","pr","ro"} |
| 6 | ipad | iphone | {"ip","pa","ad"} | {"ip","ph","ho","on","ne"} |
| 7 | iwatch | ipad | {"iw","wa","at","tc","ch"} | {"ip","pa","ad"} |
| 8 | iwatch | macbookpro | {"iw","wa","at","tc","ch"} | {"ma","ac","cb","bo","oo","ok","kp","pr","ro"} |
| 9 | iwatch | iphone | {"iw","wa","at","tc","ch"} | {"ip","ph","ho","on","ne"} |
| 10 | iphone | ipad | {"ip","ph","ho","on","ne"} | {"ip","pa","ad"} |
| 11 | iphone | macbookpro | {"ip","ph","ho","on","ne"} | {"ma","ac","cb","bo","oo","ok","kp","pr","ro"} |
| 12 | iphone | iphone | {"ip","ph","ho","on","ne"} | {"ip","ph","ho","on","ne"} |
Calculez la mesure de similarité Jaccard compute-the-jaccard-similarity-measure
Ensuite, calculez l’utilisation du coefficient de similarité Jaccard pour effectuer une analyse des similarités entre les deux ensembles de noms de produits en comparant leurs représentations segmentées en unités lexicales. La sortie du script SQL ci-dessous fournit les éléments suivants : noms de produits des deux ensembles, leurs représentations en unités lexicales, le nombre de jetons uniques communs et totaux et le coefficient de similarité Jaccard calculé pour chaque paire de jeux de données.
SELECT
SetA_ProductNames,
SetB_ProductNames,
SetA_tokens1,
SetB_tokens2,
size(array_intersect(SetA_tokens1, SetB_tokens2)) AS token_intersect_count,
size(array_union(SetA_tokens1, SetB_tokens2)) AS token_union_count,
ROUND(
CAST(size(array_intersect(SetA_tokens1, SetB_tokens2)) AS DOUBLE) / size(array_union(SetA_tokens1, SetB_tokens2)), 2) AS jaccard_similarity
FROM
(SELECT
A.featurevector1_distinct AS SetA_ProductNames,
B.featurevector2_distinct AS SetB_ProductNames,
A.tokens AS SetA_tokens1,
B.tokens AS SetB_tokens2
FROM
featurevector1tokenized A
CROSS JOIN
featurevector2tokenized B
);
Voici un résumé du SQL utilisé pour calculer le coefficient de similarité Jaccard :
- Ligne 6 :
size(array_intersect(SetA_tokens1, SetB_tokens2)) AS token_intersect_countcalcule le nombre de jetons communs àSetA_tokens1etSetB_tokens2. Ce calcul est réalisé en calculant la taille de l’intersection des deux tableaux de jetons. - Ligne 7 :
size(array_union(SetA_tokens1, SetB_tokens2)) AS token_union_countcalcule le nombre total de jetons uniques surSetA_tokens1etSetB_tokens2. Cette ligne calcule la taille de l’union des deux tableaux de jetons. - Ligne 8-10 :
ROUND(CAST(size(array_intersect(SetA_tokens1, SetB_tokens2)) AS DOUBLE) / size(array_union(SetA_tokens1, SetB_tokens2)), 2) AS jaccard_similaritycalcule la similarité Jaccard entre les jeux de jetons. Ces lignes divisent la taille de l’intersection de jetons par la taille de l’union de jetons et arrondissent le résultat à deux décimales. Le résultat est une valeur comprise entre zéro et un, où un indique une similarité complète.
Les résultats sont présentés dans le tableau ci-dessous :
| table 0-row-8 1-row-8 2-row-8 3-row-8 4-row-8 5-row-8 6-row-8 7-row-8 8-row-8 9-row-8 10-row-8 11-row-8 12-row-8 layout-auto | |||||||
|---|---|---|---|---|---|---|---|
| * | SetA_ProductNames | SetB_ProductNames | SetA_tokens 1 | SetB_tokens 2 | token_intersect_count | token_intersect_count | Similarité de Jaccard |
| 1 | ipadmini | ipad | {"ip","pa","ad","dm","mi","in","ni"} | {"ip","pa","ad"} | 3 | 7 | 0,43 |
| 2 | ipadmini | macbookpro | {"ip","pa","ad","dm","mi","in","ni"} | {"ma","ac","cb","bo","oo","ok","kp","pr","ro"} | 0 | 16 | 0,0 |
| 3 | ipadmini | iphone | {"ip","pa","ad","dm","mi","in","ni"} | {"ip","ph","ho","on","ne"} | 1 | 11 | 0,09 |
| 4 | ipad | ipad | {"ip","pa","ad"} | {"ip","pa","ad"} | 3 | 3 | 1.0 |
| 5 | ipad | macbookpro | {"ip","pa","ad"} | {"ma","ac","cb","bo","oo","ok","kp","pr","ro"} | 0 | 12 | 0,0 |
| 6 | ipad | iphone | {"ip","pa","ad"} | {"ip","ph","ho","on","ne"} | 1 | 7 | 0,14 |
| 7 | iwatch | ipad | {"iw","wa","at","tc","ch"} | {"ip","pa","ad"} | 0 | 8 | 0,0 |
| 8 | iwatch | macbookpro | {"iw","wa","at","tc","ch"} | {"ma","ac","cb","bo","oo","ok","kp","pr","ro"} | 0 | 14 | 0,0 |
| 9 | iwatch | iphone | {"iw","wa","at","tc","ch"} | {"ip","ph","ho","on","ne"} | 0 | 10 | 0,0 |
| 10 | iphone | ipad | {"ip","ph","ho","on","ne"} | {"ip","pa","ad"} | 1 | 7 | 0,14 |
| 11 | iphone | macbookpro | {"ip","ph","ho","on","ne"} | {"ma","ac","cb","bo","oo","ok","kp","pr","ro"} | 0 | 14 | 0,0 |
| 12 | iphone | iphone | {"ip","ph","ho","on","ne"} | {"ip","ph","ho","on","ne"} | 5 | 5 | 1.0 |
Filtrage des résultats selon le seuil de similarité de parcours similarity-threshold-filter
Enfin, filtrez les résultats selon un seuil prédéfini afin de sélectionner uniquement les paires répondant aux critères de similarité. L’instruction SQL ci-dessous filtre les produits avec un coefficient de similarité Jaccard d’au moins 0,4. Cela réduit les résultats en paires présentant un degré substantiel de similarité.
SELECT
SetA_ProductNames,
SetB_ProductNames
FROM
(SELECT
SetA_ProductNames,
SetB_ProductNames,
SetA_tokens1,
SetB_tokens2,
size(array_intersect(SetA_tokens1, SetB_tokens2)) AS token_intersect_count,
size(array_union(SetA_tokens1, SetB_tokens2)) AS token_union_count,
ROUND(
CAST(size(array_intersect(SetA_tokens1, SetB_tokens2)) AS DOUBLE) / size(array_union(SetA_tokens1, SetB_tokens2)),
2
) AS jaccard_similarity
FROM
(SELECT
A.featurevector1_distinct AS SetA_ProductNames,
B.featurevector2_distinct AS SetB_ProductNames,
A.tokens AS SetA_tokens1,
B.tokens AS SetB_tokens2
FROM
featurevector1tokenized A
CROSS JOIN
featurevector2tokenized B
)
)
WHERE jaccard_similarity>=0.4
Les résultats de cette requête donnent les colonnes pour la jointure par analogie, comme illustré ci-dessous :
| table 0-row-3 1-row-3 2-row-3 3-row-3 layout-auto | ||
|---|---|---|
| SetA_ProductNames | SetA_ProductNames | |
| 1 | ipadmini | ipad |
| 2 | ipad | ipad |
| 3 | iphone | iphone |
| accordion |
|---|
| : |
Étapes suivantes next-stepsEn lisant ce document, vous pouvez désormais utiliser cette logique pour mettre en évidence des relations ou des chevauchements significatifs entre des jeux de données disparates. La possibilité d’identifier des produits provenant de différents jeux de données présentant une similarité significative de leurs caractéristiques ou attributs comporte de nombreuses applications réelles. Cette logique peut être utilisée pour des scénarios tels que :
Si vous ne l’avez pas déjà fait, nous vous recommandons de lire la présentation du pipeline de fonctionnalités AI/ML. Utilisez cet aperçu pour découvrir comment Data Distiller et votre apprentissage automatique préféré peuvent créer des modèles de données personnalisés qui prennent en charge vos cas d’utilisation marketing avec des données Experience Platform. |