合并两个DataFrame实现列值列表化及映射、绘图问题求助
问题解答
一、合并DataFrame并将loaded列转为列表形式
你用inner join得到的是笛卡尔积结果,不符合预期。正确步骤是先对df_B按id分组聚合,把同一id的loaded值拼成列表,再和df_A做左连接保留所有id:
# 1. 对df_B按id分组,将loaded转为列表 df_B_grouped = df_B.groupby('id')['loaded'].agg(list).reset_index() # 2. 和df_A左连接,保留df_A所有行 result = df_A.merge(df_B_grouped, on='id', how='left') # 3. 将NaN替换为空列表 result['loaded'] = result['loaded'].apply(lambda x: x if isinstance(x, list) else [])
执行后就能得到你要的结果:
id status duration loaded 1 C 1:00 [grand,vice,cont] 2 F 3:00 [grand,bliss] 3 D 2:50 [test] 4 Y 1:00 []
二、绘制loaded条目与总时长的柱状图
你的预期里grand总时长是4:00,应该是id1和id2里的grand时长累加的结果。直接一步到位的方案:
步骤1:处理时长格式并合并数据
先把时分格式转成分钟数方便计算,再合并df_B和df_A的时长数据:
# 定义时分转分钟的函数 def time_to_minutes(time_str): hours, mins = map(int, time_str.split(':')) return hours * 60 + mins # 合并df_B和df_A的id、duration列 df_combined = df_B.merge(df_A[['id', 'duration']], on='id', how='left') # 将时长转为分钟数 df_combined['duration_min'] = df_combined['duration'].apply(time_to_minutes)
步骤2:按loaded条目求和总时长
# 按loaded分组,计算总时长(分钟) loaded_total = df_combined.groupby('loaded')['duration_min'].sum().reset_index() # 可选:把分钟转回时分格式 def minutes_to_time(minutes): hours = minutes // 60 mins = minutes % 60 return f"{hours}:{mins:02d}" loaded_total['duration'] = loaded_total['duration_min'].apply(minutes_to_time)
得到的loaded_total就是你要的x和y数据:
loaded duration_min duration grand 240 4:00 vice 60 1:00 cont 60 1:00 bliss 180 3:00 test 170 2:50
步骤3:绘制柱状图
用matplotlib直接绘制:
import matplotlib.pyplot as plt plt.bar(loaded_total['loaded'], loaded_total['duration_min']) plt.xticks(rotation=45) plt.ylabel('总时长(分钟)') plt.xlabel('loaded条目') plt.title('loaded条目与总时长柱状图') plt.tight_layout() plt.show()
如果要显示时分格式的y轴标签,可以进一步调整,但用数值绘图更准确。
三、给df_B添加duration列失败的问题排查
你写的代码逻辑没问题,但大概率是以下两个原因:
- 变量名拼写错误:比如代码里不小心把
df_A写成了df_a(大小写不一致),导致字典dd为空或错误。 - id类型不匹配:df_A的id是整数类型,df_B的id是字符串类型,map时匹配不到。
修正后的代码:
# 先统一id类型为整数,避免类型不匹配 df_A['id'] = df_A['id'].astype(int) df_B['id'] = df_B['id'].astype(int) # 用更简洁的方式生成字典(推荐) dd = df_A.set_index('id')['duration'].to_dict() # 映射duration列 df_B['duration'] = df_B['id'].map(dd)
这样就能得到你要的df_B结构:
id loaded duration 1 grand 1:00 1 vice 1:00 1 cont 1:00 2 grand 3:00 2 bliss 3:00 3 test 2:50
内容的提问来源于stack exchange,提问作者abinitio
相关产品推荐
相关产品推荐

