以下参考 クラスタリングが行われているクラスのコードを貼ります internal class Meta { private readonly int k; private readonly int maxIterations; private readonly Random random; public Meta(int k, int maxIterations = 100, int? seed = null) { this.k = k; this.maxIterations = maxIterations; this.random = seed.HasValue ? new Random(seed.Value) : new Random(); } // クラスターの平均を計算 private double[][] CalculateMeans(List> clusters) { return clusters.Select(cluster => cluster.Aggregate(new double[cluster[0].Length], (acc, point) => { for (int i = 0; i < point.Length; i++) { acc[i] += point[i]; } return acc; }) .Select(sum => sum / cluster.Count).ToArray() ).ToArray(); } // 距離を計算 private double Distance(double[] point1, double[] point2) { return Math.Sqrt(point1.Zip(point2, (x1, x2) => (x1 - x2) * (x1 - x2)).Sum()); } // クラスタリングを実行 public Dictionary> Fit(Dictionary Rdata) { // データを抽出して二次元配列に変換 var data = Rdata.Values.SelectMany(d => d).ToArray(); int n = data.Length; //個数 //int d = data[0].Length; // 初期化: k-means++ を使って初期中心を決定 double[][] means = InitializeMeans(data); // 初期メタデータをセットアップ var metas = InitializeMeta(data, means); // 初期割り当てを実行 var clusters = new List>(); for (int i = 0; i < k; i++) { clusters.Add(new List()); } var tids = InitialAssignment(clusters, metas, data); // 中心を再計算 means = CalculateMeans(clusters); // クラスタリングの改良を実行 means = RefineResult(data, means, clusters, metas, tids); // クラスタごとの要支援者を構成する辞書を作成 var result = new Dictionary>(); for (int i = 0; i < k; i++) { result[i] = new Dictionary(); } for (int i = 0; i < k; i++) { foreach (var point in clusters[i]) { int rid = Rdata.First(pair => pair.Value.Any(p => p.SequenceEqual(point))).Key; result[i][rid] = Rdata[rid]; } } return result; } // k-means++ による初期中心を決定 private double[][] InitializeMeans(double[][] data) { var means = new List //クラスタ中心の座標を格納 { data[random.Next(data.Length)] }; while (means.Count < k) { var dists = data.Select(point => means.Min(mean => Distance(point, mean))).ToArray(); var cumulativeDists = dists .Select((dist, index) => dists.Take(index + 1).Sum()) .ToArray(); double target = random.NextDouble() * cumulativeDists.Last(); means.Add(data[Array.FindIndex(cumulativeDists, dist => dist >= target)]); } return means.ToArray(); } // 初期メタデータをセットアップ private Metadata[] InitializeMeta(double[][] data, double[][] means) { var metas = new Metadata[data.Length]; for (int i = 0; i < data.Length; i++) { metas[i] = new Metadata(k); metas[i].data = data[i]; // ここで data フィールドを設定 for (int j = 0; j < k; j++) { metas[i].dists[j] = Distance(data[i], means[j]); //各要支援者からグループ中心までの距離 } metas[i].primary = Array.IndexOf(metas[i].dists, metas[i].dists.Min()); metas[i].secondary = Array.IndexOf(metas[i].dists, metas[i].dists.Max()); } return metas; } // 初期割り当てを実行 private List InitialAssignment(List> clusters, Metadata[] metas, double[][] data) { var tids = Enumerable.Range(0, data.Length).ToList(); int maxsize = (data.Length + k - 1) / k; // メタデータに基づいてソート tids.Sort((a, b) => metas[b].Priority().CompareTo(metas[a].Priority())); // 割り当てを行う foreach (var tid in tids) { Metadata meta = metas[tid]; clusters[meta.primary].Add(data[tid]); if (clusters[meta.primary].Count == maxsize) { meta.primary = -1; for (int i = 0; i < k; i++) { if (clusters[i].Count < maxsize && (meta.primary == -1 || meta.dists[i] < meta.dists[meta.primary])) { meta.primary = i; } } } } return tids; } // 距離を更新 private void UpdateDistances(double[][] data, double[][] means, Metadata[] metas) { for (int i = 0; i < data.Length; i++) { var meta = metas[i]; for (int j = 0; j < k; j++) { meta.dists[j] = Distance(data[i], means[j]); } meta.secondary = Array.IndexOf(meta.dists, meta.dists.Where((_, idx) => idx != meta.primary).Min()); } } // 結果の改良を実行 private double[][] RefineResult(double[][] data, double[][] means, List> clusters, Metadata[] metas, List tids) { int minsize = data.Length / k; //クラスタサイズの最小 int maxsize = (data.Length + k - 1) / k; //クラスタサイズの最大 var preferences = Enumerable.Range(0, k).ToArray(); for (int iter = 0; iter < maxIterations; iter++) { // 距離を更新 UpdateDistances(data, means, metas); // データの再割り当てを行う優先順位に並び替える:priorityとは現所属と最も遠いクラスタの重心の距離で大きいほど優先度は高くなる tids.Sort((a, b) => metas[a].Priority().CompareTo(metas[b].Priority())); int active = 0; // データポイントの転送を実行 foreach (var tid in tids) { Metadata meta = metas[tid]; //クラスタ重心が近い順に並び替え Array.Sort(preferences, (a, b) => meta.dists[a].CompareTo(meta.dists[b])); for (int i = 0; i < k; i++) { if (preferences[i] == meta.primary) continue; List source = clusters[meta.primary]; //所属しているクラスタに現在配分されているデータ数 List dest = clusters[preferences[i]]; //最も近いクラスタに入っているデータ数 //移動することでクラスタリングの質が向上し、移動先destのクラスタサイズがまだ最大サイズに達していないか、現状のクラスタが最小サイズ以上のデータを持っているか if (meta.Gain(preferences[i]) > 0 && dest.Count < maxsize && source.Count > minsize) { Console.WriteLine(tid); Transfer(meta, source, dest, tid, preferences[i]); //交換を行う active++; break; } } } //if (active == 0) break; if (active == 0) { // 強制移動処理: すべてのクラスタがmaxsizeを超えないようにする for (int i = 0; i < k; i++) { while (clusters[i].Count > maxsize) { // サイズが最大を超えたクラスタからデータポイントを移動 var meta = metas.First(m => m.primary == i); // 移動先クラスタを選択 (クラスタの質が最も改善されるものを選択) int newCluster = preferences .Where(p => clusters[p].Count < maxsize) .OrderBy(p => meta.dists[p]) .FirstOrDefault(); Transfer(meta, clusters[i], clusters[newCluster], Array.IndexOf(metas, meta), newCluster); active++; } } } // クラスタ中心を再計算 means = CalculateMeans(clusters); // activeが0になった場合でも強制移動があれば続ける if (active == 0 && clusters.All(c => c.Count <= maxsize)) { break; } } return means; } // 転送を実行 private void Transfer(Metadata meta, List source, List dest, int tid, int newCluster)//交換するデータ,現状所属しているクラスタの詳細,移送先のクラスタの詳細 { int index = source.FindIndex(p => p.SequenceEqual(meta.data)); if (index == -1) { throw new InvalidOperationException("Meta data not found in the source cluster."); } source.RemoveAt(index); //データポイントをsourceから削除 //source.RemoveAt(source.FindIndex(p => Array.Equals(p, meta.data))); // データポイントをdestクラスタに追加 dest.Add(meta.data); // メタデータで新しいクラスタを設定 meta.primary = newCluster; } // メタデータクラス private class Metadata { public double[] dists; //各クラスタとの距離 public int primary; //現在所属しているクラスタのIndex public int secondary; //最も遠いクラスタのIndex public double[] data; public Metadata(int k) { dists = new double[k]; primary = 0; secondary = 0; } public double Priority() => dists[secondary] - dists[primary]; public double Gain(int i) => dists[primary] - dists[i]; } } 以下エラー箇所を提示します ★★★metaがsource内にあるはずがないため、indexが-1となり、エラーが起きる private void Transfer(Metadata meta, List source, List dest, int tid, int newCluster)//交換するデータ,現状所属しているクラスタの詳細,移送先のクラスタの詳細 { int index = source.FindIndex(p => p.SequenceEqual(meta.data)); if (index == -1) { throw new InvalidOperationException("Meta data not found in the source cluster."); } source.RemoveAt(index); //データポイントをsourceから削除 //source.RemoveAt(source.FindIndex(p => Array.Equals(p, meta.data))); // データポイントをdestクラスタに追加 dest.Add(meta.data); // メタデータで新しいクラスタを設定 meta.primary = newCluster; }