缺失数据
三种缺失符号
np.nan是一个麻烦的东西,首先它不等与任何东西,甚至不等于自己
print(np.nan == np.nan)
print(np.nan == 0)
print(np.nan == None)
'''
False
False
False
'''
对于布尔类型的列表,如果是np.nan填充,那么它的值会自动变为True而不是False
print(pd.Series([1,np.nan,3],dtype='bool'))
'''
0 True
1 True
2 True
dtype: bool
'''
但当修改一个布尔列表时,会改变列表类型,而不是赋值为True
s = pd.Series([True,False],dtype='bool')
s[1]=np.nan
print(s)
'''
0 1.0
1 NaN
dtype: float64
'''
与np.nan
相比,None
的布尔值为False
,只要记住np.nan
的几个特性,而None
的特性与之相反即可。
NA的特性
1、逻辑运算
只需看该逻辑运算的结果是否依赖pd.NA的取值,如果依赖,则结果还是NA,如果不依赖,则直接计算结果
print(True | pd.NA)
print(pd.NA | True)
print(False | pd.NA)
print(False & pd.NA)
print(True & pd.NA)
'''
True
True
<NA>
False
<NA>
'''
2、算术运算和比较运算
这里只需记住除了下面两类情况,其他结果都是NA即可
print(pd.NA ** 0) # 1
print(1 ** pd.NA) # 1
convert_dtypes方法
这个函数的功能往往就是在读取数据时,就把数据列转为Nullable类型
print(pd.read_csv('table_missing.csv').convert_dtypes().dtypes)
'''
School string
Class string
ID Int64
Gender string
Address string
Height Int64
Weight Int64
Math float64
Physics string
dtype: object
'''
填充与剔除
dropna
函数作用很大,它可以剔除掉无用的NaN
缺失值,从列或者行中,或者从特定列或行中搜索缺失值剔除。
问题与习题
问题
【问题一】 如何删除缺失值占比超过25%的列?
percent = df.isna().sum()/len(df)
print(percent)
df.drop(columns=df.columns[percent>=0.25],inplace=True)
print(df.head())
'''
School 0.000000
Class 0.114286
ID 0.171429
Gender 0.200000
Address 0.000000
Height 0.000000
Weight 0.371429
Math 0.142857
Physics 0.114286
dtype: float64
School Class ID Gender Address Height Math Physics
0 S_1 C_1 NaN M street_1 173 34.0 A+
1 S_1 C_1 NaN F street_2 192 32.5 B+
2 S_1 C_1 1103.0 M street_2 186 87.2 B+
3 S_1 NaN NaN F street_2 167 80.4 NaN
4 S_1 C_1 1105.0 NaN street_4 159 84.8 A-
'''
【问题二】 什么是Nullable类型?请谈谈为什么要引入这个设计?
Nullable
类型是pandas的扩展类型,用于表示标量的缺失值且不改变数据类型。
其目的就是为了(在若干版本后)解决之前出现的混乱局面,统一缺失值处理方法。
【问题三】 对于一份有缺失值的数据,可以采取哪些策略或方法深化对它的了解?
- 通过isna(),info()等方法整体了解每行每列缺失值情况,统计缺失比例,了解缺失程度
习题
【练习一】现有一份虚拟数据集,列类型分别为string/浮点/整型,请解决如下问题:
(a)请以列类型读入数据,并选出C为缺失值的行。
(b)现需要将A中的部分单元转为缺失值,单元格中的最小转换概率为25%,且概率大小与所在行B列单元的值成正比。
df1 = pd.read_csv('Missing_data_one.csv')
print(df1[df1['C'].isna()])
'''
A B C
1 not_NaN 0.700 NaN
5 not_NaN 0.972 NaN
11 not_NaN 0.736 NaN
19 not_NaN 0.684 NaN
21 not_NaN 0.913 NaN
'''
第二小题想不明白。贴出参考答案。
min_b = df1['B'].min()
df1['A'] = pd.Series(list(zip(df1['A'].values
,df1['B'].values))).apply(lambda x:x[0] if np.random.rand()>0.25*x[1]/min_b else np.nan)
print(df1.head())
'''
A B C
0 NaN 0.922 4.0
1 not_NaN 0.700 NaN
2 not_NaN 0.503 8.0
3 NaN 0.938 4.0
4 not_NaN 0.952 10.0
'''
【练习二】 现有一份缺失的数据集,记录了36个人来自的地区、身高、体重、年龄和工资,请解决如下问题:
(a)统计各列缺失的比例并选出在后三列中至少有两个非缺失值的行。
(b)请结合身高列和地区列中的数据,对体重进行合理插值。
真~想到头皮发麻
还是想不出来。
我们来看看别人的优秀程序。
df2 = pd.read_csv('Missing_data_two.csv')
print(df2.isna().sum())
percent2 = df2.isna().sum() / len(df2)
print(percent2)
column_list = df2.columns[-3:]
df2_isna = df2[df2[column_list].isna().sum(1)<=1]
print(df2_isna).head()
'''
编号 0.000000
地区 0.000000
身高 0.000000
体重 0.222222
年龄 0.250000
工资 0.222222
dtype: float64
编号 地区 身高 体重 年龄 工资
0 1 A 157.50 NaN 47.0 15905.0
1 2 B 202.00 91.80 25.0 NaN
3 4 A 166.61 59.95 77.0 5434.0
4 5 B 185.19 NaN 62.0 4242.0
5 6 A 187.13 78.42 55.0 13959.0
'''
df3 = df2.copy()
df_group = df3.groupby('地区')
df_group.head()
for temp in df_group:
df_group_temp = temp[1]
df3.loc[df_group_temp.index, '体重'] = df_group_temp[['身高', '体重']].sort_values(by='身高').interpolate()['体重']
print(df3.head())
'''
编号 地区 身高 体重 年龄 工资
0 1 A 157.50 53.58 47.0 15905.0
1 2 B 202.00 91.80 25.0 NaN
2 3 C 169.09 62.18 NaN NaN
3 4 A 166.61 59.95 77.0 5434.0
4 5 B 185.19 81.75 62.0 4242.0
'''