掌握 Pandas read_excel:Python 数据分析必备技巧 – wiki基地


掌握 Pandas read_excel:Python 数据分析必备技巧

在数据驱动的时代,数据分析已成为各行各业不可或缺的核心能力。而 Python 凭借其强大的库生态,特别是 Pandas 库,已然成为数据分析领域的首选语言。在日常工作中,我们面对的数据源多种多样,其中,Microsoft Excel 文件(.xls 或 .xlsx)无疑是最常见、最广泛使用的数据存储和交换格式之一。无论是业务报表、实验数据、调查问卷还是简单的列表,Excel 的普及性使其成为数据分析流程中绕不开的一环。

幸运的是,Pandas 库提供了一个功能极其强大且灵活的函数——pandas.read_excel(),它就像一座桥梁,能够轻松地将 Excel 文件中的数据读取并加载到 Pandas 的核心数据结构 DataFrame 中,为后续的数据清洗、处理、分析和可视化奠定坚实的基础。掌握 read_excel() 的使用,不仅仅是学会一个函数,更是打通了 Python 数据分析与海量 Excel 数据之间的通道。

本文将深入探讨 pandas.read_excel() 的方方面面,从基础用法到高级参数,再到实际应用场景和性能优化,旨在帮助读者全面掌握这一 Python 数据分析的必备技巧,无论您是数据分析新手还是希望提升效率的资深从业者,都能从中获益。

一、read_excel() 的基础用法:开启 Excel 数据之门

read_excel() 最核心的功能是将 Excel 文件读入为一个或多个 Pandas DataFrame。其最简单的形式只需要一个参数:Excel 文件的路径。

假设我们有一个名为 sales_data.xlsx 的 Excel 文件,其内容大致如下(位于默认的 “Sheet1” 工作表):

Date Region Product Quantity Revenue
0 2023-01-15 North Laptop 10 12000
1 2023-01-16 South Keyboard 50 2500
2 2023-01-17 East Monitor 20 6000
3 2023-01-18 West Laptop 8 9600
4 2023-01-19 North Mouse 100 1500

使用 Pandas 读取这个文件的基础代码非常简洁:

“`python
import pandas as pd

指定 Excel 文件路径

file_path = ‘sales_data.xlsx’

使用 read_excel 读取数据

try:
df = pd.read_excel(file_path)
# 打印 DataFrame 的前几行,验证读取结果
print(df.head())
# 查看 DataFrame 的基本信息
print(df.info())
except FileNotFoundError:
print(f”错误:文件 ‘{file_path}’ 未找到。请检查路径是否正确。”)
except Exception as e:
print(f”读取 Excel 文件时发生错误:{e}”)
“`

执行上述代码,Pandas 会自动:

  1. 找到名为 sales_data.xlsx 的文件。
  2. 默认读取第一个工作表(Sheet1)。
  3. 将工作表的第一行识别为列标题(Header)。
  4. 将剩余的数据加载到一个 DataFrame 对象 df 中。
  5. 自动推断每一列的数据类型(如日期、字符串、整数、浮点数)。

输出的 df.head() 将显示文件中的前五行数据,而 df.info() 则会展示 DataFrame 的结构信息,包括行数、列数、列名、非空值数量以及每列的数据类型(Dtype)。

这只是 read_excel() 功能的冰山一角。现实中的 Excel 文件往往更加复杂,可能包含多个工作表、不规范的表头、需要跳过的行、特定的数据格式等。为了应对这些情况,read_excel() 提供了丰富的参数选项。

二、深入核心参数:精细控制读取过程

