You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
pqxin6emf/Part1/Chapter3/3.1 Pandas基础/3.1.7数值运算与缺失值处理.md

5.8 KiB

3.1.7:数值运算与缺失值处理

选择处理缺失值的方法

一般情况下可以分为两种:一种方法是通过一个覆盖全局的掩码表示缺失值,另一种方法是用一个**标签值sentinel value**表示缺失值。

  • 掩码方法中掩码可能是一个与原数组维度相同的完整布尔类型数组,也可能是用一个比特(01)表示有缺失值的局部状态。

  • 标签方法中,标签值可能是具体的数据(例如用-9999表示缺失的整数),也可能是些极少出现的形式。

Pandas缺失值

综合考虑各种方法的优缺点,Pandas最终选择用标签方法表示缺失值,包括两种Python原有的缺失值:浮点数据类型的NaN值,以及 PythonNone对象。

  • NonePython对象类型的缺失值 Pandas可以使用的第一种缺失值标签是None,它是一个Python单体对象,由于None是一个Python对象,所以不能作为任何NumPy / Pandas数组类型的缺失值,只能用于'object'数组类型(即由 Python对象构成的数组)
np.array([1, None, 3, 4])
Out: array([1, None, 3, 4], dtype=object)
  • NaN:数值类型的缺失值 另一种缺失值的标签是NaN(全称Not a Number),是一种按照IEEE浮点数标准设计、在任何系统中都兼容的特殊浮点数:
vals2 = np.array([1, np.nan, 3, 4]) 
vals2.dtype
Out:  dtype('float64')

注意:NumPy会为这个数组选择一个原生浮点类型,这意味着和之前的 object类型数组不同,这个数组会被编译成C代码从而实现快速操作。你可以把NaN看作是一个数据类病毒——它会将与它接触过的数据同化。无论和NaN进行何种操作,最终结果都是NaN

1 + np.nan
0 * np.nan  #这两个的结果都为nan

虽然这些累计操作的结果定义是合理的(即不会抛出异常),但是并非总是有效的:

vals2 = np.array([1, np.nan, 3, 4])
vals2.sum(), vals2.min(), vals2.max()
Out:(nan, nan, nan)

NumPy也提供了一些特殊的累计函数,它们可以忽略缺失值的影响:

np.nansum(vals2), np.nanmin(vals2), np.nanmax(vals2)
Out: (8.0, 1.0, 4.0)

谨记,NaN是一种特殊的浮点数,不是整数、字符串以及其他数据类型。

  • PandasNaNNone的差异 虽然NaNNone各有各的用处,但是Pandas把它们看成是可以等价交换的:
pd.Series([1, np.nan, 2, None])
Out:
 0 1.0 
 1 NaN 
 2 2.0 
 3 NaN 
 dtype: float64

Pandas会将没有标签值的数据类型自动转换为NA。例如我们将整形数组中的一个值设置为np.nan时,这个值就会强制转换成浮点数缺失值NA,下表表示Pandas对不同类型缺失值的转换规则:

类型 缺失值转换规则 NA标签值
floating 浮点型 无变化 np.nan
object 对象类型 无变化 np.nan或None
integer 整数类型 强制转换为 float64 np.nan
boolean 布尔类型 强制转换为 object np.nan或None

发现缺失值

Pandas有两种方法可以发现缺失值:isnull()notnull(),这俩个中方法皆可用于SeriesDataFrame。每种方法都返回布尔类型的掩码数据。

data=pd.Series([1,np.nan,'hello',None])
data.isnull()
Out: 
 0 False 
 1 True 
 2 False 
 3 True 
 dtype: bool

布尔类型掩码数组可以直接作为SeriesDataFrame的索引使用。

data[data.notnull()] 
Out: 
 0 1 
 2 hello 
 dtype: object

处理缺失值

  • dropna()删除缺失值 作用在Series对象上时,它的作用和data[data.notnull()]一样,而在DataFrame上使用它们时需要设置一些参数:
df = pd.DataFrame([[1,      np.nan,  2], 
					 [2,      3,       5], 
					 [np.nan, 4,       6]])
# 如果不传任何参数时dropna会删除有缺失值的所有行
df.dropna()
Out:
     0   1  2 
 1 2.0 3.0 5
# 传入axis=1(或者axis='columns')时会删除所有包含缺失值的列
df.dropna(axis=1)
Out:
    2 
 0 2 
 1 5 
 2 6

但是这么做也会把非缺失值一并剔除,因为可能有时候只需要剔除全部是缺失值的行或列,或者绝大多数是缺失值的行或列。这些需求可以通过设置howthresh参数来满足,它们可以设置剔除行或列缺失值的数量阈值。

df[3] = np.nan
Out:
	 0   1  2  3 
0 1.0 NaN 2 NaN 
1 2.0 3.0 5 NaN 
2 NaN 4.0 6 NaN
# 删除值全部为缺失值的列
df.dropna(axis=1,how="all")  
Out
     0   1  2
 0 1.0 NaN 2 
 1 2.0 3.0 5 
 2 NaN 4.0 6
#通过 thresh 参数设置行或列中非缺失值的最小数量
df.dropna(axis='rows', thresh=3) #非缺失值至少有3个
Out:
 	0   1  2  3 
 1 2.0 3.0 5 NaN
  • fillna()填充缺失值 有时候你可能并不想移除缺失值,而是想把它们替换成有效的数值。虽然你可以通过isnull()方法建立掩码来填充缺失值,但是Pandas为此专门提供了一个fillna()方法,它将返回填充了缺失值后的数组副本。
data=pd.Series([1, np.nan, 2, None, 3],index=list('abcd')
data.fillna(0)  # 将缺失值填充为0
Out
 a 1.0 
 b 0.0 
 c 2.0 
 d 0.0 
 e 3.0 
 dtype: float64

可以用缺失值前面的有效值来从前往后填充forward-fill,也可以用缺失值后面的有效值来从后往前填充back-fill

data.fillna(method="ffill")
Out
 a 1.0 
 b 1.0 
 c 2.0 
 d 2.0 
 e 3.0 
 dtype: float64
data.fillna(method='bfill')
Out
 a 1.0 
 b 2.0 
 c 2.0 
 d 3.0 
 e 3.0 
 dtype: float64

DataFrame的操作方法与Series类似,只是在填充时需要设置坐标轴参数axis

df.fillna(method='ffill', axis=1)  # bfill同样适用
Out
 	0   1   2   3 
 0 1.0 1.0 2.0 2.0 
 1 2.0 3.0 5.0 5.0 
 2 NaN 4.0 6.0 6.0