"""
运用拉格朗日插值法给空缺数据进行插值,其知识储备可参考如下链接:
https://blog.csdn.net/shener_m/article/details/81706358
"""
import pandas as pd # 导入数据分析库Pandas
from scipy.interpolate import lagrange # 导入拉格朗日插值函数
import matplotlib.pyplot as plt
import math
# 构建原始数据
data = pd.DataFrame([
["2015/3/1", 59],
["2015/2/28", 2618.2],
["2015/2/27", 2608.4],
["2015/2/26", 2651.9],
["2015/2/25", 3442.1],
["2015/2/24", 3393.1],
["2015/2/23", 3136.6],
["2015/2/22", 3744.1],
["2015/2/21", ],
["2015/2/20", 4060.3],
["2015/2/19", 3614.7],
["2015/2/18", 3295.5],
["2015/2/16", 2332.1],
["2015/2/15", 2699.3],
["2015/2/14", ],
["2015/2/13", 3036.8],
["2015/2/12", 1865],
["2015/2/11", 3014.3],
["2015/2/10", 2742.8],
["2015/2/9", 2173.5],
["2015/2/8", 3161.8],
["2015/2/7", 3023.8],
["2015/2/6", 2998.1],
], columns=['date', 'much'])
print(data.info())
# 设置异常值,把销量大于5000和销量小于400的异常值替换为None
data['much'] = data['much'].apply(lambda x: None if x < 400 or x > 5000 else x)
# data['much'][data['much'] < 400] = None
# data['much'][data['much'] > 3000] = None
# data.loc[data['much'] < 400, 'much'] = None
# data.loc[data['much'] > 3000, 'much'] = None
print(data)
def mylagrange_all_data(df_data, dim=1):
"""
df_data:输入的数据,格式是dataframe格式
dim:选取进行插值操作的列
"""
df = df_data.copy()
# n为插值考虑的范围,为前后5个数(相当于一个窗口windows)
n = 5
# 插搜索much列的异常值并且值
for i in range(len(df)):
# ma.isnan()判断值是否为空值, 相关指导链接:https://www.cnblogs.com/chenhuabin/archive/2019/03/06/10485549.html
if math.isnan(df.iat[i, dim]):
# 插值算法考虑的数据interdf是一个Series从空值算起前后n个
interdf = df.iloc[i-n:i+n+1, dim] # 行选取的操作
# 删除掉里面的空值
interdf = interdf[interdf.notnull()]
# x为数据的索引,也可以为其他列的值
list_x = list(interdf.index)
# y为Series里的值,x,y都转换成列表
list_y = list(interdf.values)
# f为利用拉格朗日法建立的函数关系y=f(x)
f = lagrange(list_x, list_y)
# 把插值结果加入到df中
df.iat[i, dim] = f(i)
return df
def mylagrange_one_data(df_data):
"""
df_data:输入的数据,格式是单列数据
"""
df = df_data.copy()
# n为插值考虑的范围,为前后5个数(相当于一个窗口windows)
n = 5
# 搜索much列的异常值并且插值
for i in range(len(df)):
# ma.isnan()判断值是否为空值, 相关指导链接:https://www.cnblogs.com/chenhuabin/archive/2019/03/06/10485549.html
if math.isnan(df.iat[i]):
# 插值算法考虑的数据interdf是一个Series从空值算起前后n个
interdf = df.iloc[i-n:i+n+1] # 行选取的操作
# 删除掉里面的空值
interdf = interdf[interdf.notnull()]
# x为数据的索引,也可以为其他列的值
list_x = list(interdf.index)
# y为Series里的值,x,y都转换成列表
list_y = list(interdf.values)
# f为利用拉格朗日法建立的函数关系y=f(x)
f = lagrange(list_x, list_y)
# 把插值结果加入到df中
df.iat[i] = f(i)
return df
# 把要处理的数据取出来,pandas中dataframe格式单独取出一列就是series数据格式,这里全部数据copy
tmp_data = data.copy()
tmp_data_1 = data['much'].copy()
result = mylagrange_all_data(tmp_data, dim=1) # 使用整个数据集进行拉格朗日计算
result.rename(columns={'much': 'new_much'}, inplace=True)
print(result)
result_1 = mylagrange_one_data(tmp_data_1) # 使用单列数据进行拉格朗日计算
my_result_1 = data.copy()
my_result_1['much'] = result_1
my_result_1.rename(columns={'much': 'new_much'}, inplace=True)
#绘图
data['much'].plot(alpha=0.5, style='ro-')
result['new_much'].plot(style='k--')
plt.legend(loc='best')
plt.show()