接下来直接上代码:
public class Model
{
public List<Point> CenterPoints { get; set; }
public Dictionary<int, List<Point>> Result { get; set; }
}
public class Program
{
static void Main(string[] args)
{
var pList = new List<Point>();
pList.Add(new Point() { X = 3, Y = 10 });
pList.Add(new Point() { X = 2, Y = 2 });
pList.Add(new Point() { X = 3, Y = 8 });
pList.Add(new Point() { X = 7, Y = 9 });
pList.Add(new Point() { X = 10, Y = 2 });
pList.Add(new Point() { X = 7, Y = 3 });
pList.Add(new Point() { X = 4, Y = 4 });
pList.Add(new Point() { X = 1, Y = 10 });
pList.Add(new Point() { X = 2, Y = 7 });
pList.Add(new Point() { X = 5, Y = 5 });
pList.Add(new Point() { X = 5, Y = 7 });
pList.Add(new Point() { X = 9, Y = 3 });
pList.Add(new Point() { X = 8, Y = 5 });
var result = KMeans(pList, 4);
for (int i = 0; i < result.CenterPoints.Count; i++)
{
Console.WriteLine($"中心点 ({result.CenterPoints[i].X},{result.CenterPoints[i].Y}) :");
result.Result[i].ForEach(p => Console.Write($"{p.X},{p.Y} "));
Console.WriteLine();
}
Console.ReadLine();
}
static Model KMeans(List<Point> pList, int NumberOfCenter)
{
if (pList.Count <= NumberOfCenter) throw new Exception("点的超过数据量");
var pCenters = pList.Take(NumberOfCenter).ToList(); // 随机选择K个数据点 作为中心点
while (true)
{
var model = CalcAndGetNewCenters(pList, pCenters);
if (ComparisonPoints(model.CenterPoints, pCenters)) return model;
pCenters = model.CenterPoints;
}
}
static bool ComparisonPoints(List<Point> p1, List<Point> p2)
{
var temp1 = p1.Select(x => $"{x.X},{x.Y}");
var temp2 = p2.Select(x => $"{x.X},{x.Y}");
return temp1.All(temp2.Contains) && temp1.Count() == temp2.Count();
}
static Model CalcAndGetNewCenters(List<Point> pList, List<Point> pCenters)
{
var NumberOfCenter = pCenters.Count;
// 数据归类
var result = new Dictionary<int, List<Point>>();
for (int i = 0; i < pList.Count; i++)
{
var distences = new List<double>();
// 计算数据点 到 每个中心点的距离
for (int j = 0; j < NumberOfCenter; j++)
{
distences.Add(CalcDistence(pCenters[j], pList[i]));
}
// 将数据点 归入 最近的中心点下
var minIndex = distences.IndexOf(distences.Min());
if (!result.ContainsKey(minIndex))
result[minIndex] = new List<Point>();
result[minIndex].Add(pList[i]);
}
// 计算新的中心点
var newPCenters = new List<Point>();
foreach (var tempList in result)
{
if (tempList.Value == null || tempList.Value.Count <= 0) continue;
newPCenters.Add(new Point(
tempList.Value.Sum(x => x.X) / tempList.Value.Count,
tempList.Value.Sum(x => x.Y) / tempList.Value.Count));
}
return new Model { CenterPoints = newPCenters, Result = result };
}
static double CalcDistence(Point p1, Point p2)
{
return Math.Sqrt((p1.X - p2.X) * (p1.X - p2.X) + (p1.Y - p2.Y) * (p1.Y - p2.Y));
}
}
完美,收工
不懂的留言。