import java.util.ArrayList; import java.util.List; public class KMeansExample { public static void main(String[] args) { int n = 10; // 随机数的数量 double a = -5, b = 5, c = 10; // [a, b+c] List<Double> data = generateRandomNumbers(n, a, b + c); // 生成随机数 System.out.println("Generated Data:"); for (double num : data) { System.out.print(num + " "); } System.out.println(); kMeansCluster(data); } private static List<Double> generateRandomNumbers(int count, double min, double max) { List<Double> numbers = new ArrayList<>(); for (int i = 0; i < count; i++) { double randomNum = Math.round((min + (max - min) * Math.random()) * 100.0) / 100.0; numbers.add(randomNum); } return numbers; } private static void kMeansCluster(List<Double> data) { if (data.isEmpty()) return; // 初始化两个簇心为第一个和最后一个元素 double centroid1 = data.get(0), centroid2 = data.get(data.size() - 1); boolean centroidsChanged; do { centroidsChanged = false; // 分组 List<Double> cluster1 = new ArrayList<>(); List<Double> cluster2 = new ArrayList<>(); for (Double point : data) { if (Math.abs(point - centroid1) <= Math.abs(point - centroid2)) { cluster1.add(point); } else { cluster2.add(point); } } // 更新簇心 double newCentroid1 = calculateMean(cluster1); double newCentroid2 = calculateMean(cluster2); if (newCentroid1 != centroid1 || newCentroid2 != centroid2) { centroidsChanged = true; centroid1 = newCentroid1; centroid2 = newCentroid2; } } while (centroidsChanged); // 输出分组结果 System.out.printf("Cluster1 Centroid: %.2f -> ", centroid1); for (double d : data.stream().filter(p -> Math.abs(p - centroid1) <= Math.abs(p - centroid2)).toList()) { System.out.printf("%.2f ", d); } System.out.println(); System.out.printf("Cluster2 Centroid: %.2f -> ", centroid2); for (double d : data.stream().filter(p -> Math.abs(p - centroid2) < Math.abs(p - centroid1)).toList()) { System.out.printf("%.2f ", d); } System.out.println(); } private static double calculateMean(List<Double> points) { if (points == null || points.isEmpty()) return Double.NaN; double sum = 0; for (double p : points) sum += p; return su
时间: 2025-03-23 15:08:23 浏览: 46
<<
您提供的代码片段中有一处小错误,在 `calculateMean` 方法的最后一行,返回值应该是计算后的平均值而不是未定义的变量名 `su`。正确的方法体应使用 `sum / points.size()` 来完成均值的计算。
下面是修复之后完整的 Java 实现:
```java
import java.util.ArrayList;
import java.util.List;
public class KMeansExample {
public static void main(String[] args) {
int n = 10; // 随机数的数量
double a = -5, b = 5, c = 10; // [a, b+c]
List<Double> data = generateRandomNumbers(n, a, b + c); // 生成随机数
System.out.println("Generated Data:");
for (double num : data) {
System.out.print(num + " ");
}
System.out.println();
kMeansCluster(data);
}
private static List<Double> generateRandomNumbers(int count, double min, double max) {
List<Double> numbers = new ArrayList<>();
for (int i = 0; i < count; i++) {
double randomNum = Math.round((min + (max - min) * Math.random()) * 100.0) / 100.0;
numbers.add(randomNum);
}
return numbers;
}
private static void kMeansCluster(List<Double> data) {
if (data.isEmpty()) return;
// 初始化两个簇心为第一个和最后一个元素
double centroid1 = data.get(0), centroid2 = data.get(data.size() - 1);
boolean centroidsChanged;
do {
centroidsChanged = false;
// 分组
List<Double> cluster1 = new ArrayList<>();
List<Double> cluster2 = new ArrayList<>();
for (Double point : data) {
if (Math.abs(point - centroid1) <= Math.abs(point - centroid2)) {
cluster1.add(point);
} else {
cluster2.add(point);
}
}
// 更新簇心
double newCentroid1 = calculateMean(cluster1);
double newCentroid2 = calculateMean(cluster2);
if (!Double.isNaN(newCentroid1) && !Double.isNaN(newCentroid2)
&& (newCentroid1 != centroid1 || newCentroid2 != centroid2)) {
centroidsChanged = true;
centroid1 = newCentroid1;
centroid2 = newCentroid2;
}
} while (centroidsChanged);
// 输出分组结果
System.out.printf("Cluster1 Centroid: %.2f -> ", centroid1);
for (double d : data.stream()
.filter(p -> Math.abs(p - centroid1) <= Math.abs(p - centroid2))
.toList()) {
System.out.printf("%.2f ", d);
}
System.out.println();
System.out.printf("Cluster2 Centroid: %.2f -> ", centroid2);
for (double d : data.stream()
.filter(p -> Math.abs(p - centroid2) < Math.abs(p - centroid1))
.toList()) {
System.out.printf("%.2f ", d);
}
System.out.println();
}
private static double calculateMean(List<Double> points) {
if (points == null || points.isEmpty()) return Double.NaN;
double sum = 0;
for (double p : points) sum += p;
return sum / points.size(); // 计算平均值并返回
}
}
```
### 解释
这段程序的主要功能是对一组随机生成的数据进行简单的 **K-Means 聚类**,分为两组(即 K=2)。以下是详细步骤及其背后的逻辑:
1. **数据初始化**
- 使用了 `generateRandomNumbers` 函数来生成指定数量的随机双精度浮点数,并将其存储在一个列表 (`List<Double>`) 中。
2. **聚类算法核心思想**
- 初始设定两个质心(centroid),分别为数据中的第一项与最后一项。
- 按照每个数值离这两个初始质心的距离远近对其进行分类。
- 在每次迭代过程中重新根据分配情况更新新的质心位置。
- 如果新旧质心位置发生改变,则重复上述过程直到收敛或不再有变化为止。
3. **辅助函数**
- 提供了一个工具方法用于求取某一群集内所有成员之数学期望值——这便是所谓的“中心”。
这种简单版本仅适用于一维空间内的二维划分场景;实际应用可能涉及高维度及更复杂的参数设置等问题。
阅读全文
相关推荐

















