一个典型的数据处理流程包括加载数据集,进行初步检查,并使用Pandas处理缺失值和重复项等常见问题。我们假定您已按照第1章所述,设置好基本的Python环境并安装了Pandas。设置与加载数据首先,确保您已导入Pandas。惯用的别名是pd:import pandas as pd import numpy as np # 通常与Pandas一同使用很有用 print(f"Pandas version: {pd.__version__}") print(f"NumPy version: {np.__version__}")对于本次练习,假设我们有一个名为orders.csv的数据集,包含简化的客户订单信息。我们将其加载到Pandas DataFrame中。如果您没有这个确切的文件,可以创建一个类似的文件,或者根据您已有的CSV文件修改代码。# 假设'orders.csv'与脚本在同一目录下,或提供完整路径 try: df_orders = pd.read_csv('orders.csv') print("数据集加载成功。") except FileNotFoundError: print("错误:未找到'orders.csv'。请确保文件存在或更新路径。") # 作为备用方案,创建一个示例DataFrame用于演示 data = { 'OrderID': [1001, 1002, 1003, 1004, 1005, 1006, 1007, 1003, 1008, 1009, 1010], 'CustomerID': ['CUST-A', 'CUST-B', 'CUST-A', 'CUST-C', 'CUST-B', 'CUST-D', 'CUST-E', 'CUST-A', 'CUST-F', np.nan, 'CUST-G'], 'Product': ['WidgetA', 'WidgetB', 'WidgetA', 'Gadget', 'WidgetB', 'WidgetA', None, 'WidgetA', 'Gadget', 'WidgetC', 'WidgetA'], 'Quantity': [2, 1, 1, 3, 2, 1, 1, 1, 2, 1, 3], 'Price': [10.0, 25.5, 10.0, 55.0, 25.5, 10.0, 10.0, 10.0, 55.0, 30.0, np.nan] } df_orders = pd.DataFrame(data) print("已创建示例DataFrame用于演示。") 数据初步检查现在数据已加载到df_orders中,我们来执行前面讨论的初步检查。形状: 数据集有多少行和多少列?print(f"数据集维度(行, 列):{df_orders.shape}")头部和尾部: 查看前几行和后几行,了解数据值和结构的大致情况。print("前5行:") print(df_orders.head()) print("\n后5行:") print(df_orders.tail())数据类型和非空计数: 使用.info()来获取一份简明的概况,包括每列的数据类型和非空值计数。print("\nDataFrame信息:") df_orders.info()请注意Dtype列(数据类型是否合适,例如数值列是int64或float64,分类列是object或category?)以及Non-Null Count(它是否与.shape的总行数匹配?如果不匹配,则存在缺失值)。识别和处理缺失数据.info()的输出可能已经指出了含有缺失值的列。现在我们来获取精确的计数。缺失值计数: 使用.isnull().sum()统计每列中的$NaN$或None值。print("\n每列的缺失值:") print(df_orders.isnull().sum())这确认了哪些列需要关注(在我们的样本中是CustomerID、Product、Price),以及每列有多少缺失值。处理缺失数据的策略: 如前所述,我们可以删除行/列或填充值。最佳策略取决于具体情况和缺失数据的量。删除: 如果只有极少数行的值缺失,并且删除它们不会显著影响数据,那么删除可能是可接受的。我们来看看如何删除含有任意缺失值的行:# 创建副本,避免在检查时直接修改原始DataFrame df_dropped = df_orders.dropna() print(f"\n删除含有任意NaN的行后的形状:{df_dropped.shape}") # 注意:如果NaN普遍存在,这可能会删除过多的数据。填充(数值型): 对于Price列(数值型),我们可以用均值或中位数进行填充。如果怀疑存在异常值,通常更倾向于使用中位数。median_price = df_orders['Price'].median() print(f"\n用于填充的中位数价格:{median_price}") # 使用中位数填充缺失价格 - 现在直接在原始df上操作 df_orders['Price'].fillna(median_price, inplace=True) # 验证填充结果 print("\n价格填充后的缺失值:") print(df_orders.isnull().sum())注意:inplace=True参数会直接修改DataFrame。使用时请谨慎;通常更安全的方法是将其结果赋值回去,例如df_orders['Price'] = df_orders['Price'].fillna(median_price)。填充(分类型): 对于CustomerID和Product(分类型),我们可以使用众数(最常出现的值)或引入一个新类别,例如'Unknown'。如果不存在主要类别,使用众数可能不太合适。我们将对Product使用'Unknown',并演示对CustomerID的众数填充(尽管此处使用'Unknown'也可能有效)。# 用'Unknown'填充Product列 df_orders['Product'].fillna('Unknown', inplace=True) # 用众数填充CustomerID列 mode_customer = df_orders['CustomerID'].mode()[0] # 如果有多个众数,.mode()可能会返回多个值 print(f"\n用于填充的CustomerID众数:{mode_customer}") df_orders['CustomerID'].fillna(mode_customer, inplace=True) # 最后检查缺失值 print("\n所有填充后的缺失值:") print(df_orders.isnull().sum())检测和处理重复记录重复行可能使分析结果出现偏差。我们来检查并处理它们。识别重复项: 统计完全重复的行数。duplicate_count = df_orders.duplicated().sum() print(f"\n找到的重复行数:{duplicate_count}")检查重复项(可选): 如果发现重复项,您可能希望查看它们。if duplicate_count > 0: print("\n重复行:") print(df_orders[df_orders.duplicated(keep=False)]) # 显示所有出现项注意:keep=False会将所有重复项标记为True,使它们易于筛选和查看。删除重复项: 使用.drop_duplicates()。keep参数决定保留哪个重复项('first'是默认值,'last'或False表示删除所有)。我们将保留第一次出现的记录。# 保留第一次出现的记录,删除后续重复项 original_rows = df_orders.shape[0] df_orders.drop_duplicates(inplace=True) print(f"\n删除重复项后的形状:{df_orders.shape}") print(f"已删除的行数:{original_rows - df_orders.shape[0]}") # 验证重复项已删除 print(f"\n删除后重复行的数量:{df_orders.duplicated().sum()}")最后检查在加载、检查、处理缺失值和删除重复项之后,我们最后再查看一下清理后的数据信息。print("\n初步清理后的最终DataFrame信息:") df_orders.info() print("\n清理后数据的前5行:") print(df_orders.head())现在,数据应该具有统一的数据类型(尽管您稍后可能会进行调整,例如将object转换为category),没有缺失值,也没有重复行。它现在处于更适合后续章节中涉及的单变量和双变量分析的状态。这个动手练习展示了准备几乎任何数据集进行分析的关键第一步。请记住,具体的填充策略可能会根据更深入的领域知识或分析目的而有所变化。