Sdílet prostřednictvím


pairwise_dist_fl()

Výpočet párových vzdáleností mezi entitami na základě více nominálních a číselných proměnných

Funkce pairwise_dist_fl() je UDF (uživatelem definovaná funkce), která vypočítává vícerozměrnou vzdálenost mezi datovými body, které patří do stejného oddílu, s přihlédnutím k nominálním a číselným proměnným.

  • Všechna řetězcová pole jsou kromě názvů entit a oddílů považována za nominální proměnné. Vzdálenost se rovná 1, pokud se hodnoty liší, a 0, pokud jsou stejné.
  • Všechna číselná pole jsou považována za číselné proměnné. Normalizují se transformací na skóre z a vzdálenost se vypočítá jako absolutní hodnota rozdílu. Celková vícerozměrná vzdálenost mezi datovými body se vypočítá jako průměr vzdáleností mezi proměnnými.

Vzdálenost blížící se nule znamená, že entity jsou podobné a vzdálenost nad 1 znamená, že se liší. Podobně entita s průměrnou vzdáleností blízko nebo nad ní značí, že se liší od mnoha jiných entit v oddílu, což označuje potenciální odlehlé hodnoty.

Výstupem funkce jsou dvojice vzdáleností mezi entitami ve stejném oddílu. Dá se použít tak, jak je, k vyhledání podobných nebo různých dvojic. například entity s minimální vzdáleností sdílejí mnoho společných funkcí. Dá se také snadno transformovat na matici vzdálenosti (viz příklad použití) nebo použít jako vstup pro algoritmy clusteringu nebo odlehlé detekce.

Syntax

pairwise_dist_fl(entita, oddíl)

Přečtěte si další informace o konvencích syntaxe.

Parametry

Název Typ Vyžadováno Popis
Entity string ✔️ Název sloupce vstupní tabulky obsahující názvy nebo ID entit, pro které budou vypočítány vzdálenosti.
Oddíl string ✔️ Název sloupce vstupní tabulky obsahujícího oddíl nebo obor tak, aby byly vypočítány vzdálenosti pro všechny páry entit ve stejném oddílu.

Definice funkce

Funkci můžete definovat tak, že buď vložíte její kód jako funkci definovanou dotazem, nebo ji vytvoříte jako uloženou funkci v databázi, a to následujícím způsobem:

Definujte funkci pomocí následujícího příkazu let. Nejsou vyžadována žádná oprávnění.

Důležité

Příkaz let nemůže běžet samostatně. Za ním musí následovat příkaz tabulkového výrazu. Pokud chcete spustit funkční příklad , pairwise_dist_fl()podívejte se na příklad.

let pairwise_dist_fl = (tbl:(*), id_col:string, partition_col:string)
{
    let generic_dist = (value1:dynamic, value2:dynamic) 
    {
        // Calculates the distance between two values; treats all strings as nominal values and numbers as numerical,
        // can be extended to other data types or tweaked by adding weights or changing formulas.
            iff(gettype(value1[0]) == "string", todouble(tostring(value1[0]) != tostring(value2[0])), abs(todouble(value1[0]) - todouble(value2[0])))
    };
    let T = (tbl | extend _entity = column_ifexists(id_col, ''), _partition = column_ifexists(partition_col, '') | project-reorder _entity, _partition);
    let sum_data = (
        // Calculates summary statistics to be used for normalization.
        T
        | project-reorder _entity
        | project _partition, p = pack_array(*)
        | mv-expand with_itemindex=idx p
        | summarize count(), avg(todouble(p)), stdev(todouble(p)) by _partition, idx
        | sort by _partition, idx asc
        | summarize make_list(avg_p), make_list(stdev_p) by _partition
    );
    let normalized_data = (
        // Performs normalization on numerical variables by substrcting mean and scaling by standard deviation. Other normalization techniques can be used
        // by adding metrics to previous function and using here.
        T
        | project _partition, p = pack_array(*)
        | join kind = leftouter (sum_data) on _partition
        | mv-apply p, list_avg_p, list_stdev_p on (
            extend normalized = iff((not(isnan(todouble(list_avg_p))) and (list_stdev_p > 0)), pack_array((todouble(p) - todouble(list_avg_p))/todouble(list_stdev_p)), p)
            | summarize a = make_list(normalized) by _partition
        )
        | project _partition, a
    );
    let dist_data = (
        // Calculates distances of included variables and sums them up to get a multivariate distance between all entities under the same partition.
        normalized_data
        | join kind = inner (normalized_data) on _partition
        | project entity = tostring(a[0]), entity1 = tostring(a1[0]), a = array_slice(a, 1, -1), a1 = array_slice(a1, 1, -1), _partition
        | mv-apply a, a1 on 
        (
            project d = generic_dist(pack_array(a), pack_array(a1))
            | summarize d = make_list(d)
        )
        | extend dist = bin((1.0*array_sum(d)-1.0)/array_length(d), 0.0001) // -1 cancels the artifact distance calculated between entity names appearing in the bag and normalizes by number of features        
        | project-away d
        | where entity != entity1
        | sort by _partition asc, entity asc, dist asc
    );
    dist_data
};
// Write your query to use the function here.

