为了从300个点中选择200个点,使得这200个点的方差最小(即点集在特征空间中最紧凑),可以采用以下优化方法。核心思路是通过迭代优化逼近局部最优解,结合多组初始解避免陷入不良局部最优。以下是具体步骤:
方法概述
-
目标函数:最小化选出的200个点的总方差(Trace of Covariance),即各维度方差之和:
Vartotal=∑i∈S(∥xi−μS∥2) \text{Var}_{\text{total}} = \sum_{i \in S} \left( \| \mathbf{x}_i - \boldsymbol{\mu}_S \|^2 \right) Vartotal=i∈S∑(∥xi−μS∥2)
其中 SSS 是选中的点集,μS\boldsymbol{\mu}_SμS 是其质心。 -
算法选择:使用 迭代重定位算法(类似K-Means的思想),通过交替更新质心和重新选择最近点逐步降低方差。
-
关键技巧:
- 多组初始化:结合中心点初始化和随机初始化,避免局部最优。
- 早停机制:当目标函数变化小于阈值时停止迭代。
具体步骤
1. 初始化策略
- 中心初始化:计算所有300个点的质心,选择离质心最近的200个点作为初始解(快速且通常接近优解)。
- 随机初始化:生成多组随机选择的200个点,用于探索不同区域。
2. 迭代优化
对每组初始解进行迭代:
- Step 1:计算当前200个点的质心 μS\boldsymbol{\mu}_SμS。
- Step 2:计算所有300个点到 μS\boldsymbol{\mu}_SμS 的欧氏距离平方。
- Step 3:选择距离最小的200个点作为新子集。
- Step 4:计算新子集的目标函数值(总方差)。
- 停止条件:
- 目标函数变化量 < 阈值(如
1e-6
) - 或达到最大迭代次数(如
100
次)。
- 目标函数变化量 < 阈值(如
3. 选择最优解
保留所有初始化中目标函数值最小的子集作为最终结果。
Python代码实现
import numpy as np
import random
def select_min_variance_points(points, n_select=200, n_inits=10, max_iters=100, tol=1e-6):
"""
从points中选择n_select个点,使其方差最小
:param points: np数组, 形状为(300, 2)
:param n_select: 需选择的点数
:param n_inits: 初始化次数
:param max_iters: 最大迭代次数
:param tol: 收敛阈值
:return: 选中的点索引, 最终目标函数值
"""
n_points = points.shape[0]
best_subset = None
best_obj = float('inf')
# 初始化策略
initial_subsets = []
# 1. 中心初始化: 基于全局质心
centroid_all = np.mean(points, axis=0)
dists_to_center = np.sum((points - centroid_all)**2, axis=1)
center_init = np.argsort(dists_to_center)[:n_select]
initial_subsets.append(center_init)
# 2. 随机初始化
for _ in range(n_inits - 1):
random_init = random.sample(range(n_points), n_select)
initial_subsets.append(random_init)
# 迭代优化每组初始解
for subset in initial_subsets:
obj_val = compute_objective(points[subset])
for _ in range(max_iters):
# Step 1: 计算当前子集质心
centroid = np.mean(points[subset], axis=0)
# Step 2: 计算所有点到质心的距离平方
dists = np.sum((points - centroid)**2, axis=1)
# Step 3: 选择最近的n_select个点
new_subset = np.argpartition(dists, n_select)[:n_select]
new_obj = compute_objective(points[new_subset])
# 停止判断: 目标函数变化小于阈值
if abs(obj_val - new_obj) < tol:
break
subset = new_subset
obj_val = new_obj
# 更新全局最优解
if new_obj < best_obj:
best_obj = new_obj
best_subset = subset
return best_subset, best_obj
def compute_objective(subset_points):
"""计算子集的总方差 (目标函数)"""
centroid = np.mean(subset_points, axis=0)
return np.sum((subset_points - centroid)**2)
# 使用示例
if __name__ == "__main__":
# 生成示例数据: 300个2维点
np.random.seed(0)
points = np.random.rand(300, 2) * 100 # (x, y)坐标
# 选择方差最小的200个点
selected_indices, min_variance = select_min_variance_points(points)
print("选中的点索引:", selected_indices)
print("最小总方差:", min_variance)
算法特点
- 时间复杂度:每组初始化迭代计算 O(max_iters×300)O(\text{max\_iters} \times 300)O(max_iters×300),总开销 O(n_inits×max_iters×300)O(\text{n\_inits} \times \text{max\_iters} \times 300)O(n_inits×max_iters×300),对300个点可瞬时完成。
- 最优性保证:多组初始化(中心+随机)显著降低陷入局部最优的风险。
- 扩展性:可调整参数(如
n_inits
、tol
)平衡精度与速度。
数学解释
目标函数 Vartotal\text{Var}_{\text{total}}Vartotal 在迭代中单调下降:
- 固定质心时,选择最近点最小化当前距离和。
- 更新质心后,目标函数值进一步降低(因质心是方差最小点)。
- 每次迭代目标函数值非增,最终收敛到局部最优。
通过多组初始化,算法以高概率逼近全局最优解。此方法在点集精简(Subset Selection)、核心集(Coreset)构建等任务中广泛应用。