【Educoder数据挖掘实训】插值填充法处理遗漏值
开挖
这关的介绍非常详细,只要看懂了基本就没有问题。
所谓插值其实就是根据已有的数据构造出函数,然后用这个函数来计算遗漏的数据。
比如这个题目中介绍的拉格朗日插值以及 K K K近邻。
有关拉格朗日插值在这里做一点儿介绍:
一直函数 f ( x ) f(x) f(x)在 n + 1 n+1 n+1个插值节点 a ≤ x 0 < x 1 < . . . < x n ≤ b a\le x_0 < x_1 <... < x_n \le b a≤x0<x1<...<xn≤b上的函数值 f ( x 0 ) , f ( x 1 ) , . . . , f ( x n ) f(x_0), f(x_1),...,f(x_n) f(x0),f(x1),...,f(xn),求构造一个次数不超过 n n n的插值函数多项式 L n ( x ) L_n(x) Ln(x)有 L n ( x i ) = y i = f ( x i ) L_n(x_i) = y_i = f(x_i) Ln(xi)=yi=f(xi)
给出构造:
L n ( x ) = ∑ i = 0 n l i ( x ) y i L_n(x) = \sum\limits_{i = 0} ^nl_i(x)y_i Ln(x)=i=0∑nli(x)yi
其中 l i ( x ) l_i(x) li(x)被称为 n n n次插值基函数。
l i ( x j ) = [ x j = = x i ] l_i(x_j) = [x_j == x_i] li(xj)=[xj==xi]
有 l i ( x ) = ∏ j = 0 , j ≠ i n x − x j x i − x j l_i(x) = \prod\limits_{j = 0, j\neq i}^n \frac{x - x_j}{x_i - x_j} li(x)=j=0,j=i∏nxi−xjx−xj。
易知这个构造方程是显然成立的而且次数不会超过 n n n次。
关于 K K K就是用函数 K N N I m p u t e r KNNImputer KNNImputer函数用欧几里得距离寻找最近邻,相当于最近邻算法的具体实现,不多赘述。
代码如下:
import pandas as pd
import numpy as np
from scipy.interpolate import lagrange
import sklearn
from sklearn.impute import KNNImputerdata = pd.read_csv("src/death.csv", index_col='Unnamed: 0')data = data.dropna(axis=1, thresh=data.shape[0] * 0.2)
data = data.dropna(axis=0, thresh=data.shape[1] * 0.2)cols = '2007/12/20'
########## Begin ##########
# 求出'2007/12/20'列的缺失行索引
na_index = data.index[data[cols].isna()]# 将'2007/12/20'列的缺失行使用前后三个数进行拉格朗日法替换s = data[cols]
for i in na_index :y = s[list(range(i - 3, i)) + list(range(i + 1, i + 1 + 3))]y = y[y.notnull()]data[cols][i] = lagrange(y.index, list(y))(i)print('2007/12/20 列的缺失值使用拉格朗日法替换为:', data[cols][i])########## End ##########na_index = pd.isna(data['FIPS'])
print('替换前:\n', data[['Lat', 'FIPS', 'Long_']][na_index])########## Begin ##########
# 使用 'Lat', 'FIPS', 'Long_' 三列进行 K 近邻计算
# data[['Lat', 'FIPS', 'Long_']] = data[['Lat', 'FIPS', 'Long_']].fillna(method='bfill')
imputer = KNNImputer(n_neighbors = 1)
# data[['Lat', 'FIPS', 'Long_']] = imputer.fit_transform(data[['Lat', 'FIPS', 'Long_']])
data[['Lat','FIPS','Long_']] = pd.DataFrame(imputer.fit_transform(data[['Lat','FIPS','Long_']]),columns=[['Lat', 'FIPS', 'Long_']])
print('替换后:\n', data[['Lat', 'FIPS', 'Long_']][na_index])########## End ##########
依然给出补充
这个题目中间有两行代码,分别是:
# data[['Lat', 'FIPS', 'Long_']] = imputer.fit_transform(data[['Lat', 'FIPS', 'Long_']])
data[['Lat','FIPS','Long_']] = pd.DataFrame(imputer.fit_transform(data[['Lat','FIPS','Long_']]),columns=[['Lat', 'FIPS', 'Long_']])
很疑惑这两行代码具体的区别是什么。
在大多数情况下是没区别的,但是第二种写法会更稳定,保证修改的行就是标记为 c o l u m n s columns columns的行。
两者的区别在于对填充后的数据是否进行了 D a t a F r a m e DataFrame DataFrame 包装,以及是否指定了列名。通常建议使用第一种方式,以确保填充后的数据与原始数据结构一致,并且避免潜在的错误。