目的
1.查找NaN值(定位到哪一列、在列的哪个索引位置)
2.填充NaN值(向上填充、向下填充、线性填充等)
3.过滤NaN值
构建简单的Dataframe数据结构环境
import pandas as pd import numpy as np #在df中nan和None都会被自动填充为NaN df=pd.DataFrame({'a':[np.nan,1,2,3],'b':[None,5,6,7],'c':[8,9,10,11]}) print(df) '''结果 a b c 0 NaN NaN 8 1 1.0 5.0 9 2 2.0 6.0 10 3 3.0 7.0 11 '''
注意点:
1.None、nan在构建dataframe数据结构中都会被识别为NaN
2.None与nan的类型是不一样的
#nan是个特殊的float类型 print(type(np.nan)) #<class 'float'> #None是NoneType print(type(None)) #<class 'NoneType'>
#打印空值看输出结果 print(df['a'][0]) #nan
#作为字典的key时,会被认为是不同的key
dic={None:1, NaN:2}
print(dic) #{None: 1, nan: 2}
目的1:查找NaN值
原始数据:
df=pd.DataFrame({'a':[0,1,np.nan,3,4],'b':[4,5,6,np.nan,8],'c':[9,10,np.nan,np.nan,13]}) print(df) '''结果 a b c 0 0.0 4.0 9.0 1 1.0 5.0 10.0 2 NaN 6.0 NaN 3 3.0 NaN NaN 4 4.0 8.0 13.0 '''
1.1 输出NaN值所在具体位置(调用math下面的isnan做判断)
from math import isnan for i in df.columns: # print(df[i].values) for k in range(len( df[i].values)): if isnan(df[i].values[k]): print('字段%s存在NaN值:' % i + '索引位置是:%s'%k)
1.2 分别找到NaN值所在的列名、行名:np.isnan()
import pandas as pd import numpy as np from math import isnan #在df中nan和None都会被自动填充为NaN df=pd.DataFrame({'a':[np.nan,1,2,3,4],'b':[4,5,6,np.nan,np.nan],'c':[9,10,np.nan,np.nan,np.nan]},index=['index_0','index_1','index_2','index_3','index_4']) print(df) '''原始数据 a b c index_0 NaN 4.0 9.0 index_1 1.0 5.0 10.0 index_2 2.0 6.0 NaN index_3 3.0 NaN NaN index_4 4.0 NaN NaN ''' #利用np.isnan(df),对整个df的NaN值做判断 res=np.isnan(df) print(res) ''' a b c index_0 True False False index_1 False False False index_2 False False True index_3 False True True index_4 False True True ''' nan_res=np.where(np.isnan(df)) print(nan_res) #(array([0, 2, 3, 3, 4, 4], dtype=int32), array([0, 2, 1, 2, 1, 2], dtype=int32)) ''' #得到一个元祖 (array([0, 2, 3, 3, 4, 4], dtype=int32), array([0, 2, 1, 2, 1, 2], dtype=int32)) 元祖第一个值:表示行索引(都是以数字表示) 元祖第二个值:表示列索引(都是以数字表示) 注意:看前后行、列索引列表的排序,发现是每一行的数据去逐一检索的 ''' #查看NaN值默认行号(数字)(有重复值时表示是这一行里有多个NaN值) print(nan_res[0]) #[0 2 3 3 4 4] print(nan_res[1]) #[0 2 1 2 1 2] #查看NaN值的行号名(即实际行号名字) nan_index_info=df.index[np.where(np.isnan(df))[0]] print(nan_index_info) #Index(['index_0', 'index_2', 'index_3', 'index_3', 'index_4', 'index_4'], dtype='object') #查看NaN值的列名 nan_columns_info=df.columns[np.where(np.isnan(df))[1]] print(nan_columns_info) #Index(['a', 'c', 'b', 'c', 'b', 'c'], dtype='object')
1.3 isnull、notnull
isnull_res=df.isnull() print(isnull_res) ''' a b c 0 False False False 1 False False False 2 True False True 3 False True True 4 False False False '''
1.4 isnull().values
# 2.1 isnull().values isnull_res=df.isnull().values print(isnull_res) ''' [[False False False] [False False False] [ True False True] [False True True] [False False False]] '''
1.5 isnull().sum() 统计显示
#2.3 isnull().sum() 统计 isnull_res=df.isnull().sum() print(isnull_res) ''' a 1 b 1 c 2 dtype: int64 '''
1.6 isnull().any() 布尔值,显示行里是不是有NaN值
df=pd.DataFrame({'a':[0,1,np.nan,3,4],'b':[4,5,6,np.nan,8],'c':[9,10,np.nan,np.nan,13]}) print(df) '''原始数据 a b c 0 0.0 4.0 9.0 1 1.0 5.0 10.0 2 NaN 6.0 NaN 3 3.0 NaN NaN 4 4.0 8.0 13.0 ''' any_res=df.isnull().any() print(any_res) ''' a True b True c True dtype: bool '''
目的2:填充NaN值
原始数据样子:
df=pd.DataFrame({'a':[0,1,np.nan,3,4],'b':[4,5,6,np.nan,8],'c':[9,10,np.nan,np.nan,13]}) print(df) '''结果 a b c 0 0.0 4.0 9.0 1 1.0 5.0 10.0 2 NaN 6.0 NaN 3 3.0 NaN NaN 4 4.0 8.0 13.0 '''
2.1 fillna直接填充
#2.1.fillna直接填充 df.fillna(0,inplace=True) #表示更新到源数据 print(df) ''' a b c 0 0.0 4.0 9.0 1 1.0 5.0 10.0 2 0.0 6.0 0.0 3 3.0 0.0 0.0 4 4.0 8.0 13.0 '''
#另外一种方式
res=df.where(df.notna(),100)
fillna({字典}),字典key:表示列索引 value:表示要填充的值
df=pd.DataFrame({'a':[0,1,2,3,4],'b':[4,5,6,np.nan,8],'c':[9,10,np.nan,np.nan,13]}) #意为将b列空值:填充为00 c列空值填充为:11
df_new=df.fillna({'b':00,'c':11}) print(df_new) ''' a b c 0 0 4.0 9.0 1 1 5.0 10.0 2 2 6.0 11.0 3 3 0.0 11.0 4 4 8.0 13.0 '''
2.2 向上填充(即取NaN后面一个数值作为填充):bfill
fillna_res=df.fillna(method='bfill') print(fillna_res) ''' a b c 0 0.0 4.0 9.0 1 1.0 5.0 10.0 2 3.0 6.0 13.0 3 3.0 8.0 13.0 4 4.0 8.0 13.0 '''
2.3 向下填充(即取NaN前面一个数值作为填充):ffill
fillna_res=df.fillna(method='ffill') print(fillna_res) ''' a b c 0 0.0 4.0 9.0 1 1.0 5.0 10.0 2 1.0 6.0 10.0 3 3.0 6.0 10.0 4 4.0 8.0 13.0 '''
2.4 用一个数据代替NaN:pad (功能类似于向下填充ffill)
fillna_res=df.fillna(method='pad') print(fillna_res) ''' a b c 0 0.0 4.0 9.0 1 1.0 5.0 10.0 2 1.0 6.0 10.0 3 3.0 6.0 10.0 4 4.0 8.0 13.0 '''
2.5 平均值替换:df.mean()
#平均值替换:df.mean() fillna_res=df.fillna(df.mean()) print(fillna_res) ''' a b c 0 0.0 4.00 9.000000 1 1.0 5.00 10.000000 2 2.0 6.00 10.666667 3 3.0 5.75 10.666667 4 4.0 8.00 13.000000 '''
2.6 指定替换具体列的NaN值
#选择指定替换哪些列 choose_fillna=df.fillna(df.mean()['a':'b']) print(choose_fillna) ''' a b c 0 0.0 4.00 9.0 1 1.0 5.00 10.0 2 2.0 6.00 NaN 3 3.0 5.75 NaN 4 4.0 8.00 13.0 '''
2.7 限制每列替换NaN的个数:limit=
limit_res=df.fillna(df.mean(),limit=1) print(limit_res) ''' a b c 0 0.0 4.00 9.000000 1 1.0 5.00 10.000000 2 2.0 6.00 10.666667 3 3.0 5.75 NaN 4 4.0 8.00 13.000000 '''
2.8 线性插值 df.interpolate(),如果存在第一个值是NaN的情况,这个NaN值无法被替换,需要单独再判断
df=pd.DataFrame({'a':[2,1,2,3,4],'b':[4,5,6,np.nan,2],'c':[9,10,np.nan,np.nan,4]},index=['index_0','index_1','index_2','index_3','index_4']) print(df) ''' a b c index_0 2 4.0 9.0 index_1 1 5.0 10.0 index_2 2 6.0 NaN index_3 3 NaN NaN index_4 4 2.0 4.0 ''' #实际上上前一个值和后一个值得平均数,因为interpolate()假设函数是直线形式 print(df.interpolate()) ''' a b c index_0 2 4.0 9.0 index_1 1 5.0 10.0 index_2 2 6.0 8.0 index_3 3 4.0 6.0 index_4 4 2.0 4.0 '''
特殊情况的填充:
重点:假设每一列数据的第一或最后为空(再用上面的普通方法就填充时就容易忽略掉1和最后的值)
解决思路:
#解决的一个问题是开头和结果都是NaN的情况 1.判断如果开头是NaN取下面最近的数值填充 2.如果结尾是NaN取上面最近的数值填充 3.最后再对整体的中间NaN进行替换,就可以向上或向下取值了代码
初始数据结构:
df=pd.DataFrame({'a':[np.nan,1,np.nan,3,4],'b':[None,5,np.nan,7,None],'c':[9,10,np.nan,12,13]}) print(df) df=pd.DataFrame({'a':[np.nan,1,np.nan,3,4],'b':[None,5,np.nan,7,None],'c':[9,10,np.nan,12,13]}) print(df) ''' a b c 0 NaN NaN 9.0 1 1.0 5.0 10.0 2 NaN NaN NaN 3 3.0 7.0 12.0 4 4.0 NaN 13.0 '''
代码实现3个步骤:
#循环没一个列的value值(判断) for i in df.columns: n=1 for k in range(len(df[i].values)): #如果第一个值是NaN if isnan(df[i].values[0]): #找下面最近的不是NaN的值做填充 if not isnan(df[i].values[k]): df[i].values[0]=df[i].values[k] # print('说明第一个值是0,要替换成下面离他最近的一个数值') #如果最后一个值是NaN elif isnan(df[i].values[len(df[i].values)-1]): n+=1 #再判断倒数第二个值看是否是NaN(依次往上找,找到不是NaN的值做替换) if not isnan(df[i].values[len(df[i].values)-n]): df[i].values[len(df[i].values) - 1]=df[i].values[len(df[i].values)-n] # print('说明最后一个值是0,要替换成上面离他最近的一个数值') #最终对整体没一列中存在的NaN数据进行向前取值 df=df.fillna(method='pad') print(df)
目的3:过滤NaN值
初始数据
df=pd.DataFrame({'a':[0,1,2,3,4],'b':[4,5,6,np.nan,8],'c':[9,10,np.nan,np.nan,13]}) print(df) ''' a b c 0 0 4.0 9.0 1 1 5.0 10.0 2 2 6.0 NaN 3 3 NaN NaN 4 4 8.0 13.0 '''
3.1 删除存在NaN的行或列:dropna()
#默认删除存在NaN的行: # res=df.dropna() # print(res) ''' a b c 0 0 4.0 9.0 1 1 5.0 10.0 4 4 8.0 13.0 '''
3.2 删除存在NaN的列:axis=1
res=df.dropna(axis=1) #删除存在NaN的列 print(res) ''' a 0 0 1 1 2 2 3 3 4 4 '''
3.3 删除全为NaN的行:how='all'
#删除全为NaN的行 all_res=df.dropna(how='all') print(all_res)
3.4 删除全为NaN的列(axis=1,how='all')
#删除全为NaN的列(axis=1,how='all') df=pd.DataFrame({'a':[0,1,2,np.nan,4],'b':[4,5,6,np.nan,8],'c':[np.nan,np.nan,np.nan,np.nan,np.nan]}) print(df) ''' a b c 0 0.0 4.0 NaN 1 1.0 5.0 NaN 2 2.0 6.0 NaN 3 NaN NaN NaN 4 4.0 8.0 NaN ''' all_loc_res=df.dropna(axis=1,how='all') print(all_loc_res) ''' a b 0 0.0 4.0 1 1.0 5.0 2 2.0 6.0 3 NaN NaN 4 4.0 8.0 '''
3.5 dropna(thresh=2参数),过滤NaN时再做近一步的条件筛选
#在df中nan和None都会被自动填充为NaN df=pd.DataFrame({'a':[np.nan,1,2,3,4],'b':[4,5,6,np.nan,np.nan],'c':[9,10,np.nan,np.nan,np.nan]},index=['index_0','index_1','index_2','index_3','index_4']) print(df) '''原始数据 a b c index_0 NaN 4.0 9.0 index_1 1.0 5.0 10.0 index_2 2.0 6.0 NaN index_3 3.0 NaN NaN index_4 4.0 NaN NaN ''' #过滤取值,保留在行方向上至少有3个非空的项:dropna(thresh=2) res=df.dropna(thresh=2) print(res) ''' a b c index_0 NaN 4.0 9.0 index_1 1.0 5.0 10.0 index_2 2.0 6.0 NaN ''' #过滤取值,保留在列方向上至少有3个非空的项 res=df.dropna(thresh=3,axis=1) print(res) ''' a b index_0 NaN 4.0 index_1 1.0 5.0 index_2 2.0 6.0 index_3 3.0 NaN index_4 4.0 NaN '''