Příklad

Následující příklad používá operátor invoke ke spuštění funkce.

Pokud chcete použít funkci definovanou dotazem, vyvoláte ji po definici vložené funkce.

let pairwise_dist_fl = (tbl:(*), id_col:string, partition_col:string)
{
    let generic_dist = (value1:dynamic, value2:dynamic) 
    {
        // Calculates the distance between two values; treats all strings as nominal values and numbers as numerical,
        // can be extended to other data types or tweaked by adding weights or changing formulas.
            iff(gettype(value1[0]) == "string", todouble(tostring(value1[0]) != tostring(value2[0])), abs(todouble(value1[0]) - todouble(value2[0])))
    };
    let T = (tbl | extend _entity = column_ifexists(id_col, ''), _partition = column_ifexists(partition_col, '') | project-reorder _entity, _partition);
    let sum_data = (
        // Calculates summary statistics to be used for normalization.
        T
        | project-reorder _entity
        | project _partition, p = pack_array(*)
        | mv-expand with_itemindex=idx p
        | summarize count(), avg(todouble(p)), stdev(todouble(p)) by _partition, idx
        | sort by _partition, idx asc
        | summarize make_list(avg_p), make_list(stdev_p) by _partition
    );
    let normalized_data = (
        // Performs normalization on numerical variables by substrcting mean and scaling by standard deviation. Other normalization techniques can be used
        // by adding metrics to previous function and using here.
        T
        | project _partition, p = pack_array(*)
        | join kind = leftouter (sum_data) on _partition
        | mv-apply p, list_avg_p, list_stdev_p on (
            extend normalized = iff((not(isnan(todouble(list_avg_p))) and (list_stdev_p > 0)), pack_array((todouble(p) - todouble(list_avg_p))/todouble(list_stdev_p)), p)
            | summarize a = make_list(normalized) by _partition
        )
        | project _partition, a
    );
    let dist_data = (
        // Calculates distances of included variables and sums them up to get a multivariate distance between all entities under the same partition.
        normalized_data
        | join kind = inner (normalized_data) on _partition
        | project entity = tostring(a[0]), entity1 = tostring(a1[0]), a = array_slice(a, 1, -1), a1 = array_slice(a1, 1, -1), _partition
        | mv-apply a, a1 on 
        (
            project d = generic_dist(pack_array(a), pack_array(a1))
            | summarize d = make_list(d)
        )
        | extend dist = bin((1.0*array_sum(d)-1.0)/array_length(d), 0.0001) // -1 cancels the artifact distance calculated between entity names appearing in the bag and normalizes by number of features        
        | project-away d
        | where entity != entity1
        | sort by _partition asc, entity asc, dist asc
    );
    dist_data
};
//
let raw_data = datatable(name:string, gender: string, height:int, weight:int, limbs:int, accessory:string, type:string)[
    'Andy',     'M',    160,    80,     4,  'Hat',      'Person',
    'Betsy',    'F',    170,    70,     4,  'Bag',      'Person',
    'Cindy',    'F',    130,    30,     4,  'Hat',      'Person',
    'Dan',      'M',    190,    105,    4,  'Hat',      'Person',
    'Elmie',    'M',    110,    30,     4,  'Toy',      'Person',
    'Franny',   'F',    170,    65,     4,  'Bag',      'Person',
    'Godzilla', '?',    260,    210,    5,  'Tail',     'Person',
    'Hannie',   'F',    112,    28,     4,  'Toy',      'Person',
    'Ivie',     'F',    105,    20,     4,  'Toy',      'Person',
    'Johnnie',  'M',    107,    21,     4,  'Toy',      'Person',
    'Kyle',     'M',    175,    76,     4,  'Hat',      'Person',
    'Laura',    'F',    180,    70,     4,  'Bag',      'Person',
    'Mary',     'F',    160,    60,     4,  'Bag',      'Person',
    'Noah',     'M',    178,    90,     4,  'Hat',      'Person',
    'Odelia',   'F',    186,    76,     4,  'Bag',      'Person',
    'Paul',     'M',    158,    69,     4,  'Bag',      'Person',
    'Qui',      'F',    168,    62,     4,  'Bag',      'Person',
    'Ronnie',   'M',    108,    26,     4,  'Toy',      'Person',
    'Sonic',    'F',    52,     20,     6,  'Tail',     'Pet',
    'Tweety',   'F',    52,     20,     6,  'Tail',     'Pet' ,
    'Ulfie',    'M',    39,     29,     4,  'Wings',    'Pet',
    'Vinnie',   'F',    53,     22,     1,  'Tail',     'Pet',
    'Waldo',    'F',    51,     21,     4,  'Tail',     'Pet',
    'Xander',   'M',    50,     24,     4,  'Tail',     'Pet'
];
raw_data
| invoke pairwise_dist_fl('name', 'type')
| where _partition == 'Person' | sort by entity asc, entity1 asc
| evaluate pivot (entity, max(dist), entity1) | sort by entity1 asc

