2015-10-29 2 views
2

J'ai une grille carrée (200 x 200). Je voudrais que les utilisateurs puissent voter sur leur prochaine position désirée d'un objet dans cet espace. Lorsqu'un utilisateur vote, j'ajoute la position XY à un tableau.Calculer le point central de la plus haute densité de points xy

Actuellement, pour trouver la position «gagnante», je prends juste une moyenne de X et une moyenne de Y, mais ce que j'ai trouvé, c'est que la position gagnante a tendance à graviter autour du milieu. !).

Average

Blanc = votes, jaune = "gagner" le point XY

Ce que je préfère est si elle trouve la zone des voix les plus denses, et a choisi un point au milieu de cette . Les votes dispersés uniques ne tirent pas la position gagnante trop loin de la zone dense comme le fait la moyenne.

Est-ce possible?

tableau Exemple

[ { x: 39, y: 28 }, 
    { x: 69, y: 33 }, 
    { x: 51, y: 51 }, 
    { x: 14, y: 63 }, 
    { x: 75, y: 140 }, 
    { x: 171, y: 68 }, 
    { x: 140, y: 53 }, 
    { x: 173, y: 150 }, 
    { x: 123, y: 179 }, 
    { x: 103, y: 150 }, 
    { x: 145, y: 119 }, 
    { x: 92, y: 85 }, 
    { x: 58, y: 49 }, 
    { x: 28, y: 65 }, 
    { x: 41, y: 39 }, 
    { x: 46, y: 41 }, 
    { x: 49, y: 51 }, 
    { x: 43, y: 55 }, 
    { x: 35, y: 48 }, 
    { x: 29, y: 31 }, 
    { x: 68, y: 22 }, 
    { x: 58, y: 39 } ] 
+0

@Igor ne traine pas seulement le gars si vous n'avez pas la question ... pour le reste d'entre nous est assez clair que il veut ... de la malédiction j'ai voté cette question. –

Répondre

1

Eh bien, je ne poste pas seulement une idée mais je publie du code réel. J'espère que vous pouvez voir si cela fonctionne pour vous. Votre problème tombe essentiellement dans le domaine de l'analyse de cluster.

Vous souhaitez identifier les différents groupes de données présents dans votre ensemble de données et qui forment un cluster. Heureusement pour vous, ce problème a déjà quelques méthodes à résoudre, et il y a même un paquetage NPM qui vous permet d'exécuter certains des outils d'analyse de cluster bien connus.J'ai choisi DBSCAN pour résoudre votre ensemble de points, n'hésitez pas à essayer un autre algorithme si vous pensez avoir besoin d'autre chose. https://en.wikipedia.org/wiki/DBSCAN

J'ai utilisé la bibliothèque de clustering de densité de NPM. https://github.com/LukaszKrawczyk/density-clustering

Les paramètres arbitraires donnés à dbscan étaient pour le rayon de voisinage et pour le nombre minimum de points à être considéré comme un « cluster »

Et le code est une version modifiée de l'exemple donné dans la page github du paquetage NPM.

var sample = [ { x: 39, y: 28 }, 
    { x: 69, y: 33 }, 
    { x: 51, y: 51 }, 
    { x: 14, y: 63 }, 
    { x: 75, y: 140 }, 
    { x: 171, y: 68 }, 
    { x: 140, y: 53 }, 
    { x: 173, y: 150 }, 
    { x: 123, y: 179 }, 
    { x: 103, y: 150 }, 
    { x: 145, y: 119 }, 
    { x: 92, y: 85 }, 
    { x: 58, y: 49 }, 
    { x: 28, y: 65 }, 
    { x: 41, y: 39 }, 
    { x: 46, y: 41 }, 
    { x: 49, y: 51 }, 
    { x: 43, y: 55 }, 
    { x: 35, y: 48 }, 
    { x: 29, y: 31 }, 
    { x: 68, y: 22 }, 
    { x: 58, y: 39 } ]; 


/* Transform your dataset to the format expected by the library */ 
var dataset = []; 

for(var i=0; i<sample.length; i++){ 
    dataset.push([sample[i].x, sample[i].y]); 
} 

var clustering = require('density-clustering'); 
var dbscan = new clustering.DBSCAN(); 
/* parameters: 
    20 - neighborhood radius 
    5 - number of points in neighborhood to form a cluster 
*/ 
var clusters = dbscan.run(dataset, 20, 5); 

if(clusters.length > 0){ 

    /* Find the biggest cluster */ 
    var biggestCluster = clusters[0]; 

    for(i=1;i<clusters.length;i++){ 

     if(cluster[i].length > biggestCluster.length){ 
      biggestCluster = cluster[i];  
     } 
    } 

    /* The output of the library contains the indexes of the points in the cluster, not the coordinates, so we need to get the point from the dataset */ 
    var clusterPoints = []; 
    var sumx = 0; 
    var sumy = 0; 

    for(i=0;i<biggestCluster.length;i++){ 
     var point = dataset[biggestCluster[i]]; 
     clusterPoints.push(point); 

     /* It's also a good opportunity to cumulate x and y so we can get the average */ 
     sumx+=point[0]; 
     sumy+=point[1]; 
    } 

    console.log('Cluster:', clusterPoints);  
    console.log('Center:', sumx/clusterPoints.length, sumy/clusterPoints.length); 
} 
else{ 
    console.log('No clusters'); 
} 