read_excel() 函数拥有众多参数,允许我们对读取过程进行精细化的控制。掌握这些参数是高效、准确地处理各种 Excel 文件的关键。以下是一些最常用且最重要的参数详解:

  1. io (Input/Output):

    • 这是第一个位置参数,用于指定输入源。
    • 可以是字符串:表示本地文件路径(如 'data.xlsx')或 URL(如 'http://example.com/data.xlsx')。
    • 可以是文件类对象:如通过 open() 打开的文件对象,或者 BytesIO 等内存中的二进制流。这在处理网络请求或内存中的数据时非常有用。
    • 还可以是 ExcelFile 对象:pd.ExcelFile('data.xlsx'),这在需要多次从同一个文件读取不同工作表时可以提高效率,因为它只打开文件一次。
  2. sheet_name:

    • 控制读取哪个或哪些工作表。这是处理多工作表文件的核心参数。
    • 默认值 0: 读取第一个工作表(索引从 0 开始)。
    • 整数: 读取指定索引的工作表(如 1 读取第二个工作表)。
    • 字符串: 读取指定名称的工作表(如 'Sales Data''Sheet2')。
    • 列表: 读取列表中指定的多个工作表,可以是索引和名称的混合(如 [0, 'Summary', 2])。此时,read_excel 返回一个字典,其中键是工作表索引或名称,值是对应的 DataFrame。
    • None: 读取文件中的所有工作表。同样返回一个以工作表名称为键、DataFrame 为值的字典。

    “`python

    读取名为 “Q1 Sales” 的工作表

    df_q1 = pd.read_excel(file_path, sheet_name=’Q1 Sales’)

    读取第一个和第三个工作表

    dfs_dict = pd.read_excel(file_path, sheet_name=[0, 2])
    df_sheet1 = dfs_dict[0]
    df_sheet3 = dfs_dict[2]

    读取所有工作表

    all_sheets_dict = pd.read_excel(file_path, sheet_name=None)
    for sheet_name, df_sheet in all_sheets_dict.items():
    print(f”\n— 工作表: {sheet_name} —“)
    print(df_sheet.head())
    “`

  3. header:

    • 指定哪一行(或多行)用作列名。索引从 0 开始。
    • 默认值 0: 将第一行(索引为 0)作为列名。
    • 整数 n: 将第 n+1 行(索引为 n)作为列名,该行之前的数据将被忽略。
    • 列表 [n, m, ...]: 指定多行作为多级索引(MultiIndex)的列名。例如 [0, 1] 表示前两行共同构成列名。
    • None: 表示文件中没有列名行。Pandas 会自动生成从 0 开始的整数列名(0, 1, 2, …)。

    “`python

    假设数据从第 3 行开始,且第 3 行为列名

    df_header_row3 = pd.read_excel(file_path, sheet_name=’Data’, header=2)

    假设前两行是合并的复杂表头

    df_multi_header = pd.read_excel(file_path, sheet_name=’ComplexReport’, header=[0, 1])

    文件没有表头行

    df_no_header = pd.read_excel(file_path, sheet_name=’RawLog’, header=None)
    “`

  4. names:

    • header=None 配合使用,提供自定义的列名列表。列表长度应与数据列数匹配。
    • 如果提供了 names,则 header 参数通常设为 None 或指向实际数据开始行的前一行(如果想跳过原有的“假”表头)。

    “`python

    文件无表头,手动指定列名

    custom_names = [‘Timestamp’, ‘SensorID’, ‘Value’, ‘Unit’]
    df_custom_names = pd.read_excel(file_path, sheet_name=’SensorData’, header=None, names=custom_names)
    “`

  5. index_col:

    • 指定哪一列(或多列)用作 DataFrame 的行索引(Index)。
    • 默认值 None: 不使用任何列作为索引,Pandas 会自动生成从 0 开始的整数索引。
    • 整数 n: 使用第 n+1 列(索引为 n)作为行索引。
    • 字符串: 使用指定名称的列作为行索引。
    • 列表 [n, m, ...]['col1', 'col2', ...]: 使用多列创建多级索引(MultiIndex)。

    “`python

    使用第一列 (‘ID’) 作为行索引

    df_indexed = pd.read_excel(file_path, sheet_name=’Employees’, index_col=0)

    或者按列名指定

    df_indexed_name = pd.read_excel(file_path, sheet_name=’Employees’, index_col=’EmployeeID’)

    使用 ‘Department’ 和 ‘EmployeeID’ 创建多级索引

    df_multi_index = pd.read_excel(file_path, sheet_name=’Employees’, index_col=[‘Department’, ‘EmployeeID’])
    “`

  6. usecols:

    • 选择只读取 Excel 文件中的特定列,这对于处理宽表格或节省内存非常有用。
    • 整数列表 [n, m, ...]: 读取指定索引的列(如 [0, 2, 4] 读取第 1、3、5 列)。
    • 字符串列表 ['col1', 'col3', ...]: 读取指定名称的列。前提是 header 参数能正确识别列名。
    • Excel 列字母范围字符串: 如 'A:C,E,G:H',表示读取 A 到 C 列、E 列、G 到 H 列。
    • 可调用对象(函数): 传入一个函数,该函数接受列名作为参数,返回 True 则读取该列,返回 False 则跳过。

    “`python

    只读取 ‘Date’, ‘Product’, ‘Revenue’ 列

    df_subset_cols = pd.read_excel(file_path, usecols=[‘Date’, ‘Product’, ‘Revenue’])

    只读取第 1, 3, 5 列 (索引 0, 2, 4)

    df_subset_idx = pd.read_excel(file_path, usecols=[0, 2, 4])

    使用 Excel 范围表示法

    df_subset_range = pd.read_excel(file_path, usecols=’A,C:D’) # 读取 A 列,C 列和 D 列

    使用函数筛选包含 ‘ID’ 的列名

    def filter_cols(col_name):
    return ‘ID’ in col_name.upper()
    df_subset_func = pd.read_excel(file_path, usecols=filter_cols)
    “`

  7. dtype:

    • 指定列的数据类型。这对于确保数据正确性和防止 Pandas 自动类型推断错误(尤其对于包含数字和文本混合的列)至关重要。
    • 传入一个字典,键是列名或列索引,值是期望的数据类型(如 str, int, float, np.int64, np.float32, object)。
    • 可以设置为 'object'str 来强制将某列读取为字符串,避免数字(如 ID、邮编)被错误地解析为数值类型。

    “`python

    强制 ‘EmployeeID’ 和 ‘ZipCode’ 读取为字符串

    dtypes_spec = {‘EmployeeID’: str, ‘ZipCode’: str, ‘Salary’: float}
    df_typed = pd.read_excel(file_path, sheet_name=’Employees’, dtype=dtypes_spec)

    将所有列读取为字符串 (object)

    df_all_str = pd.read_excel(file_path, dtype=str) # pandas >= 1.0.0

    df_all_obj = pd.read_excel(file_path, dtype=object) # 兼容旧版本
    “`

  8. engine:

    • 指定用于解析 Excel 文件的底层库。
    • 默认: Pandas 会根据文件扩展名自动选择。.xlsx 使用 openpyxl.xls 使用 xlrd.ods 使用 odfpy
    • 'openpyxl': 推荐用于 .xlsx 文件。需要安装 openpyxl 库 (pip install openpyxl)。
    • 'xlrd': 主要用于旧版 .xls 文件。注意:较新版本的 xlrd (>=2.0.0) 不再支持 .xlsx 文件。如果需要用 xlrd 读取 .xlsx,需要安装旧版本 (pip install xlrd==1.2.0),但这通常不推荐。
    • 'odfpy': 用于 OpenDocument Spreadsheet 文件 (.ods)。需要安装 odfpy 库 (pip install odfpy)。
    • 在某些情况下(如特定 Excel 功能或性能问题),可能需要显式指定引擎。
  9. skiprows:

    • 跳过文件顶部的指定行数。
    • 整数 n: 跳过开头的 n 行。
    • 列表 [n, m, ...]: 跳过指定索引的行(索引从 0 开始)。
    • 可调用对象(函数): 传入一个函数,该函数接受行索引作为参数,返回 True 则跳过该行。

    “`python

    跳过文件开头的 5 行说明文字

    df_skip_header_notes = pd.read_excel(file_path, skiprows=5)

    跳过第 1 行和第 3 行 (索引 0 和 2)

    df_skip_specific = pd.read_excel(file_path, skiprows=[0, 2])
    “`

  10. nrows:

    • 只读取文件的前 n 行数据(不包括表头和跳过的行)。这对于预览大型文件或进行快速测试非常有用。

    “`python

    只读取数据部分的前 100 行

    df_preview = pd.read_excel(file_path, nrows=100)
    “`

  11. na_values:

    • 指定哪些值在读取时应被视为空值(NaN)。
    • 单个值: 如 na_values='--'
    • 列表: 如 na_values=['N/A', 'Not Available', -999]
    • 字典: 为特定列指定不同的 NA 标记符,键是列名,值是该列的 NA 值列表。

    “`python

    将 ‘N/A’, ‘null’, 和 ‘-‘ 视为空值

    df_custom_na = pd.read_excel(file_path, na_values=[‘N/A’, ‘null’, ‘-‘])

    ‘Score’ 列的 -1 和 ‘Comment’ 列的 ‘No Response’ 视为空值

    na_dict = {‘Score’: [-1], ‘Comment’: [‘No Response’]}
    df_col_specific_na = pd.read_excel(file_path, na_values=na_dict)
    “`

  12. parse_dates:

    • 尝试将指定的列解析为日期时间对象 (datetime)。这是处理时间序列数据的关键一步。
    • True: 尝试将索引列解析为日期。
    • 列表 [col_idx]['col_name']: 解析指定的单列或多列。
    • 列表的列表 [[col1, col2], ...]: 将多个列组合起来解析为一个日期时间列(例如,年、月、日分开在不同列)。
    • 字典 {'new_col': [col1, col2]}: 将多个列组合解析,并将结果存储在名为 new_col 的新列中。

    “`python

    解析 ‘Order Date’ 和 ‘Ship Date’ 列

    df_dates = pd.read_excel(file_path, parse_dates=[‘Order Date’, ‘Ship Date’])

    假设 ‘Year’, ‘Month’, ‘Day’ 是三列,合并解析为 ‘FullDate’

    df_combined_date = pd.read_excel(file_path, parse_dates={‘FullDate’: [‘Year’, ‘Month’, ‘Day’]})

    假设日期和时间在不同列 ‘Date’, ‘Time’,合并解析为 ‘DateTime’

    df_datetime = pd.read_excel(file_path, parse_dates=[[‘Date’, ‘Time’]]) # 结果在原’Date’列位置或新列

    更明确的写法 (需要Pandas较新版本)

    df_datetime = pd.read_excel(file_path, parse_dates={‘DateTime’: [‘Date’, ‘Time’]}, keep_date_col=True) # 保留原列

    “`

  13. skipfooter:

    • 跳过文件末尾的指定行数。常用于忽略文件底部的总计行或注释。

    “`python

    忽略文件末尾的 3 行总结信息

    df_skip_footer = pd.read_excel(file_path, skipfooter=3)
    “`

  14. comment:

    • 指定一个字符,如果某行以该字符开头,则该行(及其后的所有内容)被视为注释,不会被解析。

    “`python

    跳过以 ‘#’ 开头的注释行

    df_no_comments = pd.read_excel(file_path, comment=’#’)
    “`

  15. thousands:

    • 指定千位分隔符(如 ,),以便在读取包含分隔符的数值列时能正确解析为数字。

    “`python

    解析带逗号千位分隔符的 ‘Revenue’ 列

    注意:通常与 dtype 结合使用效果更佳或 Pandas 会自动尝试

    df_thousands = pd.read_excel(file_path, thousands=’,’)
    “`

