You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

将MATLAB中带seuclidean距离的knnimpute转换为Python实现

将MATLAB的knnimpute转换为Python的解决方案

你的MATLAB代码filled_data = knnimpute(data,1, 'distance','seuclidean')核心逻辑是:用k=1的K近邻填充缺失值,采用距离加权(k=1时等价于直接取最近邻的值),距离度量为标准化欧氏距离(seuclidean)。以下是两种可行的转换方案:

方案一:使用sklearn.impute.KNNImputer自定义度量

KNNImputer支持传入自定义距离函数,我们可以实现兼容NaN的标准化欧氏距离:

  1. 先计算每个特征的标准差(忽略NaN,避免除以0)
  2. 定义处理NaN的标准化欧氏距离函数
  3. 初始化KNNImputer并执行填充
import numpy as np
from sklearn.impute import KNNImputer

# 假设data是你的输入数组(含NaN)
data = np.array(...)

# 1. 计算各特征的标准差(忽略NaN),处理标准差为0的情况
data_std = np.nanstd(data, axis=0)
data_std[data_std == 0] = 1e-8  # 避免除以0

# 2. 定义兼容NaN的标准化欧氏距离函数
def seuclidean_with_nan(x, y):
    # 筛选两个样本都非NaN的特征
    valid_mask = ~(np.isnan(x) | np.isnan(y))
    if not np.any(valid_mask):
        return np.inf  # 全NaN时距离设为无穷大
    # 计算标准化欧氏距离
    diff = (x[valid_mask] - y[valid_mask]) / data_std[valid_mask]
    return np.sqrt(np.sum(diff ** 2))

# 3. 初始化KNNImputer并填充
imputer = KNNImputer(n_neighbors=1, weights='distance', metric=seuclidean_with_nan)
filled_data = imputer.fit_transform(data)

方案二:手动实现MATLAB风格的knnimpute

如果需要完全贴合MATLAB的原始行为,可手动实现核心逻辑,适合小数据集或需要精细调试的场景:

import numpy as np

def knnimpute_seuclidean(data, k=1):
    data = np.array(data, dtype=np.float64)
    n_samples, n_features = data.shape
    
    # 计算各特征标准差(忽略NaN)
    stds = np.nanstd(data, axis=0)
    stds[stds == 0] = 1e-8
    
    # 获取所有无缺失值的样本索引
    non_missing_idx = np.where(~np.isnan(data).any(axis=1))[0]
    if len(non_missing_idx) == 0:
        raise ValueError("没有可用的非缺失样本")
    
    # 遍历每个样本,填充缺失值
    for i in range(n_samples):
        missing_mask = np.isnan(data[i])
        if not np.any(missing_mask):
            continue
        
        # 计算当前样本与所有非缺失样本的标准化欧氏距离
        distances = []
        for j in non_missing_idx:
            if i == j:
                continue
            # 筛选两个样本都非NaN的特征
            valid_mask = ~(missing_mask | np.isnan(data[j]))
            if not np.any(valid_mask):
                dist = np.inf
            else:
                diff = (data[i, valid_mask] - data[j, valid_mask]) / stds[valid_mask]
                dist = np.sqrt(np.sum(diff ** 2))
            distances.append((dist, j))
        
        # 按距离排序,取最近的k个样本
        distances.sort(key=lambda x: x[0])
        top_k = distances[:k]
        
        # 距离加权填充(k=1时直接取最近邻的值)
        if k == 1:
            fill_vals = data[top_k[0][1], missing_mask]
        else:
            # 加权平均(k>1时用,这里保留逻辑)
            total_weight = sum(1 / (d + 1e-8) for d, _ in top_k)
            fill_vals = sum((data[j, missing_mask] / (d + 1e-8)) for d, j in top_k) / total_weight
        
        data[i, missing_mask] = fill_vals
    
    return data

# 使用示例
filled_data = knnimpute_seuclidean(data, k=1)

注意事项

  • 两种方案都处理了标准差为0的情况,避免除以0错误
  • 针对全NaN的样本或特征,添加了异常处理逻辑
  • 当k=1时,距离加权等价于直接取最近邻的值,和MATLAB代码行为一致

内容的提问来源于stack exchange,提问作者k-c

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 18:17:42