浅谈 Pandas 样式
简介
大家都知道 Excel 可以设定单元格格式,还支持单元格迷你图,其实 Pandas 也可以,本文参照 Chris Moffitt 的 Stylin’ with Pandas 一文,为大家简单介绍一下 Pandas 如何实现 DataFrame 的样式设置,主要内容如下:
-
设置 DataFrame 不同列的样式,如千分号、小数位数、货币符号、日期格式,百分比等;
-
突出显示 DataFrame 中某一列里符合某些条件的数据,如,按不同颜色显示某列中的最大值与最小值;
-
以不同渐变色展示每一行数据占总数据的比例大小,占比越大,颜色越深,占比越小,则颜色越浅;
-
实现类似 Excel 迷你条形图的功能,根据数据大小,在单元格里显示迷你条形图;
-
利用 Sparklines 支持库,配合 Pandas 绘制迷你走势图。需要先用
pip install sparklines
命令安装 Sparklines 支持库。
什么是样式?为什么与使用样式?
样式的基本理念是用户在调整数据显示形式的同时,不会影响数据本身的计算操作。
最直观的样式是货币符号,如果只显示一个数字,比如 25.06,读者并不清楚这个数字代表的到底是美元、英镑、日元还是人民币,但 ¥25.06,大家就都知道这是人民币了,由此可见,样式可以让数据提供更多信息。
百分比也是数据样式的重要形式,0.12 就不如 12% 更直观,用百分比说明数据更清晰,也更简单。
Pandas 支持不同样式,可以用更易理解的方式显示数据,但并未修改数据的类型,所以依然还可以用 Pandas 提供的各种数学、日期、字符串函数处理数据。
Pandas 样式还包括内容里提及的高级样式,比如添加颜色与条形图等可视化元素。本文只是简要介绍 Pandas 样式的基本功能,方便大家快速上手,提高数据分析报表的可读性。
数据文件说明
-
数据文件为 2018年销售汇总表.csv(点击下载),本文件引用的是原文作者 Chris 虚构的一家企业 2018 年的销售数据,但汉化了数据表的标题,方便大家在代码中识别数据列的信息;
-
文件格式从原文的
xlsx
改为csv
; -
文件共有 5 列,分别为账号(字符串)、姓名(字符串)、单品(字符串)、数量(整数)、单价(2 位小数)、金额(2 位小数)、日期(DateTime)
Jupyter Notebook 示例文件,点击下载。
0.1 导入 Numpy 与 Pandas
import numpy as np
import pandas as pd
下面的代码与原文不同,原文用的是 xlsx 文件,本文用的是 csv 文件,需要解析日期。
另外需要注意,数据文件与 ipynb 文件要在同一文件夹下。
df = pd.read_csv('2018年销售汇总表.csv',parse_dates=['日期'])
0.2 df.head()
预览数据
df.head()
0.3 汇总数据,根据客人姓名分组计算 2018 年每个客人的平均金额与消费总额
df.groupby('姓名')['金额'].agg(['mean','sum'])
汇总统计消费金额
1.1 设置金额样式:货币符号、千分号、2 位小数
可以看到平均值显示的是 6 位小数,没有货币符号,整数部分也没有千分号。此时,可以用 DataFrame 的 style.format
修饰。
代码如下,汇总计算的代码与上面相同,但多了 .style.format('${0:,.2f}')
,引号里的 $ 符号代表美元,冒号(:)后的逗号代表千分号,.2f
代表 2 位小数。
(
df.groupby('姓名')['金额']
.agg(['mean', 'sum'])
.style.format('${0:,.2f}')
)
调整以后,数据显示如下:
货币样式示例1可以看到,用了 .style.format()
函数以后,DataFrame 中平均值(mean)列显示的数据变成了带美元符号标记、整数部分带千分号、小数仅保留两位的样式,这种样式更便于理解金额这一概念。
如果只想保留整数,可使用 .style.format('${0:,.0f}')
,把上面代码里的 2 改为 0,即可。
(
df.groupby('姓名')['金额']
.agg(['mean', 'sum'])
.style.format('${0:,.0f}')
)
货币样式示例2
此时,可以看到,货币数据已经按四舍五入的原则保留了整数。
如需了解更多 Python 字符串格式化示例,请参照 Python String Format Cookbook 。
1.2 设定日期与百分比样式
接下来用 groupby
函数,按销售日期计算每月销售金额及其占年度销售总额的比例。
monthly_sales = df.groupby([pd.Grouper(key='日期', freq='M')])['金额'].agg(['sum']).reset_index()
monthly_sales['月占比'] = monthly_sales['sum']/df['金额'].sum()
日期与百分比示例1
此处可以看到,日期显示的是每个月的最后一天,比例一列则显示为 6 位小数,这种样式显然非常不直观,但一列一列调整样式也不是好方法,能不能一次性调整多列数据的样式呢?答案自然是,能!用样式字典就可以了。
format_dict = {'sum': '${0:,.0f}', '日期': '{:%Y-%m}', '月占比': '{:.2%}'}
monthly_sales.style.format(format_dict).hide_index()
上面的代码,首先把 format_dict
定义为一个样式字典,分别设置了汇总金额(sum)、日期、月占比三列的样式。其中,汇总金额为带美元符号、千分号、0 位小数的数字;日期为经典的“年月”格式,月占比则为带 2 位小数的百分比形式。
第二行代码,使用 style.format()
调用了第一行代码设定的样式字典(format_dict
),并用 hide_index()
隐藏了索引,隐藏索引的功能在很多情况下都有用,大家可以试试。
这样一来,DataFrame 的数据显示就变得比较可耐了,是不是数据显示得更清晰了,而且实现起来其实也很简单。
2. 突出显示最大值与最小值
Pandas 还支持用颜色突出显示符合条件的数据,类似 Excel 里的条件格式,本文主要演示一下如何突出显示某列数据里的最大值(浅绿色)与最小值(红色)。
(
monthly_sales
.style
.format(format_dict)
.hide_index()
.highlight_max(color='lightgreen')
.highlight_min(color='red')
)
突出显示最大值与最小值
这里的 color
参数除了可以用lightgreen
这样的关键词以外,还可以使用 '#cd4f39'
这样的颜色代码,更灵活。而且可以设置多个条件,比如可以同时设置 highlight_max
、highlight_min
。
3. 渐变色样式
只改变数字的样式,还不够,我们还想要更多,还想用颜色的深浅渐变来表示某一列数据占比的多少,其实这也是 Excel 已经提供了的功能,Pandas 也支持了。实现这一目标,需要使用 style
的 background_gradient
函数。
(
monthly_sales.style
.format(format_dict)
.background_gradient(subset=['sum'], cmap='BuGn')
)
上述代码设定了颜色渐变针对的列,subset=['sum']
,色图用的是 cmap 参数,值为'BuGn',是一种绿色的渐变色图,色图的值请参阅 matplotlib 的文档 ,还有更多色彩可选。
显示效果如下,是不是觉得更直观了?
渐变色样式4. 迷你条形图样式
除了渐变色,Pandas 还支持在 DataFrame 单元格里显示迷你条形图。
(
monthly_sales
.style
.format(format_dict)
.hide_index()
.bar(color='#FFA07A', vmin=100_000, subset=['sum'], align='zero')
.bar(color='lightblue', vmin=0, subset=['月占比'], align='zero')
.set_caption('2018年销售一览表')
)
这里使用的是 style
的 bar
函数,分别需要设置几个参数,color
还是支持颜色编码与关键词,vmin
是基准值,比如销售额的基准值是 10 万,百分比的基准值是 1,subset
是针对的列,align
则代表对齐方式。
此外,还可以用 set_caption
函数设置 DataFrame 的标题。代码执行后,显示效果如下。
5. Sparklines - 走势图
走势图这种样式不是 Pandas 的内置样式,但依然很实用,也很酷,它是一个叫 sparklines 的支持库提供的。详情请参阅它的文档 ,这个模块可以为 Pandas 的 DataFrame 添加迷你走势图。
首先,导入 sparklines
;
import sparklines
接着,定义调用 sparklines
的函数;
def sparkline_str(x):
bins=np.histogram(x)[0]
sl = ' '.join(sparklines(bins))
return sl
sparkline_str.__name__ = "走势图"
最后,在 groupby
函数里调用定义的 sparkline_str
函数;
df.groupby('姓名')['数量', '金额'].agg(['mean', sparkline_str])
迷你走势图示例
这种汇总功能可以很直观的显示数据,更有趣的是这个走势图是由纯文本组成的,又简单,又实用,对不?
总结
Pandas 的样式功能备受欢迎,尤其是分析师完成数据分析工作后,要给别人展示数据分析结果的时候,这个功能可以让你的数据分析报告更直观,更清晰。除了本文介绍的功能之外,其实还有更多样式与函数功能供你选择,本文只是引导您上手 Pandas 样式的基础入门,想要玩的更花俏,请自行研究 Pandas 官方的样式文档。
最后,感谢 Alexas_Fotos 提供的图片,非常有创意。
【呆鸟云】翻译不易,四处求证、三天翻译、两天校对,只求一秒点赞 _
感谢天善智能的Python爱好者社区公众号一直以来对我的支持,敬请关注!
也欢迎大家关注我的微信公众号 Python大咖谈
Python大咖谈