Python Pandas 异常数据处理:NaN 检查、填充与范围裁剪方法
本文介绍了在 pandas 中处理异常数据的常用方法,涵盖了 NaN 值的查找、移除、填充以及超出合理范围值的裁剪。通过 `isna()`、`dropna()`、`fillna()` 等方法,可以有效处理缺失数据。文章展示了如何按列均值或按规律填充缺失值,以及使用 `clip()` 函数限定数值范围,以避免异常值对分析结果的干扰。配合代码和图表示例,本文为数据清洗提供了实用的 pandas 操作技
Python Pandas 异常数据处理:NaN 检查、填充与范围裁剪方法
本文介绍了在 pandas 中处理异常数据的常用方法,涵盖了 NaN 值的查找、移除、填充以及超出合理范围值的裁剪。通过 isna()
、dropna()
、fillna()
等方法,可以有效处理缺失数据。文章展示了如何按列均值或按规律填充缺失值,以及使用 clip()
函数限定数值范围,以避免异常值对分析结果的干扰。配合代码和图表示例,本文为数据清洗提供了实用的 pandas 操作技巧,使数据分析更加精确和直观。
文章目录
引入第三方库
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
一 主要功能
找到NaN数据 | 移除NaN | 填充NaN | 处理不符合范围的值 |
---|---|---|---|
pd.isna() | df.dropna() | df.fillna() | df.clip() |
pd.notna() |
二 查找NaN数据
# 创建一个包含 NaN 的 DataFrame
df = pd.DataFrame([[1, None], [np.nan, 4]])
print(df)
print(df.isna()) # 查找 NaN 值
print(~df.isna()) # 反转 NaN 查找结果,得到非 NaN 值的位置
print(df.notna()) # 另一种查找非 NaN 值的方法
三 pandas 中NaN值
# 创建包含 NaN 值的 DataFrame
df = pd.DataFrame({
"a": [1, None, 1],
"b": [np.nan, 4, 3]
})
print(df)
print("skipped NaN:\n", df.mean(axis=0)) # 默认跳过 NaN 计算均值
print("\n\nnot skipped:\n", df.mean(axis=0, skipna=False)) # 不跳过 NaN 计算均值
1 df.mean(axis=0)
df.mean(axis=0)
默认参数 skipna=True
,会跳过缺失值 NaN
。计算结果如下:
- 列
"a"
:有效值为1.0
和1.0
,平均值为(1 + 1) / 2 = 1.0
。 - 列
"b"
:有效值为4.0
和3.0
,平均值为(4 + 3) / 2 = 3.5
。
2 skipna=False
使用 skipna=False
计算平均值时,不会跳过 NaN
值。如果列中包含任何 NaN
值,则该列的平均值结果为 NaN
。
- 列
"a"
:包含NaN
,结果为NaN
。 - 列
"b"
:包含NaN
,结果也为NaN
。
划重点
在 pandas
中,计算均值时默认跳过 NaN
值,不会将 NaN
计入运算。如果 NaN
被计入,那么均值的计算就会将 NaN
视为一个数据项,从而影响数据的数量。例如,在包含 [1, NaN, 1]
的数据中,如果考虑 NaN
,均值会是 (1 + 1) / 3
而不是 (1 + 1) / 2
。
四 移除NaN
# 创建包含 NaN 值的 DataFrame
df = pd.DataFrame({
"a": [1, None, 3],
"b": [4, 5, 6]
})
print(df)
print(df.dropna(axis=0)) # 删除包含 NaN 值的行
print(df.dropna(axis=1)) # 删除包含 NaN 值的列
df.dropna(axis=0)
删除包含NaN
值的行。df.dropna(axis=1)
删除包含NaN
值的列。
五 填充NaN
1 常用的均值填充
# 使用均值填充缺失值
df = pd.DataFrame({
"a": [1, None, 3],
"b": [4, 5, 6]
})
print(df)
a_mean = df["a"].mean() # 计算列 "a" 的平均值
new_col = df["a"].fillna(a_mean) # 用平均值填充缺失值
df["a"] = new_col # 更新 DataFrame 中的 "a" 列
print(df)
计算列的平均值并用其填充缺失值,更新 DataFrame 中的 NaN。
2 按数据的规律填充
1)使用 df.fillna
填充
# 根据列 "b" 中的规律填充列 "a" 中的 NaN 值
df = pd.DataFrame({
"a": [1, None, 3, None],
"b": [4, 8, 12, 12]
})
a_nan = df["a"].isna() # 查找列 "a" 中的 NaN
a_new_value = df["b"][a_nan] / 4 # 计算填充值
new_col = df["a"].fillna(a_new_value) # 用计算的值填充缺失值
df["a"] = new_col # 更新 DataFrame 中的 "a" 列
print(df)
用列 "b"
中对应的值除以 4 的结果填充列 "a"
中的缺失值。
2)使用 df.loc 填充
# 使用 df.loc 方法按规律填充缺失值
df = pd.DataFrame({
"a": [1, None, 3, None],
"b": [4, 8, 12, 12]
})
a_nan = df["a"].isna() # 查找列 "a" 中的 NaN
df.loc[a_nan, "a"] = df["b"][a_nan] / 4 # 按规律填充缺失值
print(df)
六 不符合范围的值
# 创建包含异常值的 DataFrame
df = pd.DataFrame({
"a": [1, 1, 2, 1, 2, 40, 1, 2, 1],
})
df.plot() # 初始数据的图表
df["a"] = df["a"].clip(lower=0, upper=3) # 截取值,将所有值限制在 0 到 3 之间
df.plot() # 截取后的图表
plt.show()
由于存在异常值 40
,初始图表可能会拉高纵轴范围,使得其他数据点在视觉上变得不明显。使用 clip(lower=0, upper=3)
对列 "a"
的值进行截取,将所有低于 0
的值替换为 0
,所有高于 3
的值替换为 3
。这样一来,异常值 40
会被替换为 3
,确保数据在指定的范围内。
截取前的图表展示了原始数据的异常值。截取后,所有数据点都被限制在 [0, 3]
范围内,消除了异常值的影响,使图表更直观。
七 完整代码示例
# This is a sample Python script.
# Press ⌃R to execute it or replace it with your code.
# Press Double ⇧ to search everywhere for classes, files, tool windows, actions, and settings.
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
def print_hi(name):
# Use a breakpoint in the code line below to debug your script.
print(f'Hi, {name}') # Press ⌘F8 to toggle the breakpoint.
# 找到NaN数据
# pd.isna(), pd.notna()
# NaN的影响
# 移除NaN
# df.dropna()
# 填充NaN
# df.fillna()
# 不符合范围的值
# df.clip()
# 找到NaN数据
df = pd.DataFrame([[1, None], [np.nan, 4]])
print(df)
print(df.isna())
print(~df.isna())
print(df.notna())
# NaN的影响
# pandas 是不考虑 NaN 值的,也就是说不会把 NaN 带入运算,如果考虑 NaN 的话, mean 就会是 (1+1)/3 和 (4+4)/3 因为有三个数据。
df = pd.DataFrame({
"a": [1, None, 1],
"b": [np.nan, 4, 3]
})
print(df)
print("skipped NaN:\n", df.mean(axis=0))
print("\n\nnot skipped:\n", df.mean(axis=0, skipna=False))
# 移除NaN
df = pd.DataFrame({
"a": [1, None, 3],
"b": [4, 5, 6]
})
print(df)
print(df.dropna(axis=0))
print(df.dropna(axis=1))
print()
# 填充NaN
df = pd.DataFrame({
"a": [1, None, 3],
"b": [4, 5, 6]
})
print(df)
a_mean = df["a"].mean()
print(a_mean)
new_col = df["a"].fillna(a_mean)
print(new_col)
df["a"] = new_col
print(df)
print()
# 有规律的数据填充
# 使用fillna填充
df = pd.DataFrame({
"a": [1, None, 3, None],
"b": [4, 8, 12, 12]
})
print(df)
a_nan = df["a"].isna()
print(a_nan)
a_new_value = df["b"][a_nan] / 4
print(a_new_value)
new_col = df["a"].fillna(a_new_value)
print(new_col)
df["a"] = new_col
print(df)
print()
# 使用 loc 填充
df = pd.DataFrame({
"a": [1, None, 3, None],
"b": [4, 8, 12, 12]
})
a_nan = df["a"].isna()
print(a_nan)
print(df.loc[a_nan, "a"])
print(df["b"][a_nan] / 4)
df.loc[a_nan, "a"] = df["b"][a_nan] / 4
print(df)
# 不符合范围的值
df = pd.DataFrame({
"a": [1, 1, 2, 1, 2, 40, 1, 2, 1],
})
df.plot()
df["a"] = df["a"].clip(lower=0, upper=3)
df.plot()
plt.show()
# Press the green button in the gutter to run the script.
if __name__ == '__main__':
print_hi('异常数据处理')
# See PyCharm help at https://www.jetbrains.com/help/pycharm/
复制粘贴并覆盖到你的 main.py 中运行,运行结果如下。
Hi, 异常数据处理
0 1
0 1.0 NaN
1 NaN 4.0
0 1
0 False True
1 True False
0 1
0 True False
1 False True
0 1
0 True False
1 False True
a b
0 1.0 NaN
1 NaN 4.0
2 1.0 3.0
skipped NaN:
a 1.0
b 3.5
dtype: float64
not skipped:
a NaN
b NaN
dtype: float64
a b
0 1.0 4
1 NaN 5
2 3.0 6
a b
0 1.0 4
2 3.0 6
b
0 4
1 5
2 6
a b
0 1.0 4
1 NaN 5
2 3.0 6
2.0
0 1.0
1 2.0
2 3.0
Name: a, dtype: float64
a b
0 1.0 4
1 2.0 5
2 3.0 6
a b
0 1.0 4
1 NaN 8
2 3.0 12
3 NaN 12
0 False
1 True
2 False
3 True
Name: a, dtype: bool
1 2.0
3 3.0
Name: b, dtype: float64
0 1.0
1 2.0
2 3.0
3 3.0
Name: a, dtype: float64
a b
0 1.0 4
1 2.0 8
2 3.0 12
3 3.0 12
0 False
1 True
2 False
3 True
Name: a, dtype: bool
1 NaN
3 NaN
Name: a, dtype: float64
1 2.0
3 3.0
Name: b, dtype: float64
a b
0 1.0 4
1 2.0 8
2 3.0 12
3 3.0 12
八 源码地址
代码地址:
国内看 Gitee 之 pandas/异常数据处理.py
国外看 GitHub 之 pandas/异常数据处理.py
引用 莫烦 Python
更多推荐
所有评论(0)