Python
掌握 DataFrame Dropna:初学者指南

掌握 DataFrame Dropna:初学者指南

MoeNagy Dev

使用 df.dropna() 处理 Pandas 中的缺失数据

Pandas 中缺失数据的基础知识

理解 Pandas 中的 null 值和 NaN

在 Pandas 中,缺失数据用特殊值 NaN(Not a Number)表示。NaN 是一个浮点值,用于指示缺失有效值。这一点很重要,因为 Pandas 会将 NaN 值与常规数值或 None 值区别对待。

import pandas as pd
 
# 创建一个包含缺失值的 DataFrame
data = {'A': [1, 2, None, 4], 'B': [5, None, 7, 8]}
df = pd.DataFrame(data)
print(df)
#    A    B
# 0  1  5.0
# 1  2  NaN
# 2  None  7.0
# 3  4  8.0

在上面的示例中,DataFrame df 包含由 NoneNaN 表示的缺失值。

认识处理缺失数据的重要性

缺失数据是数据分析中的常见挑战,可能会严重影响结果的准确性和可靠性。忽视或处理不当缺失数据可能会导致偏差结论、错误预测和不可靠的见解。因此,掌握如何有效处理 Pandas 工作流中的缺失数据是非常重要的。

介绍 df.dropna()

什么是 df.dropna()?

Pandas 中的 df.dropna() 方法是一个强大的工具,用于从 DataFrame 中删除包含缺失数据的行或列。该方法允许您自定义缺失数据处理的行为,使其成为一个灵活多样的解决方案,用于处理不完整的数据集。

何时使用 df.dropna()

通常情况下,df.dropna() 方法用于...当您想要从DataFrame中删除包含缺失数据的行或列时,这可能会很有用。这种情况可能发生在以下场景中:

  1. 您需要准备一个干净的数据集进行进一步分析或建模。
  2. 缺失数据的存在可能会对机器学习模型的性能产生负面影响。
  3. 您想要在不受缺失值影响的情况下可视化您的数据。
  4. 您需要满足要求完整数据集的特定要求或约束。

删除包含缺失数据的行

删除包含任何NaN值的行

删除包含缺失数据的行最简单的方法是使用df.dropna()方法,不需要任何参数:

import pandas as pd
 
# 创建一个包含缺失值的DataFrame
data = {'A': [1, 2, None, 4], 'B': [5, None, 7, 8]}
df = pd.DataFrame(data)
 
# 删除包含任何NaN值的行
df_dropped = df.dropna()
print(df_dropped)
#    A    B
# 0  1  5.0
# 3  4  8.0

在这个例子中,df.dropna()方法删除了包含至少一个NaN值的行,得到一个新的DataFrame df_dropped,只包含完整的行。

删除特定列包含NaN值的行

您还可以指定在删除行时要考虑哪些列。这是通过将subset参数传递给df.dropna()来实现的:

# 删除'A'列包含NaN值的行
df_dropped_A = df.dropna(subset=['A'])
print(df_dropped_A)
#    A    B
# 0  1  5.0
# 1  2  NaN
# 3  4  8.0
 
# 删除'A'和'B'列都包含NaN值的行
df_dropped_AB = df.dropna(subset=['A', 'B'])
print(df_dropped_AB)
#    A    B
# 0  1  5.0
# 3  4  8.0

在第一个例子中,df.dropna(subset=['A'])删除了'A'列包含NaN值的行。在第二个例子中,df.dropna(subset=['A', 'B'])删除了'A'和'B'列都包含NaN值的行。

自定义df.dropna()的行为

df.dropna()方法提供了几个额外的参数来自定义其行为。这是中文翻译:

  • how: 指定删除行的条件。可以是 'any'(默认)删除任何包含 NaN 值的行, 或 'all' 只删除所有值都是 NaN 的行。
  • thresh: 指定保留行所需的最小非 NaN 值数量。
  • subset: 指定在删除行时要考虑的列。
# 删除所有值都是 NaN 的行
df_dropped_all = df.dropna(how='all')
print(df_dropped_all)
#    A    B
# 0  1  5.0
# 1  2  NaN
# 3  4  8.0
 
# 删除少于 2 个非 NaN 值的行
df_dropped_thresh = df.dropna(thresh=2)
print(df_dropped_thresh)
#    A    B
# 0  1  5.0
# 3  4  8.0

在第一个例子中, df.dropna(how='all') 删除所有值都是 NaN 的行。在第二个例子中, df.dropna(thresh=2) 删除少于 2 个非 NaN 值的行。

删除包含缺失数据的列

删除任何包含 NaN 值的列