三、实战应用场景:read_excel() 的威力展现

掌握了众多参数后,我们来看看如何在实际场景中组合运用它们来解决复杂问题:

场景一:读取包含多个数据表和说明信息的工作簿

假设一个 Excel 文件 report.xlsx 包含:
* “Introduction” 工作表:仅含报告说明文字。
* “Sales_Data” 工作表:销售数据,但前 3 行是标题和空行,数据从第 4 行开始,且需要将 ‘CustomerID’ 列作为索引,并只关注 ‘Date’, ‘CustomerID’, ‘Amount’ 列。
* “Inventory” 工作表:库存数据,表头在第 2 行,且需要将 ‘ProductID’ 列强制读取为字符串。

“`python
import pandas as pd

file = ‘report.xlsx’

使用 ExcelFile 提高效率

try:
with pd.ExcelFile(file) as xls:
# 读取 Sales_Data 工作表
df_sales = pd.read_excel(xls,
sheet_name=’Sales_Data’,
header=3, # 数据从第4行开始,所以表头在索引3
index_col=’CustomerID’,
usecols=[‘Date’, ‘CustomerID’, ‘Amount’],
parse_dates=[‘Date’])

    # 读取 Inventory 工作表
    df_inventory = pd.read_excel(xls,
                                 sheet_name='Inventory',
                                 header=1,  # 表头在第2行,索引1
                                 dtype={'ProductID': str})

print("--- Sales Data ---")
print(df_sales.head())
print("\n--- Inventory Data ---")
print(df_inventory.head())

except FileNotFoundError:
print(f”错误:文件 ‘{file}’ 未找到。”)
except KeyError as e:
print(f”错误:工作表名称 {e} 不存在。”)
except Exception as e:
print(f”读取 Excel 文件时发生错误:{e}”)

“`

