1。1数据缺失值处理
小伙伴们,今天我为大家介绍一下什么是缺失值以及怎样处理缺失值(Missing values)的问题。
数据缺失主要包括我们在输入数据时,记录缺失和字段信息缺失等情况,缺失数据是一种常见现象,会对从数据中得出的结论产生重大影响。
首先,我们导入相关库import numpy as np import pandas as pd import matplotlib.pyplot as plt from scipy import stats %matplotlib inline #解决中文显示问题 plt.rcParams["font.sans-serif"]=["SimHei"] plt.rcParams["axes.unicode_minus"] = False# 创建数据 df = pd.DataFrame({"value1":[22,33,55,123,np.nan,np.nan,66,54,np.nan,99,180], "value2":["a","b","c","d","e",np.nan,np.nan,"f","g",np.nan,"g"]}) df
#查看缺失值 # Dataframe直接判断是否是缺失值,返回一个Series df.notnull()
# 通过索引判断 df["value1"].notnull()
# 注意和 df2 = df[df["value2"].notnull()] ["value1"] 的区别 df2 = df[df["value2"].notnull()] df2
现在,我们来看看用哪些方法来处理缺失值:
a. 删除缺失值 - dropna# drop方法:可直接用于Series,Dataframe df3 = df.dropna() df3
伙伴们可以把原始df与drop nan值之后的下表比较一下:
b. 填充/替换缺失数据 - fillna、replace# 创建数据 s = pd.Series([12,33,45,23,np.nan,np.nan,66,54,np.nan,99]) df = pd.DataFrame({"value1":[12,33,45,23,np.nan,np.nan,66,54,np.nan,99,190], "value2":["a","b","c","d","e",np.nan,np.nan,"f","g",np.nan,"g"]}) print(s) s.fillna(0,inplace = True) print(s)
Nan值已经变成了0。
左为原s,右为fillna后的结果
看一下fillna的方法参数:# s.fillna(value=None, method=None, axis=None, inplace=False, limit=None, downcast=None, **kwargs) # value:填充值 # 注意inplace参数
DataFrame使用fillna的代码和结果:df["value1"].fillna(method = "pad",inplace = True) df
左为原df,右为fillna后的结果
我们也可以使用中文来代替缺失值:s = pd.Series([1,1,1,1,2,2,2,3,4,5,np.nan,np.nan,66,54,np.nan,99]) print(s) s.replace(np.nan,"缺失数据",inplace = True) print(s)
左为原s,右为fillna后的结果
c. 缺失值插补, 使用均值/中位数/众数插补、临近值插补、插值法s = pd.Series([1,2,3,np.nan,3,4,5,5,5,5,np.nan,np.nan,6,6,7,12,2,np.nan,3,4]) print(s) # 分别求出均值/中位数/众数 u = s.mean() # 均值 me = s.median() # 中位数 mod = s.mode() # 众数 print("均值为:%.2f, 中位数为:%.2f" % (u,me)) print("众数为:", mod.tolist()) # 示例: 用均值填补 s.fillna(u,inplace = True) print(s)
均值
用均值填充NaN值
用前值填充Nan值:s = pd.Series([1,2,3,np.nan,3,4,5,5,5,5,np.nan,np.nan,6,6,7,12,2,np.nan,3,4]) s.fillna(method = "ffill",inplace = True) print(s)
d. 用拉格朗日插值法, 拉格朗日插值就是计算出相关x的系数来拟合多个点的方法。
例如:from scipy.interpolate import lagrange x = [3, 6, 9] y = [10, 8, 4] df = pd.DataFrame({"x": np.arange(15)}) df["y"] = lagrange(x,y)(df["x"]) # df plt.plot(df["x"],df["y"], linestyle="--", color="k")
y值就是通过拉格朗日插值法拟合函数后可能的结果:
拉格朗日插值
拉格朗日插值法,实际运用:data = pd.Series(np.random.rand(100)*100) data[[5,6,33,56,45,66,67,80,90]] = np.nan # 密度图查看缺失值情况 data_c = data.fillna(data.median()) # 中位数填充缺失值 fig,axes = plt.subplots(1,4,figsize = (20,5)) data.plot.box(ax = axes[0],grid = True,title = "数据分布") data.plot(kind = "kde",style = "--r",ax = axes[1],grid = True,title = "删除缺失值",xlim = [-50,150]) data_c.plot(kind = "kde",style = "--b",ax = axes[2],grid = True,title = "缺失值填充中位数",xlim = [-50,150]) # 创建函数,做插值,由于数据量原因,以空值前后5个数据(共10个数据)为例做插值 def na_c(s,n,k=5): y = s[list(range(n-k,n+1+k))] # 取数 y = y[y.notnull()] # 剔除空值 return(lagrange(y.index,list(y))(n)) # 缺失值插值 na_re = [] for i in range(len(data)): if data.isnull()[i]: data[i] = na_c(data,i) print(na_c(data,i)) na_re.append(data[i]) data.dropna(inplace=True) # 清除插值后仍存在的缺失值 data.plot(kind = "kde",style = "--k",ax = axes[3],grid = True,title = "拉格朗日插值后",xlim = [-50,150])
最后,我们用图例来比较一下删除缺失值、用中位数填充缺失值以及使用拉格朗日插值法后的数据密度分布情况:
可以看出,拉格朗日插值来填充缺失值还是很不错的!
好了,小伙伴们如果对处理缺失值有什么疑问,欢迎在评论区留言,咱们下期再见!~