Výstup

entita1 Andy Betsy Cindy Dan Elmie Franny Godzilla Hana ...
Andy 0.354 0.4125 0.1887 0.4843 0.3702 1.2087 0.6265 ...
Betsy 0.354 0.416 0.4708 0.6307 0.0161 1.2051 0.4872 ...
Cindy 0.4125 0.416 0.6012 0.3575 0.3998 1.4783 0.214 ...
Dan 0.1887 0.4708 0.6012 0.673 0.487 1.0199 0.8152 ...
Elmie 0.4843 0.6307 0.3575 0.673 0.6145 1.5502 0.1565 ...
Franny 0.3702 0.0161 0.3998 0.487 0.6145 1.2213 0.471 ...
Godzilla 1.2087 1.2051 1.4783 1.0199 1.5502 1.2213 1.5495 ...
Hana 0.6265 0.4872 0.214 0.8152 0.1565 0.471 1.5495 ...
... ... ... ... ... ... ... ... ... ...

Při pohledu na entity dvou různých typů bychom chtěli vypočítat vzdálenost mezi entitami patřícími do stejného typu s ohledem na nominální proměnné (jako je pohlaví nebo upřednostňované příslušenství) a číselné proměnné (například počet končetin, výška a váha). Číselné proměnné jsou v různých škálách a musí být centralizované a škálované, což se provádí automaticky. Výstupem jsou dvojice entit ve stejném oddílu s vypočtenou vícerozměrnou vzdáleností. Lze ji analyzovat přímo, vizualizovat jako matici vzdálenosti nebo bodový graf nebo použít jako vstupní data pro algoritmus detekce odlehlých hodnot výpočtem střední vzdálenosti na entitu s entitami s vysokými hodnotami, které označují globální odlehlé hodnoty. Když například přidáte volitelnou vizualizaci pomocí matice vzdálenosti, získáte tabulku, jak je znázorněno v ukázce. Z ukázky vidíte, že:

  • Některé dvojice entit (Betsy a Franny) mají nízkou hodnotu vzdálenosti (blížící se 0), což znamená, že jsou podobné.
  • Některé dvojice entit (Godzilla a Elmie) mají vysokou hodnotu vzdálenosti (1 nebo vyšší), což znamená, že se liší.

Výstup lze dále použít k výpočtu průměrné vzdálenosti pro každou entitu. Vysoká průměrná vzdálenost může znamenat globální odlehlé hodnoty. Vidíme například, že Godzilla má v průměru velkou vzdálenost od ostatních, což značí, že se jedná o pravděpodobnou globální odlehlou hodnotu.