要删除任何包含 NaN 值的列, 可以在 df.dropna() 方法中使用 axis=1 参数:

# 删除任何包含 NaN 值的列
df_dropped_cols = df.dropna(axis=1)
print(df_dropped_cols)
#    A
# 0  1
# 1  2
# 2  None
# 3  4

在这个例子中, df.dropna(axis=1) 方法删除了包含 NaN 值的 'B' 列, 只留下 'A' 列在结果 DataFrame df_dropped_cols 中。

删除超过一定阈值 NaN 值的列

你也可以指定一个阈值, 超过这个阈值的列将被删除。这是通过使用 thresh 参数来实现的:

# 删除包含超过 1 个 NaN 值的列
df_dropped_threshold = df.dropna(axis=1, thresh=3)
print(df_dropped_threshold)
#    A    B
# 0  1  5.0
# 1  2  NaN
# 2  None  7.0
# 3  4  8.0

在这个例子中, df.dropna(axis=1, thresh=3) 删除了包含超过 1 个 NaN 值的列(因为 DataFrame 有 4 行), 保留了 'A' 和 'B' 列在结果 DataFrame df_dropped_threshold 中。

处理包含混合数据类型的列当使用包含混合数据类型(包括 NaN 值)的列时, df.dropna() 方法的行为可能会有所不同。这是因为 Pandas 对不同数据类型中的缺失值进行了不同的处理。

# 创建一个包含混合数据类型的 DataFrame
data = {'A': [1, 2, None, 4], 'B': [5, None, '7', 8]}
df = pd.DataFrame(data)
print(df)
#    A     B
# 0  1   5.0
# 1  2   NaN
# 2  None  7
# 3  4   8.0
 
# 删除包含任何 NaN 值的列
df_dropped_mixed = df.dropna(axis=1)
print(df_dropped_mixed)
#    A
# 0  1
# 1  2
# 2  None
# 3  4

在这个例子中, 'B' 列包含数字和字符串值, 其中包括 NaN。当使用 df.dropna(axis=1) 时, 'B' 列被删除, 因为它包含 NaN 值, 即使字符串值 '7' 不被 Pandas 视为缺失值。

为了处理包含混合数据类型的列, 您可能需要转换数据类型或使用其他方法来处理缺失数据, 如插补或数据清洗技术。

使用 df.dropna() 的高级技术

将 df.dropna() 与其他 Pandas 操作结合使用

df.dropna() 方法可以与其他 Pandas 操作结合使用, 以创建更复杂的数据清洗和预处理工作流。例如, 您可以将 df.dropna()df.fillna() 结合使用, 以更全面地处理缺失数据。

# 结合使用 df.dropna() 和 df.fillna()
data = {'A': [1, 2, None, 4], 'B': [5, None, 7, 8]}
df = pd.DataFrame(data)
 
# 用 0 填充缺失值, 然后删除包含任何 NaN 的行
df_cleaned = df.fillna(0).dropna()
print(df_cleaned)
#    A  B
# 0  1  5
# 3  4  8

在这个例子中, df.fillna(0) 方法用 0 填充缺失值, 然后 df.dropna() 方法删除任何剩余的包含 NaN 值的行。

使用 .copy() 保留原始 DataFrame

使用 df.dropna() 时, 需要注意该方法会修改原始 DataFrame。如果您想保留原始 DataFrame, 可以使用 .copy() 方法创建一个副本。如果您想要保留原始的 DataFrame,您可以使用 .copy() 方法创建一个新的 DataFrame,然后再应用 df.dropna()

# 保留原始 DataFrame
data = {'A': [1, 2, None, 4], 'B': [5, None, 7, 8]}
df = pd.DataFrame(data)
 
# 创建 DataFrame 的副本,然后删除缺失值
df_copy = df.copy()
df_dropped = df_copy.dropna()
 
print("原始 DataFrame:")
print(df)
print("\n复制并删除缺失值后的 DataFrame:")
print(df_dropped)

在这个例子中,df_copy = df.copy() 创建了一个新的 DataFrame df_copy,它是原始 df 的副本。然后在 df_copy 上执行 df.dropna() 操作,保留了原始的 df DataFrame。

处理时间序列数据中的缺失值

在处理时间序列数据时,处理缺失值尤为重要,因为数据中的空白可能会严重影响您的分析和预测。df.dropna() 方法可用于删除时间序列数据中具有缺失值的行,但您可能还需要考虑其他方法,如插值或向前/向后填充,这取决于您的具体使用情况。

# 处理时间序列数据中的缺失值示例
import pandas as pd
 
