【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 KNNImputer
data = 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 包装,以及是否指定了列名。通常建议使用第一种方式,以确保填充后的数据与原始数据结构一致,并且避免潜在的错误。