Python 数据处理(十九)—— Excel

Excel 文件

read_excel() 方法可以使用 openpyxl 模块读取 Excel 2007+.xlsx)文件

可以使用 xlrd 读取 Excel 2003(.xls)文件。可以使用 pyxlsb 读取二进制 Excel.xlsb)文件

to_excel() 实例方法可以用于将 DataFrame 保存到 Excel 文件

注意

用于写出旧式 .xls 文件的 xlwt 软件包不再维护。 xlrd 软件包现在仅用于读取旧式 .xls 文件

对于默认参数 engine=None, read_excel() 将使用 xlrd 引擎。

如果安装了 openpyxl,则现在许多情况下将默认使用 openpyxl 引擎。因此,强烈建议安装 openpyxl 来读取 Excel 2007+ (.xlsx)文件

1 读取 Excel 文件

在最基本的用例中,read_excel 采用一个指向 Excel 文件的路径,而 sheet_name 指示要解析的工作表。

# Returns a DataFrame
pd.read_excel("path_to_file.xls", sheet_name="Sheet1")
1.1 ExcelFile 类

为了方便处理来自同一文件的多个工作表,可以使用 ExcelFile 类包装文件并将其传递到 read_excel 中。

由于仅将文件读入内存一次,因此读取多个工作表会带来性能上的好处。

xlsx = pd.ExcelFile("path_to_file.xls")
df = pd.read_excel(xlsx, "Sheet1")

ExcelFile 类也可以用作上下文管理器

with pd.ExcelFile("path_to_file.xls") as xls:
    df1 = pd.read_excel(xls, "Sheet1")
    df2 = pd.read_excel(xls, "Sheet2")

sheet_names 属性将会获取文件中工作表名称列表

ExcelFile 的主要作用是用不同的参数解析多个工作表

data = {}
# For when Sheet1's format differs from Sheet2
with pd.ExcelFile("path_to_file.xls") as xls:
    data["Sheet1"] = pd.read_excel(xls, "Sheet1", index_col=None, na_values=["NA"])
    data["Sheet2"] = pd.read_excel(xls, "Sheet2", index_col=1)

请注意,如果所有工作表都使用相同的解析参数,则可以将工作表名称列表简单地传递给 read_excel,且不会降低性能。

# using the ExcelFile class
data = {}
with pd.ExcelFile("path_to_file.xls") as xls:
    data["Sheet1"] = pd.read_excel(xls, "Sheet1", index_col=None, na_values=["NA"])
    data["Sheet2"] = pd.read_excel(xls, "Sheet2", index_col=None, na_values=["NA"])

# equivalent using the read_excel function
data = pd.read_excel(
    "path_to_file.xls", ["Sheet1", "Sheet2"], index_col=None, na_values=["NA"]
)

还可以使用 xlrd.book.Book 对象作为参数来调用 ExcelFile。这允许用户控制如何读取 excel 文件。

例如,可以通过使用 xlrd.open_workbook() 函数并设置参数 on_demand=True,来按需加载工作表。

import xlrd

xlrd_book = xlrd.open_workbook("path_to_file.xls", on_demand=True)
with pd.ExcelFile(xlrd_book) as xls:
    df1 = pd.read_excel(xls, "Sheet1")
    df2 = pd.read_excel(xls, "Sheet2")
1.2 指定工作表

第二个参数是 sheet_name,不要与 ExcelFile.sheet_names 混淆

ExcelFile 的属性 sheet_names 用于访问所有工作表

  • sheet_name 参数用于指定要读取的一个或多个工作表
  • sheet_name 的默认值是 0,表示读取第一个工作表
  • 传递一个字符串来引用工作簿中特定工作表的名称
  • 传递一个整数来引用工作表的索引,索引从 0 开始
  • 传递一个字符串或整数列表,以返回指定工作表的 DataFrame 字典
  • 传递一个 None 来返回包含所有可用工作表的 DataFrame 字典

传入工作表名称

# Returns a DataFrame
pd.read_excel("path_to_file.xls", "Sheet1", index_col=None, na_values=["NA"])

传入工作表索引

# Returns a DataFrame
pd.read_excel("path_to_file.xls", 0, index_col=None, na_values=["NA"])

使用默认值

# Returns a DataFrame
pd.read_excel("path_to_file.xls")

使用 None 获取所有表

