基于Pandas Groupby实现列作为X轴的时序数据可视化优化
当然可以用groupby实现向量化绘图!
你现在的嵌套循环确实可以优化,利用pandas的groupby功能,我们可以把相同cluster和cat的时间序列归为一组,一次性绘制整组的序列,避免逐行循环,代码会更简洁高效。
具体实现步骤:
首先,先确认我们需要的核心数据:
- 时间序列的列:就是多级索引中
('frac_norm',2,1)对应的所有列(也就是DataFrame中从第2列到倒数第2列) - X轴的取值:这些时间序列列的第二个索引层级
month_rel的值(比如-5, -4, ..., 5)
然后,我们可以按cluster和cat的组合来分组,每个组内的所有序列共享相同的颜色和线型,直接批量绘制:
import pandas as pd import numpy as np import matplotlib.pyplot as plt # 先生成你的DataFrame(和你提供的代码一致) vals = np.array([['-1b', 0.7606747496046389, 0.7898535589129476, 0.959409594095941, 0.8677546569280126, 0.7901020186672455, 1.0, 0.5887286145588728, 0.7190726452719073, 0.6955719557195572, 0.6476962793343348, 0.6563233814156323, 4], ['-1b', 0.5804363905325444, 0.5467611336032389, 0.7134300126103406, 0.7420329670329671, 0.8021978021978022, 0.389957264957265, 0.861451048951049, 0.6517857142857143, 0.798265460030166, 0.4763049450549451, 0.8960720130932898, 0], ['-1b', 0.9461875843454791, 0.49953095684803, 0.8348848603625673, 0.8257715338553662, 0.7540183696900115, 0.6782302664655606, 0.43069179143004643, 0.35398860398860393, 0.33376068376068374, 0.28475935828877, 0.260501012145749, 2], ['-1b', 0.8267008985879333, 0.8120300751879698, 0.7651821862348178, 0.680161943319838, 0.7634749524413443, 0.8026315789473684, 1.0, 0.7801857585139319, 0.8440191387559809, 0.8686980609418281, 0.7226720647773278, 4], ['-1b', 1.0, 0.955656108597285, 0.6776470588235294, 0.9115556882651537, 0.766129636568003, 0.7437589670014347, 0.6179800221975582, 0.6065359477124183, 0.715527950310559, 0.6149019607843138, 0.4822670674109059, 3], ['-1b', 0.8700564971751412, 0.3719806763285024, 0.6402116402116402, 0.8351851851851851, 0.6731078904991948, 0.5365853658536585, 1.0, 0.8502415458937197, 0.55119825708061, 0.873015873015873, 0.6355555555555555, 4], ['-1b', 0.8196997807387418, 0.879872907246731, 0.961178456344944, 1.0, 0.8554654738607772, 0.8278240873814314, 0.8271388025408839, 0.3040112596762843, 0.5749778172138421, 0.47399605003291634, 0.35893441346004046, 3], ['-1b', 1.0, 0.9958592132505176, 0.7384176764076977, 0.9912165129556433, 0.8543355440923606, 0.9365176566646254, 0.9103471520053926, 0.8832054560954816, 0.9877955758962623, 0.6994328922495274, 0.8150724637681159, 4], ['-1b', 0.9490474080638015, 0.9902376128200405, 0.8995240613432046, 1.0, 0.9610655737704917, 0.837029893924783, 0.8351136964569011, 0.759142496847415, 0.7497267759562841, 0.8869130313976105, 0.9369612979550449, 4], ['-1b', 0.7805383022774327, 0.7021791767554478, 0.5686274509803921, 1.0, 0.6013824884792627, 0.7891156462585033, 0.0, 0.07142857142857142, 0.0, 0.11196911196911197, 0.07397959183673469, 2]], dtype=object) cols = pd.MultiIndex.from_tuples([( 'cat', ''), (('frac_norm', 2, 1), -5), (('frac_norm', 2, 1), -4), (('frac_norm', 2, 1), -3), (('frac_norm', 2, 1), -2), (('frac_norm', 2, 1), -1), (('frac_norm', 2, 1), 0), (('frac_norm', 2, 1), 1), (('frac_norm', 2, 1), 2), (('frac_norm', 2, 1), 3), (('frac_norm', 2, 1), 4), (('frac_norm', 2, 1), 5), ( 'cluster', '')], names=[None, 'month_rel']) idx = pd.MultiIndex.from_tuples([(3414845, 4232621), (4369232, 3370279), ( 22771, 3795428), (2660226, 3126314), (4154510, 4348009), (2860801, 164553), ( 120577, 3480468), (6692132, 5095003), (2515737, 4263756), ( 707596, 2856619)], names=['user1', 'user2']) df = pd.DataFrame(vals, columns=cols, index=idx) # 准备颜色和线型字典(和你原来的一致) colors = ['r','g','b','c','y','k'] lnst = ['-','--'] cats = np.sort(df['cat'].unique()) clusters = np.sort(df['cluster'].unique()) colordict = dict(zip(clusters, colors)) lnstdict = dict(zip(cats,lnst)) fig, ax = plt.subplots() # 提取时间序列列和X轴值 ts_cols = df.columns[1:-1] # 跳过第一个cat列和最后一个cluster列 x_vals = ts_cols.get_level_values(1) # 获取month_rel作为X轴 # 按cluster和cat分组,批量绘制 for (clus_val, cat_val), group in df.groupby(['cluster', 'cat']): # 把组内的时间序列转置,这样每一列对应一个用户的序列,plot会自动绘制所有列 ax.plot(x_vals, group[ts_cols].T, color=colordict[clus_val], linestyle=lnstdict[cat_val]) plt.show()
为什么这样更高效?
- 原来的代码是两层嵌套循环(先遍历cluster,再遍历每行),而现在只需要一层循环遍历分组
group[ts_cols].T把每行的序列转成列,matplotlib的plot函数可以一次性绘制所有列,避免了逐行调用plot的开销- 代码逻辑更清晰,直接按分组逻辑处理,和你的可视化需求(同cluster同颜色,同cat同线型)完全匹配
这样绘制出来的结果和你原来逐行绘制的效果完全一致,但代码更简洁,数据量大的时候性能提升会更明显。
内容的提问来源于stack exchange,提问作者irene
相关产品推荐
相关产品推荐