场景二:处理格式不统一、含有合并单元格表头的报表

有时会遇到跨越多行的复杂表头,甚至包含合并单元格。read_excel 对合并单元格有一定的处理能力,但复杂情况可能仍需后续处理。

假设表头跨越第 1、2 行:

| Sales | Profit |
| Region A | Region B | Region A | Region B |
Product |----------|----------|----------|----------|
Laptop | 100 | 120 | 20 | 25 |
Keyboard | 300 | 280 | 30 | 28 |

“`python

读取带有 MultiIndex 列名的表

df_multi = pd.read_excel(‘complex_report.xlsx’, header=[0, 1], index_col=0)
print(df_multi)
print(“\nColumn Index:”)
print(df_multi.columns)
“`

此时 df_multi.columns 会是一个 MultiIndex 对象。Pandas 会尝试填充合并单元格的值到所有相关的底层单元格。

场景三:读取大型 Excel 文件,关注性能和内存

对于非常大的 Excel 文件,一次性加载到内存可能导致程序崩溃。虽然 read_excel 不像 read_csv 那样有 chunksize 参数进行分块读取,但我们可以采取以下策略:

  • 使用 nrows: 只读取文件开头的一部分进行探索或测试。
  • 使用 usecols: 只加载需要的列,显著减少内存占用。
  • 指定 dtype: 特别是将可以表示为更小数值类型(如 float32 代替 float64, int32 代替 int64)或将数字 ID 读取为 object,可以节省内存。
  • 分工作表读取: 如果数据分散在多个工作表中,一次只读取和处理一个工作表。
  • 考虑替代格式: 如果性能是首要瓶颈,且不需要 Excel 的特定格式(如图表、公式),将数据转换为更高效的格式(如 CSV, Parquet, Feather)可能是更好的长期方案。