La sortie de ce programme sera:

Cluster: [ [ 51, 51 ], [ 58, 49 ], [ 41, 39 ], [ 46, 41 ], [ 49, 51 ], [ 43, 55 ], [ 35, 48 ], [ 58, 39 ], [ 69, 33 ], [ 39, 28 ], [ 29, 31 ], [ 28, 65 ], [ 68, 22 ] ] 

Center: 47.23076923076923 42.46153846153846 
+0

Très gentil merci, recommanderiez-vous que je retombe à l'aide d'une moyenne comme dans mon exemple original si aucun cluster ne peut être trouvé? – Titan

+0

@ GreenGiant ouais je suppose que ... je veux dire, tu dois faire ce qui correspond à ta situation. Que ferait un humain, si dans un groupe personne ne semble trouver un consensus sur une décision (démocratique), comme dans votre exemple? –

+0

Cela fonctionne parfaitement merci! http://f.cl.ly/items/090q1I1g460m1e2V3y2G/Screen%20Shot%202015-10-29%20at%2015.40.30.png – Titan

2

qui est en fait vraiment facile - Combine tous les X en 1 variable et Devide par le nombre de X. Même chose pour y:

var totalX = 0, totalY = 0, avgX, avgY; 

var coords = [ { x: 39, y: 28 }, 
    { x: 69, y: 33 }, 
    { x: 51, y: 51 }, 
    { x: 14, y: 63 }, 
    { x: 75, y: 140 }, 
    { x: 171, y: 68 }, 
    { x: 140, y: 53 }, 
    { x: 173, y: 150 }, 
    { x: 123, y: 179 }, 
    { x: 103, y: 150 }, 
    { x: 145, y: 119 }, 
    { x: 92, y: 85 }, 
    { x: 58, y: 49 }, 
    { x: 28, y: 65 }, 
    { x: 41, y: 39 }, 
    { x: 46, y: 41 }, 
    { x: 49, y: 51 }, 
    { x: 43, y: 55 }, 
    { x: 35, y: 48 }, 
    { x: 29, y: 31 }, 
    { x: 68, y: 22 }, 
    { x: 58, y: 39 } ] 

for (var i = 0; i <= coords.length; i++) { 
    totalX += coords[i].x; 
    totalY += coords[i].y; 
} 

avgX = totalX/coords.length; 
avgY = totalY/coords.length; 

Voir en action harrr (lol à ID): https://jsfiddle.net/harr55d2/

EDIT: Ce n'est pas la bonne réponse, désolé, a mal interprété votre question. Ce que vous pourriez faire cependant, c'est prendre cet endroit avarage et à partir de là, calculer les distances à tous les points à partir de là. Vous obtiendrez quelques chiffres de cela. Si vous calculez ensuite une avarage sur la distance, je pense que vous vous rapprocherez du point que vous voulez être.

Une autre méthode consiste à balayer la zone 200x200 dans des blocs de 20x20 (ou quelque chose, peut-être les cercles fonctionne mieux) et de compter tous les votes là-bas. Celui qui a le plus de votes gagne.

EDIT: Une autre méthode; Prenez la distance pour chaque vote du point d'avarage. Alors c'est le «score» ou le «poids» pour un certain vote. Vous pouvez alors voir que les votes les plus proches de l'avarage sont pondérés les «meilleurs». Si vous attrapez ma dérive.

+0

Vous calculez réellement le point moyen de la zone entière. Qu'est-ce que GreenGIant veut, c'est d'abord obtenir la zone la plus dense et obtenir le centre de cette zone –

+0

Oooh merde, lisez-le trop vite. Tu as raison. C'est une question complètement différente ... Un dur .. Laissez-moi penser à cela .. –

+0

Édité ma réponse avec une autre méthode :) –

3

Une solution peut être de calculer pour chaque point la somme des distances entre elle et tous les autres points. Le point avec la plus petite somme devrait être le centre de la zone avec la densité la plus élevée.

+1

C'est en fait une très bonne version - je doute que ce soit rapide mais cela fait le travail correctement, et vous n'aurez probablement qu'à le lancer une fois. Avoir mon upvote! –

+0

Une idée intéressante, je ne suis pas trop préoccupé par la vitesse, je n'aurais que 700 entrées au maximum absolu, j'imagine en moyenne 100. Calculeriez-vous le X de tous les X, puis Y de tous les autres Y et ajoutez X + Y pour chaque point pour obtenir sa "somme de distances"? – Titan

+1

La distance entre deux points peut être calculée en utilisant cette formule: d (A (x1, y1), B (x2, y2)) = sqrt ((x2 - x1)^2 + (y2 - y1)^2). Vous devez appliquer ce formulla pour chaque point individuellement, ce qui signifie que vous ne pouvez pas ajouter toutes les valeurs X et toutes les valeurs Y et calculer la distance en les utilisant. –