引言
本文主要介绍一下 Pandas 数据清洗,处理缺失值。更多 Python 进阶系列文章,请参考 Python 进阶学习 玩转数据系列
内容提要:
- 数据缺失的现实场景
- Python 中表示缺失值的对象
● None
● NaN
● NA
● 正负无穷 inf and -inf - 处理缺失值
● 了解数据
● 定位缺失数据
● 处理缺失数据
数据缺失的现实场景
- 数据应用类别
比如,患者生日,对女性来说是这个数据比较有参考意义,没有值提供的被认为是男性患者。 - 数据来源缺失
比如用户调查数据,有部分用户拒绝提供数据,数据录入系统时由于数据转换被删除一部分数据。 - 数据无效
输入格式不正确,或错误的数据(如,年龄 250 或 -5), 对这类数据就要处理成缺失数据
Python 中表示缺失值的对象
对象 | 描述 |
---|---|
NA | Not Available |
NaN | Not a Number |
None | Pythonic missing data, a Python object that can be used in arrays with data type object |
inf | positive infinity |
-inf | negative infinity |
None
- None 一个 Python 对象
- 不可以用在任意的 NumPy 或 Pandas 数组里,只用于列表且数据类型是 Object。
- 默认 Pandas 会将 None 转换成 NAN
- 对包含 None 元素的数组进行计算(如: sum, min, max)会抛出 TypeError 异常。
NaN
- NaN 是一个特殊的浮点型值
- 带有 NaN 的值进行算术运算的结果是 NaN
- 可以用特殊的函数忽略 NaN: 如 np.nansum()
注意:NaN 是浮点型类型,如果用其它类型去访问它会抛出异常。
NA
- Pandas 遇到缺失对象会视为 NaN
- NumPy数组不能处理缺失对象,但能处理 NaN 值
import pandas as pd
import io
data_pd_na = '''Gender|Age|Weight
M | 22 | 72.0
F | 29 | 55.0
M | 24 |
F || 57.0
'''
df_na = pd.read_table (io.StringIO(data_pd_na), sep = '|')
# NumPy: Can NOT handle NA values
d2 = '''M 22 72.0
F 29
M 24 78.0
F 25 57.0
'''
data_np_na = io.StringIO(d2)
# Should produce a ValueError
np.loadtxt(data_np_na,
dtype={'names': ('Gender', 'Age', 'Color'),
'formats': ('S1', 'i4', 'f4')})
NumPy能处理 NaN的值
# Missing values as NaN
d3 = '''M 22 72.0
F 29 NaN
M 24 78.0
F 25 57.0
'''
data_np_nan = io.StringIO(d3)
# Should work with NaN missing values
np_array_nan = np.loadtxt(data_np_nan,
dtype={'names': ('Gender', 'Age', 'Color'),
'formats': ('S1', 'i4', 'f4')})
# an array of tuples
np.reshape (np.array (np_array_nan), (4,1))
# Missing values as NaN
d3 = '''1 22 1
1 29 NaN
1 24 1
1 25 1
'''
data_np_nan = io.StringIO(d3)
# state explicitly to treat nan as floating point
np_array_nan = np.loadtxt(data_np_nan, dtype=np.float)
print (np_array_nan)
print (np_array_nan.shape) # 4-by-3 array
NaN 必须是浮点型类型,不然会抛错
# should fail if try to treat nan as int:
d4 = '''1 22 1
1 29 NaN
1 24 1
1 25 1
'''
data_np_nan = io.StringIO(d4)
np_array_nan_int = np.loadtxt(data_np_nan, dtype=np.int)
正负无穷 inf and -inf
- 正负无穷的表示:
● float(“inf”) or float(“-inf”)
● np.inf, np.PINF, -np.inf, np.NINF - 判断数字是否是正负无穷
● math 包的 math.isinf() 函数
● numpy 包的 np.isinf(), np.isposinf(), np.isneginf(), np.isfinite() 函数
正负无穷表示
import numpy as np
# positive infinity
p_inf = float("inf")
np_posinf = np.inf
np_posinf_1 = np.PINF
# negative infinity
n_inf = float("-inf")
np_neginf = -np.inf
np_neginf_1 = np.NINF
print("p_inf:{}".format(p_inf))
print("np_posinf:{}".format(np_posinf))
print("np_posinf_1:{}".format(np_posinf_1))
print("n_inf:{}".format(n_inf))
print("np_neginf:{}".format(np_neginf))
print("np_neginf_1:{}".format(np_neginf_1))
输出:
p_inf:inf
np_posinf:inf
np_posinf_1:inf
n_inf:-inf
np_neginf:-inf
np_neginf_1:-inf
判断是否是正负无穷:
import numpy as np
import pandas as pd
import io
x = np.array([-np.inf, 0., np.inf])
print("x:\n{}".format(np.isinf (x)))
data_pd_na = '''Gender|Age|Weight
M | 22 | 72.0
F || 55.0
M | 24 |-inf
F |inf| 57.0
'''
df = pd.read_table (io.StringIO(data_pd_na), sep = '|')
inf_df = df.isin ([np.inf, -np.inf])
# Remove rows with inf
no_inf_df = df[ ~df.isin([np.inf, -np.inf]).any(1) ]
print("inf_df:\n{}".format(inf_df))
print("no_inf_df:\n{}".format(no_inf_df))
Pandas: pd.set_options() to 处理 inf, -inf
通过 pd.set_option (‘mode.use_inf_as_na’, True) 将 inf 和 -inf 用 NaN 代替
import pandas as pd
import io
#pd.set_option?
# default is False
pd.set_option ('mode.use_inf_as_na', False)
pd_option = pd.get_option ('mode.use_inf_as_na')
data_pd_inf = '''Gender|Age|Weight
M | 22 | 72.0
F || 55.0
M | 24 |-inf
F |inf| 57.0
'''
df_inf = pd.read_table (io.StringIO(data_pd_inf), sep = '|')
print("options mode.use_inf_as_na:{}".format(pd_option))
print("df_inf:\n{}".format(df_inf))
# set mode.use_inf_as_na as true
pd.set_option ('mode.use_inf_as_na', True)
pd_option = pd.get_option ('mode.use_inf_as_na')
print("options mode.use_inf_as_na:{}".format(pd_option))
print("df_inf:\n{}".format(df_inf))
处理缺失值
步骤:
- 了解数据
- 定位缺失数据
- 处理缺失数据
下面通过一个例子来实战一把。
了解数据
通过 shape,columns,head() 等大概了解一下数据
describe() 了解一下统计信息,只支持数字类的统计,但是没有缺失数据的报告。
定位缺失数据
df.isin([np.nan, np.inf, -np.inf]) 判断数据是否缺失
df.info() 用来了解非缺失数据的数量
还可以通过下面几种方式更直观的了解缺失数据的数量。
df.isnull().sum() 和 len(df.index) - df.count()
df.isnull().sum().sum() 和 *df.isnull().sum()/len(df)100
处理缺失数据
方法1:用 mask (Boolean) 数组过滤
● 用 df.isin([np.nan, np.inf, -np.inf]) 方法
● 用 df.any() 方法只要包含任意一个缺失的值
● 最后,用 布尔数组来进行切分
df [ ~df.isin([np.nan, np.inf, -np.inf]).any(1) ].head(5)
方法2:替换 inf 和 -inf 成 NaN, 然后选择 non-null 的行数据
df [ df.replace([np.inf, -np.inf], np.nan).notnull().all(axis=1) ].head(5)
方法3:替换 inf 和 -inf 成 NaN, 然后用 .dropna() 方法删除为空的数据
df.replace([np.inf, -np.inf], np.nan).dropna(axis=1).head(5)
方法4:用df.fillna(value=values) 将缺失的数据进行填充
values = {“NonD”:111, “Dream”:222, “Span”:333}
df.fillna(value = values).head()
df.fillna(555).head()