# 创建一个包含缺失值的时间序列 DataFrame
dates = pd.date_range(start='2022-01-01', end='2022-01-10', freq='D')
data = {'A': [1, 2, None, 4, 5, None, 7, 8, 9, 10]}
df_ts = pd.DataFrame(data, index=dates)
 
# 删除包含任何 NaN 值的行
df_ts_dropped = df_ts.dropna()
print(df_ts_dropped)
#            A
# 2022-01-01  1
# 2022-01-02  2
# 2022-01-04  4
# 2022-01-05  5
# 2022-01-07  7
# 2022-01-08  8
# 2022-01-09  9
# 2022-01-10 10

在这个例子中,df_ts DataFrame 表示一个包含缺失值的时间序列。使用 df.dropna() 方法删除包含 NaN 值的行,得到 df_ts_dropped DataFrame。

最佳实践和注意事项

评估删除数据的影响

使用 df.dropna() 时,重要的是要考虑删除缺失值会对您的分析产生什么影响。您可能需要检查删除后数据的分布和统计特征是否发生变化。如果删除太多数据,可能会导致分析结果不准确或缺乏代表性。在这种情况下,您可能需要考虑使用其他方法,如插值或前向/后向填充,来处理缺失值。

条件语句

Python 中的条件语句允许您根据特定条件执行不同的代码块。最常见的条件语句是 if-elif-else 语句。

age = 25
if age < 18:
    print("你是未成年人。")
elif age >= 18 and age < 65:
    print("你是成年人。")
else:
    print("你是老年人。")

在这个示例中,程序检查 age 变量的值,并根据年龄范围打印相应的消息。

循环

Python 中的循环允许您重复执行一个代码块。最常见的两种循环类型是 for 循环和 while 循环。

for 循环

for 循环用于遍历一个序列,如列表、元组或字符串。

fruits = ["苹果", "香蕉", "樱桃"]
for fruit in fruits:
    print(fruit)

这段代码将输出:

苹果
香蕉
樱桃

while 循环

while 循环用于只要某个条件为真就执行一个代码块。

count = 0
while count < 5:
    print(count)
    count += 1

这段代码将输出:

0
1
2
3
4

函数

Python 中的函数是可重复使用的代码块,用于执行特定的任务。它们可以接受参数并返回值。

def greet(name):
    print(f"你好, {name}!")
 
greet("Alice")
greet("Bob")

这段代码将输出:

你好, Alice!
你好, Bob!

您还可以定义带有默认参数和可变长度参数的函数。

def calculate_area(length, width, height=None):
    if height is None:
        return length * width
    else:
        return length * width * height
 
print(calculate_area(5, 10))       # 输出: 50
print(calculate_area(2, 3, 4))     # 输出: 24

模块和包

Python 的标准库提供了广泛的内置模块,您可以在程序中使用它们。您也可以创建自己的模块和包来组织您的代码。

import math
print(math.pi)  # 输出: 3.141592653589793

在这个例子中,我们导入了 math 模块,并使用了它的 pi 常量。

您也可以从一个模块中导入特定的函数或属性:

from math import sqrt, pi
print(sqrt(16))  # 输出: 4.0
print(pi)       # 输出: 3.141592653589793

文件 I/O

Python 提供了内置函数来读取和写入文件。

# 写入文件
with open("example.txt", "w") as file:
    file.write("This is a sample text file.")
 
# 读取文件
with open("example.txt", "r") as file:
    content = file.read()
    print(content)  # 输出: This is a sample text file.

with 语句确保在操作完成后文件被正确关闭。

异常处理

Python 的异常处理机制允许您处理代码中的错误和意外情况。

try:
    result = 10 / 0
except ZeroDivisionError:
    print("Error: Division by zero")
else:
    print(f"Result: {result}")
finally:
    print("This block will always execute.")

这段代码将输出:

Error: Division by zero
This block will always execute.

面向对象编程 (OOP)

Python 支持面向对象编程,允许您创建自定义类和对象。

class Car:
    def __init__(self, make, model, year):
        self.make = make
        self.model = model
        self.year = year
 
    def start(self):
        print(f"The {self.year} {self.make} {self.model} has started.")
 
my_car = Car("Toyota", "Corolla", 2020)
my_car.start()  # 输出: The 2020 Toyota Corolla has started.

在这个例子中,我们定义了一个 Car 类,它有一个 __init__ 方法来初始化对象的属性,以及一个 start 方法来模拟启动车辆。## 结论

在本教程中,您已经学习了各种 Python 概念,包括条件语句、循环、函数、模块和包、文件 I/O、异常处理和面向对象编程。这些基本技能将帮助您构建更复杂和强大的 Python 应用程序。请记得练习和实验提供的代码示例,以巩固对这些主题的理解。

MoeNagy Dev.