Pandas按subject_id分组筛选sld数据后绘制折线图的优化咨询
高效绘制分组折线图的解决方案
原始数据
| subject_id | name | day | value |
|---|---|---|---|
| 1 | sld | 0 | 0 |
| 1 | sld | 1 | 5 |
| 1 | sld | 2 | 12 |
| 1 | dsld | 0 | 0 |
| 1 | dsld | 1 | -1 |
| 2 | sld | 0 | 0 |
| 2 | sld | 1 | 7 |
| 2 | sld | 2 | 8 |
| 2 | sld | 3 | 4 |
| 2 | dsld | 0 | 0 |
绘图需求
- 按
subject_id分组展示 - 只保留
name为sld的数据行 - 以
day为X轴、value为Y轴画折线图,所有组放在同一张图里,优先用seaborn
试过的代码和遇到的问题
- 首次尝试的代码:
fig, ax = plt.subplots(figsize=(8, 6)) df_sld = df[df['name'] == 'sld'] df_sld.groupby('subject_id').plot(x = 'day', y = 'value', ax = ax)
问题:运行耗时较长,想找更高效的分组筛选方式。
- 后续尝试的代码:
df.groupby('subject_id')['name'].apply(lambda x: x == 'sld').plot(x = 'day', y = 'value') df.groupby('subject_id').apply(lambda x: x['name'] == 'sld').plot(x = 'day', y = 'value')
问题:出现“无数值数据”的报错。
高效解决方案(优先用seaborn)
seaborn的lineplot原生支持分组绘图,无需手动循环分组,效率远高于循环绘图的方式,代码也更简洁:
import seaborn as sns import matplotlib.pyplot as plt # 先筛选name为sld的数据,这是矢量化操作,效率极高 df_sld = df[df['name'] == 'sld'] # 用hue参数指定按subject_id分组绘图 plt.figure(figsize=(8, 6)) sns.lineplot(data=df_sld, x='day', y='value', hue='subject_id', marker='o') plt.title('各subject的sld数值变化趋势') plt.xlabel('Day') plt.ylabel('Value') plt.show()
为啥之前的方法要么慢要么报错?
- 首次尝试的
groupby().plot()本质是循环每个分组单独调用绘图函数,数据量大时多次绘图的开销会显著增加;而seaborn是一次性处理所有分组数据,效率自然更高。 - 后续代码的错误在于:
apply(lambda x: x['name'] == 'sld')返回的是布尔值序列,不是包含day和value的有效数值数据,绘图函数找不到可用于绘图的数值字段,因此报错。
不用seaborn的高效替代方案
如果坚持使用pandas绘图,可先筛选数据,再利用plot的hue参数(pandas 1.3及以上版本支持),比循环groupby的方式更高效:
import matplotlib.pyplot as plt df_sld = df[df['name'] == 'sld'] fig, ax = plt.subplots(figsize=(8, 6)) df_sld.plot(x='day', y='value', hue='subject_id', marker='o', ax=ax) plt.title('各subject的sld数值变化趋势') plt.xlabel('Day') plt.ylabel('Value') plt.show()
内容的提问来源于stack exchange,提问作者Sharhad Bashar
相关产品推荐
相关产品推荐

