如何使用seaborn或matplotlib绘制与crosstab效果一致的折线图
问题描述
我有一个包含三列的DataFrame,需要针对其中两列绘制关联可视化:两列数据类型分别为datetime和object,datetime类型列名为started_at,object类型列名为member_casual。我希望x轴展示started_at提取的小时维度,y轴展示member_casual各分类的对应计数。
我的DataFrame(df)样例如下:
rideable_type started_at member_casual electric_bike 2021-06-13 14:31:28 casual classic_bike 2021-06-04 11:18:02 member classic_bike 2021-06-04 09:49:35 casual calssic_bike 2021-06-04 09:55:34 casual electric_bike 2021-06-04 14:05:51 casual classic_bike 2021-06-04 14:09:59 member electric_bike 2021-06-03 19:32:01 casual electric_bike 2021-06-10 16:30:10 member ... ... ... ... ... ...
目前我使用如下pandas内置绘图代码可以实现需求:生成x轴为小时维度、y轴为member_casual分类计数的折线图:
pd.crosstab(df.started_at.dt.hour,df.member_casual).plot(kind='line', ax = ax)
核心疑问
如何使用seaborn或matplotlib绘制出完全相同的图表?
我是Python可视化初学者,自行尝试了两种写法均运行报错,尝试代码如下:
尝试写法1
plt.plot(df.started_at.dt.hour, df.member_casual)
尝试写法2
sns.lineplot(df.started_at.dt.hour, hue = df.member_casual)
报错原因
两种写法报错的核心原因是未提前对数据做分组聚合统计:直接传入原始明细行的话,绘图函数无法自动按小时统计两类用户的数量,自然无法输出预期的计数折线图。
实现方案
无论使用matplotlib还是seaborn,都需要先完成和pd.crosstab一致的聚合计算,再传入绘图函数。
第一步:数据预处理
先提取小时字段,统计每个小时下两类用户的骑行次数:
import pandas as pd import matplotlib.pyplot as plt import seaborn as sns # 从时间列提取小时 df['hour'] = df['started_at'].dt.hour # 生成小时-用户类型的计数交叉表,和原有逻辑完全一致 count_df = pd.crosstab(df['hour'], df['member_casual'])
方法1:纯Matplotlib实现
逐类绘制折线即可得到和pandas原生绘图完全一致的效果:
fig, ax = plt.subplots(figsize=(10, 6)) # 遍历每个用户分类绘制折线 for user_type in count_df.columns: ax.plot(count_df.index, count_df[user_type], label=user_type) ax.set_xlabel('Hour of Day') ax.set_ylabel('Ride Count') ax.legend(title='member_casual') plt.show()
方法2:Seaborn实现
Seaborn的lineplot需要输入长表格式数据,先转换表结构再绘图即可:
# 宽表转长表,适配Seaborn输入格式 count_long = count_df.reset_index().melt( id_vars='hour', var_name='member_casual', value_name='count' ) fig, ax = plt.subplots(figsize=(10, 6)) sns.lineplot(data=count_long, x='hour', y='count', hue='member_casual', ax=ax) plt.show()
内容的提问来源于stack exchange,提问作者Ibad Ullah
相关产品推荐
相关产品推荐

