Estoy haciendo un trabajo de agrupación en clústeres con la biblioteca Accord.net. En última instancia, estoy tratando de encontrar la cantidad óptima de clústeres para usar con el método del codo que requiere algunos cálculos relativamente simples. Sin embargo, estoy teniendo dificultades para obtener los valores que necesito para determinar el mejor número de K para usar en mi modelado KMeans.

Tengo algunos datos / código de ejemplo:

open Accord
open Accord.Math
open Accord.MachineLearning
open Accord.Statistics
open Accord.Statistics.Analysis

let x = [|
    [|4.0; 1.0; 1.0; 2.0|]; 
    [|2.0; 4.0; 1.0; 2.0|]; 
    [|2.0; 3.0; 1.0; 1.0|]; 
    [|3.0; 6.0; 2.0; 1.0|]; 
    [|4.0; 4.0; 1.0; 1.0|]; 
    [|5.0; 10.0; 1.0; 2.0|]; 
    [|7.0; 8.0; 1.0; 2.0|]; 
    [|6.0; 5.0; 1.0; 1.0|]; 
    [|7.0; 7.0; 2.0; 1.0|]; 
    [|5.0; 8.0; 1.0; 1.0|]; 
    [|4.0; 1.0; 1.0; 2.0|]; 
    [|3.0; 5.0; 0.0; 3.0|]; 
    [|1.0; 2.0; 0.0; 0.0|]; 
    [|4.0; 7.0; 1.0; 2.0|]; 
    [|5.0; 3.0; 2.0; 0.0|]; 
    [|4.0; 11.0; 0.0; 3.0|]; 
    [|8.0; 7.0; 2.0; 1.0|]; 
    [|5.0; 6.0; 0.0; 2.0|]; 
    [|8.0; 6.0; 3.0; 0.0|]; 
    [|4.0; 9.0; 0.0; 2.0|] 
    |]

Y puedo generar los clústeres con bastante facilidad con

let kmeans = new KMeans 5

let kmeansMod = kmeans.Learn x
let clusters = kmeansMod.Decide x

Pero ¿cómo puedo calcular la distancia desde cualquier punto de datos dado x a su grupo asignado? No veo nada en la KMeans documentación de la clase Cluster Collection que sugiere que ya existe un método implementado para este problema.

Parece que debería ser relativamente sencillo calcular esta distancia, pero estoy perdido. ¿Sería tan fácil como hacer algo como

let dataAndClusters = Array.zip clusters x

let getCentroid (m: KMeansClusterCollection) (i: int) = 
    m.Centroids.[i]

dataAndClusters
|> Array.map (fun (c, d) -> (c, (getCentroid kmeansMod c) 
                                |> Array.map2 (-) d
                                |> Array.sum))

Que regresa

val it : (int * float) [] =
  [|(1, 0.8); (0, -1.5); (1, -0.2); (0, 1.5); (0, -0.5); (4, 0.0); (2, 1.4);
    (2, -3.6); (2, 0.4); (3, 0.75); (1, 0.8); (0, 0.5); (1, -4.2); (3, -0.25);
    (1, 2.8); (4, 0.0); (2, 1.4); (3, -1.25); (2, 0.4); (3, 0.75)|]

¿Estoy calculando esta distancia correctamente? Sospecho que no.

Como mencioné, estoy buscando determinar el número correcto de K para usar en la agrupación KMeans. Pensé que usaría el algoritmo simple presentado en el segundo párrafo de esta respuesta de Stats.StackExchange.com. Tenga en cuenta que no me opongo a utilizar la "Estadística de brechas" vinculada al final de la respuesta superior.

4
Steven 13 dic. 2016 a las 17:40
Debería poder calcular la distancia al clúster más cercano utilizando el método Scores () en lugar de Decide ().
 – 
Cesar
8 jul. 2017 a las 19:48

1 respuesta

La mejor respuesta

Resulta que no calculaba las distancias correctamente, pero estaba cerca.

Investigando un poco más, vi esta pregunta similar, pero para el R idioma y desglosé el proceso descrito en esa respuesta aceptada en mi propia sesión de R.

Los pasos parecen ser bastante sencillos:

1. From each data value, subtract the centroid values
2. Sum the differences for a given data/centroid pair
3. Square the differences
4. Find the square root of the differences.

Para mis datos de ejemplo anteriores, se desglosaría en esto:

let distances = 
    dataAndClusters
    |> Array.map (fun (c, d) -> (c, ((getCentroid kmeansMod c) 
                                    |> Array.map2 (-) d
                                    |> Array.sum
                                    |> float) ** 2.0
                                    |> sqrt))

Tenga en cuenta la adición de dos líneas,

|> float) ** 2.0 convierte el valor en un flotante para que pueda cuadrarse (es decir, x**y)

Y

|> sqrt) que encuentra la raíz cuadrada del valor.

Puede haber un método incorporado para hacer esto, pero aún no lo he encontrado. Por ahora, esto funciona para mí.

1
Community 23 may. 2017 a las 13:30