# Returns a dictionary of DataFrames
pd.read_excel("path_to_file.xls", sheet_name=None)

使用列表获取多个工作表

# Returns the 1st and 4th sheet, as a dictionary of DataFrames.
pd.read_excel("path_to_file.xls", sheet_name=["Sheet1", 3])
1.3 读取 MultiIndex

read_excel 可以通过对 index_col 传递一个列表读取多级索引,通过向 header 传递一个列表读取列名多级索引

例如,读取不带名称的 MultiIndex 索引

In [315]: df = pd.DataFrame(
   .....:     {"a": [1, 2, 3, 4], "b": [5, 6, 7, 8]},
   .....:     index=pd.MultiIndex.from_product([["a", "b"], ["c", "d"]]),
   .....: )
   .....: 

In [316]: df.to_excel("path_to_file.xlsx")

In [317]: df = pd.read_excel("path_to_file.xlsx", index_col=[0, 1])

In [318]: df
Out[318]: 
     a  b
a c  1  5
  d  2  6
b c  3  7
  d  4  8

如果索引具有级别名称,它们也将使用相同的参数进行解析

In [319]: df.index = df.index.set_names(["lvl1", "lvl2"])

In [320]: df.to_excel("path_to_file.xlsx")

In [321]: df = pd.read_excel("path_to_file.xlsx", index_col=[0, 1])

In [322]: df
Out[322]: 
           a  b
lvl1 lvl2      
a    c     1  5
     d     2  6
b    c     3  7
     d     4  8

如果源文件同时具有 MultiIndex 索引和列名,则应将它们对应的列表传递给 index_colheader 参数

In [323]: df.columns = pd.MultiIndex.from_product([["a"], ["b", "d"]], names=["c1", "c2"])

In [324]: df.to_excel("path_to_file.xlsx")

In [325]: df = pd.read_excel("path_to_file.xlsx", index_col=[0, 1], header=[0, 1])

In [326]: df
Out[326]: 
c1         a   
c2         b  d
lvl1 lvl2      
a    c     1  5
     d     2  6
b    c     3  7
     d     4  8
1.4 解析特定的列

read_excel 使用 usecols 关键字来允许您指定要读取的列的子集。

usecols 传入一个整数将不再有效。请将一个从 0 开始的列表传递给 usecols

您也可以将以逗号分隔的一组 Excel 列或数据表范围的字符串传递给 usecols

pd.read_excel("path_to_file.xls", "Sheet1", usecols="A,C:E")

如果 usecols 是整数列表,则假定它是文件的列索引

pd.read_excel("path_to_file.xls", "Sheet1", usecols=[0, 2, 3])

元素顺序并不重要,即 usecols=[0,1][1,0] 相同

如果 usecols 是一个字符串列表,则假定每个字符串都对应于文件的列名或从文档标题行推断出来的列名。

pd.read_excel("path_to_file.xls", "Sheet1", usecols=["foo", "bar"])

同样也会忽略列表元素的顺序

如果 usecols 是可调用函数,传入的是列名,返回可调用函数计算结果为 True 的列名

pd.read_excel("path_to_file.xls", "Sheet1", usecols=lambda x: x.isalpha())
1.5 解析日期

在读取 excel 文件时,类似 datetime 的值通常会自动转换为适当的 dtype

但是,如果你有一列字符串看起来像日期(但实际上不是格式化为 excel 中的日期),你可以使用 parse_dates 关键字将这些字符串解析为日期时间格式

pd.read_excel("path_to_file.xls", "Sheet1", parse_dates=["date_strings"])
1.6 单元格转换

可以通过 converters 选项转换 Excel 单元格的内容。例如,要将列转换为布尔值

pd.read_excel("path_to_file.xls", "Sheet1", converters={"MyBools": bool})

这个选项可以处理缺失值,并将转换时出现的异常作为缺失数据处理。变换是逐个单元格而不是对整个列进行的,所以不能保证数组的 dtype

def cfun(x):
    return int(x) if x else -1

pd.read_excel("path_to_file.xls", "Sheet1", converters={"MyInts": cfun})
1.7 指定类型

作为转换器的替代方法,可以使用 dtype 关键字指定整个列的类型,该关键字通过将字典的名称映射到列,值对应列的类型。

pd.read_excel("path_to_file.xls", dtype={"MyInts": "int64", "MyText": str})

2 写出 Excel 文件

