KNN Imputation 利用均值还是众数?

数据挖掘 数据挖掘 k-nn 数据插补
2022-03-05 04:56:54

在我当前的项目中,我正在使用 K = 5 进行 KNN 插补,并且正在使用 sklearn.impute.KNNImputer。我混合了连续变量和名义变量(编码为 0/1 或已编码为 0/0.25/0.5/0.75/1 等的序数变量)。但是,文档说“每个样本的缺失值都是使用训练集中找到的 n_neighbors 最近邻居的平均值估算的。” 因此,对于标称属性,我得到了介于 0.4 之类的中间值。有没有办法覆盖它以将名义列的平均值更改为模式?

另外,我查看了missingpy和fancyimpute,但它们似乎都在使用均值~

2个回答

默认情况下,scikit-learn 的KNNImputer使用欧几里德距离度量来搜索邻居并使用平均值来估算值。

如果您有连续变量和名义变量的组合,则应传入不同的距离度量。

如果您想使用除均值之外的其他插补函数,则必须自己实现。

解决此问题的最佳方法是使用如下管道:

工作示例

import pandas as pd
import numpy as np

from sklearn.pipeline import Pipeline
from sklearn.compose import make_column_selector, make_column_transformer
from sklearn.linear_model import LogisticRegression
from sklearn.impute import SimpleImputer, KNNImputer
from sklearn.preprocessing import OneHotEncoder, StandardScaler
from sklearn.model_selection import train_test_split
from sklearn.metrics import plot_roc_curve
from sklearn.datasets import fetch_openml

# Load the data
X, y = fetch_openml("titanic", version=1, as_frame=True, return_X_y=True)
X.replace({None:np.nan}, inplace = True)
# Some preprocessing to correct data types and replace None with nans for pipeline imputer
X.drop(["name","home.dest"], axis = 1, inplace = True)
X["embarked"] = X["embarked"].astype("object")
X["sex"] = X["sex"].astype("object")

X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y, test_size=0.2)

cat_prepro = Pipeline([("imputer",SimpleImputer(strategy="most_frequent")),
                        ("encoder",OneHotEncoder(handle_unknown = "ignore"))])

cont_prepro = Pipeline([("imputer", KNNImputer()), ("scaler",StandardScaler())])

preprocessor = make_column_transformer(
    (cat_prepro,make_column_selector(dtype_include= "object")),
     (cont_prepro,make_column_selector(dtype_exclude="object"))
     )

model = Pipeline([("preprocessor",preprocessor),
                  ("classifier",LogisticRegression(random_state= 1990))]).fit(X_train, y_train)


model.score(X_test,y_test)

plot_roc_curve(model,X_test,y_test);

在此处输入图像描述