You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用np.where为Pandas DataFrame创建多条件分段工时占比列

解决方案

问题分析

你当前代码的问题是:只要某行匹配到目标分组,就把所有Hours列的总和除以8,而不是只累加对应Group匹配目标分组的Hours值。比如ID=1的Seg_Maintenance,应该只取Hours1的4(因为Group1是Maintenance),而不是把Hours1+Hours2+Hours3全加起来。

方法一:循环遍历分组,精准匹配累加

直接针对每个目标分组,遍历3组Group-Hours对,提取匹配的Hours值求和后除以8:

import pandas as pd
import numpy as np

df = pd.DataFrame({
    'ID': [1, 2, 3, 4],
    'Group1': ['Maintenance', 'Shop', 'Admin', 'Shop'],
    'Hours1': [4, 4, 8, 8],
    'Group2': ['Admin', 'Customer', '0', '0'],
    'Hours2': [4.0, 2.0, 0.0, 0.0],
    'Group3': ['0', 'Admin', '0', '0'],
    'Hours3': [0.0, 2.0, 0.0, 0.0],
})

segment_list = ["Maintenance", "Shop", "Admin", "Customer"]

for seg in segment_list:
    # 初始化累加列
    total_hours = pd.Series(0, index=df.index)
    # 遍历3组Group-Hours对
    for n in range(1, 4):
        # 找到当前Group列等于目标分组的行,取出对应Hours值累加
        mask = df[f'Group{n}'] == seg
        total_hours += df.loc[mask, f'Hours{n}'].reindex(df.index, fill_value=0)
    # 计算结果并赋值给新列
    df[f'Seg_{seg}'] = total_hours / 8

print(df)

运行后得到的结果符合预期:

ID       Group1  Hours1    Group2  Hours2 Group3  Hours3  Seg_Maintenance  Seg_Shop  Seg_Admin  Seg_Customer
0   1  Maintenance       4     Admin     4.0      0     0.0              0.5       0.0       0.5           0.0
1   2         Shop       4  Customer     2.0  Admin     2.0              0.0       0.5       0.25          0.25
2   3        Admin       8         0     0.0      0     0.0              0.0       0.0       1.0           0.0
3   4         Shop       8         0     0.0      0     0.0              0.0       1.0       0.0           0.0

方法二:用melt重塑数据(更高效的Pandas风格写法)

如果分组数量较多,推荐用数据重塑的方式,避免嵌套循环:

# 重塑数据:把Group和Hours列转成行
melted = df.melt(
    id_vars=['ID'],
    value_vars=[f'Group{n}' for n in range(1,4)] + [f'Hours{n}' for n in range(1,4)],
    var_name='Type',
    value_name='Value'
)

# 拆分出分组编号(1/2/3)
melted['Num'] = melted['Type'].str.extract('(\d+)')
# 拆分出类型(Group/Hours)
melted['Type'] = melted['Type'].str.replace('\d+', '')

# 转成宽表:每个ID+Num对应Group和Hours
pivoted = melted.pivot(index=['ID', 'Num'], columns='Type', values='Value').reset_index()
# 过滤掉Group为0的行
pivoted = pivoted[pivoted['Group'] != '0']
# 把Hours转成数值类型
pivoted['Hours'] = pd.to_numeric(pivoted['Hours'])

# 计算每个ID+Group的总Hours,再除以8
result = pivoted.groupby(['ID', 'Group'])['Hours'].sum().unstack(fill_value=0) / 8
# 重命名列并合并回原DataFrame
result.columns = [f'Seg_{col}' for col in result.columns]
df = df.merge(result, on='ID', how='left')

print(df)

这个方法逻辑更清晰,也更适合扩展到更多Group-Hours对的场景。


内容的提问来源于stack exchange,提问作者user12715151

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 08:22:20