“`python

读取大文件时优化

large_file = ‘very_large_data.xlsx’
try:
df_large_optimized = pd.read_excel(
large_file,
sheet_name=’TimeSeriesData’,
usecols=[‘Timestamp’, ‘SensorA’, ‘SensorB’],
parse_dates=[‘Timestamp’],
dtype={‘SensorA’: ‘float32’, ‘SensorB’: ‘float32′},
# nrows=10000 # 如果只想读取前1万行数据
)
print(df_large_optimized.info(memory_usage=’deep’)) # 查看内存占用
except MemoryError:
print(“错误:内存不足,无法加载整个 Excel 文件。请尝试使用 usecols, nrows 或分工作表处理。”)
except Exception as e:
print(f”读取大文件时出错:{e}”)
“`

四、最佳实践与注意事项

  1. 明确数据需求: 在读取前,尽可能了解 Excel 文件的结构(工作表、表头位置、数据范围、特殊值)。
  2. 优先使用 openpyxl 引擎: 对于 .xlsx 文件,openpyxl 通常是最新且功能最全的选择。确保已安装 (pip install openpyxl)。
  3. 显式指定参数: 不要过度依赖默认值。明确指定 sheet_name, header, index_col 等可以提高代码的可读性和健壮性。
  4. 善用 usecolsnrows: 对于大型文件或只需要部分数据的场景,这两个参数是性能优化的利器。
  5. 精确控制 dtype: 通过 dtype 参数确保数据类型正确,避免后续清洗麻烦和潜在错误,同时可能优化内存。特别是包含数字 ID、邮编等的列,务必考虑用 strobject 读取。
  6. 处理日期时间: 使用 parse_dates 参数在读取时就完成日期解析,通常比读取后再转换更高效方便。
  7. 处理 NaN: 了解数据中表示缺失值的方式,并使用 na_values 参数进行统一处理。
  8. 使用 pd.ExcelFile: 当需要从同一个 Excel 文件读取多个工作表或进行多次读取操作时,使用 pd.ExcelFile 上下文管理器可以避免重复打开和关闭文件,提升效率。
  9. 错误处理: 使用 try...except 块捕获潜在的 FileNotFoundErrorKeyError (工作表不存在)、ValueError (解析错误) 等异常,使代码更鲁棒。
  10. 考虑文件格式转换: 如果频繁处理同一个大型 Excel 文件且性能是主要问题,考虑一次性将其转换为更适合分析的格式(如 Parquet)并后续直接读取该格式。

五、结语

pandas.read_excel() 是 Python 数据分析工具箱中一颗璀璨的明珠。它不仅提供了读取 Excel 文件的基本功能,更通过其丰富的参数集赋予了用户强大的数据导入控制能力。从简单的单表读取到复杂的多表、多格式、大规模数据的处理,read_excel 都能灵活应对。

熟练掌握 read_excel 的各项参数及其应用场景,意味着你能够更加高效、准确地将现实世界中无处不在的 Excel 数据转化为可供 Python 分析利用的 DataFrame,从而极大地扩展你的数据分析能力边界,提升工作效率。这不仅仅是一项“必备技巧”,更是通往深度数据洞察的重要一步。不断实践,探索不同参数组合的效果,你将能自如地驾驭来自 Excel 世界的各种数据挑战。


发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部