2.1 将 Excel 文件写入磁盘

要将 DataFrame 对象写入 Excel 文件的工作表中,可以使用 to_excel 实例方法。

其参数与 to_csv 基本相同,第一个参数是 excel 文件的名称,第二个可选参数是数据写入到的工作表的名称。例如:

df.to_excel("path_to_file.xlsx", sheet_name="Sheet1")

扩展名为 .xls 的文件将使用 xlwt 写出,扩展名为 .xlsx 的文件将使用 xlsxwriter(如果可用)或 openpyxl 编写。

可以使用 index_label 参数设置索引名称,如果是多级索引,需要传递名称列表

merge_cells 参数可以设置多级索引是否合并单元格,默认为 TRUE,如果为 False,则会写出所有的索引值

df.to_excel("path_to_file.xlsx", index_label="label", merge_cells=False)

为了在一个 Excel 文件中写入不同的 DataFrame,可以传递一个 ExcelWriter

with pd.ExcelWriter("path_to_file.xlsx") as writer:
    df1.to_excel(writer, sheet_name="Sheet1")
    df2.to_excel(writer, sheet_name="Sheet2")

注意
因为 Excel 默认将所有数字存储为浮点数,在不损失精度的情况下,pandas 默认会尝试将整数转换为浮点数。

你可以设置 convert_float=False 来取消这一行为,可能会带来性能的提升

2.2 将 Excel 文件写入内存

pandas 支持使用 ExcelWriterExcel 文件写入到类似缓冲区的对象中,如 StringIOBytesIO

from io import BytesIO

bio = BytesIO()

# By setting the 'engine' in the ExcelWriter constructor.
writer = pd.ExcelWriter(bio, engine="xlsxwriter")
df.to_excel(writer, sheet_name="Sheet1")

# Save the workbook
writer.save()

# Seek to the beginning and read to copy the workbook to a variable in memory
bio.seek(0)
workbook = bio.read()

注意
engine 参数是可选的,但是推荐为该参数指定值

设置 engine='xlrd' 将生成 excel2003 格式的工作簿(xls)。使用 "openpyxl""xlsxwriter" 将生成 excel2007 格式的工作簿(xlsx)。

如果省略,则生成 Excel 2007 格式的工作簿

3 Excel 写出引擎

1.2.0 版本后,由于 xlwt 包不再维护,xlwt 引擎将从 pandas 的未来版本中移除。

这是 pandas 中唯一支持写入 .xls 文件的引擎

pandas 通过两种方法选择 Excel 写出引擎

  1. engine 参数
  2. 文件扩展名(通过配置选项中指定的默认值)

默认情况下,pandas.xlsx 使用 XlsxWriter,对 .xlsm 使用 openpyxl,对 .xls 文件使用 xlwt

如果您安装了多个引擎,则可以通过设置配置选项 io.excel.xlsx.writerio.excel.xls.writer 来设置默认引擎

如果 Xlsxwriter 不可用,pandas 将使用 openpyxl 来获取 .xlsx 文件。

要指定要使用哪个写出引擎,可以将 engine 关键字参数传递给 to_excelExcelWriter。内置引擎为

  • openpyxl: 需要 2.4 或更高版本
  • xlsxwriter
  • xlwt
# By setting the 'engine' in the DataFrame 'to_excel()' methods.
df.to_excel("path_to_file.xlsx", sheet_name="Sheet1", engine="xlsxwriter")

# By setting the 'engine' in the ExcelWriter constructor.
writer = pd.ExcelWriter("path_to_file.xlsx", engine="xlsxwriter")

# Or via pandas configuration.
from pandas import options  # noqa: E402

options.io.excel.xlsx.writer = "xlsxwriter"

df.to_excel("path_to_file.xlsx", sheet_name="Sheet1")

4 样式和格式

可以使用 to_excel 方法中的以下参数来修改创建的 Excel 工作表的外观和感觉

  • float_format: 浮点数的格式化字符串(默认为 None
  • freeze_panes: 包含两个整数的元组,表示冻结最底行和最后列范围内的单元格。这些数值是 1 起始的,因此 (1, 1) 将冻结第一行和第一列(默认为 None

使用 Xlsxwriter 引擎可以提供许多选项来控制用 to_excel 方法创建的 Excel 工作表的格式

具体可参考 https://xlsxwriter.readthedocs.io/working_with_pandas.html

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容