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

遍历DataFrame填充嵌套字典统计公司活跃实例数未达预期

问题排查与解决方案:统计公司每年活跃实例数

核心问题分析

你的代码输出不符合预期,主要源于三个关键错误:

  1. 嵌套字典初始化引用重复:若多个年份共用同一个公司字典对象,修改任意年份的计数会同步影响所有年份,导致各年份结果完全一致。
  2. 未实现逐年累计逻辑:现有代码仅计算单年份的增减量,没有基于上一年的活跃数累加当年变化,无法得到累计活跃实例数。
  3. 未处理NaT终止日期:终止日期为空的记录未被跳过,可能引发错误或不正确的计数逻辑。

解决方案

方法一:基于Pandas的高效实现(推荐)

利用Pandas的事件分组与累计计算,避免嵌套循环的低效与错误:

import pandas as pd

# 1. 加载并预处理数据
data = [
    [106072, 84028, 'COMPANY A', '7/1/04', '4/9/69'],
    [106084, 84028, 'COMPANY A', '12/1/85', '8/20/69'],
    [106094, 84028, 'COMPANY A', '12/1/70', '10/3/69'],
    [106115, 84028, 'COMPANY B', '12/1/85', '1/7/70'],
    [106133, 91108, 'COMPANY B', '2/4/86', '3/6/70'],
    [106133, 91108, 'COMPANY C', pd.NaT, '3/6/91'],
    [106133, 91108, 'COMPANY C', pd.NaT, '3/6/91'],
]
df = pd.DataFrame(data, columns=['ID', 'CO_Num', 'CO_Name', 'Termination_Date', 'Effective_Date'])

# 转换日期列(处理两位年份)
df['Effective_Date'] = pd.to_datetime(df['Effective_Date'], format='%m/%d/%y')
df['Termination_Date'] = pd.to_datetime(df['Termination_Date'], format='%m/%d/%y', errors='coerce')

# 2. 生成生效/终止事件
# 生效事件:+1
events_eff = df[['CO_Name', 'Effective_Date']].copy()
events_eff['year'] = events_eff['Effective_Date'].dt.year
events_eff['change'] = 1

# 终止事件:-1(仅处理非空终止日期)
events_term = df[df['Termination_Date'].notna()][['CO_Name', 'Termination_Date']].copy()
events_term['year'] = events_term['Termination_Date'].dt.year
events_term['change'] = -1

# 3. 合并事件并计算年度变化量
all_events = pd.concat([events_eff, events_term])
yearly_changes = all_events.groupby(['CO_Name', 'year'])['change'].sum().unstack(fill_value=0)

# 4. 重索引目标年份并计算累计活跃数
target_years = range(1969, 1972)
yearly_changes = yearly_changes.reindex(columns=target_years, fill_value=0)
active_counts = yearly_changes.cumsum(axis=1)

# 输出结果
print(active_counts)

执行后将得到预期结果:

1969  1970  1971
CO_Name                     
COMPANY A      3     2     2
COMPANY B      0     2     2
COMPANY C      0     0     0

方法二:修正嵌套循环逻辑

若坚持使用嵌套循环,需修正初始化与累计逻辑:

import pandas as pd

# 预处理数据(同方法一)
data = [
    [106072, 84028, 'COMPANY A', '7/1/04', '4/9/69'],
    [106084, 84028, 'COMPANY A', '12/1/85', '8/20/69'],
    [106094, 84028, 'COMPANY A', '12/1/70', '10/3/69'],
    [106115, 84028, 'COMPANY B', '12/1/85', '1/7/70'],
    [106133, 91108, 'COMPANY B', '2/4/86', '3/6/70'],
    [106133, 91108, 'COMPANY C', pd.NaT, '3/6/91'],
    [106133, 91108, 'COMPANY C', pd.NaT, '3/6/91'],
]
df = pd.DataFrame(data, columns=['ID', 'CO_Num', 'CO_Name', 'Termination_Date', 'Effective_Date'])
df['Effective_Date'] = pd.to_datetime(df['Effective_Date'], format='%m/%d/%y')
df['Termination_Date'] = pd.to_datetime(df['Termination_Date'], format='%m/%d/%y', errors='coerce')

# 1. 正确初始化嵌套字典(每个年份的公司字典独立)
companies = df['CO_Name'].unique().tolist()
target_years = range(1969, 1972)
nest_dict = {year: {comp: 0 for comp in companies} for year in target_years}

# 2. 初始化累计计数器
current_counts = {comp: 0 for comp in companies}

# 3. 逐年计算累计活跃数
for year in sorted(target_years):
    # 继承上一年的累计数
    for comp in companies:
        nest_dict[year][comp] = current_counts[comp]
    
    # 处理当年的生效/终止事件
    for _, row in df.iterrows():
        comp = row['CO_Name']
        # 生效事件
        if row['Effective_Date'].dt.year == year:
            nest_dict[year][comp] += 1
            current_counts[comp] += 1
        # 终止事件(跳过NaT)
        if pd.notna(row['Termination_Date']) and row['Termination_Date'].dt.year == year:
            nest_dict[year][comp] -= 1
            current_counts[comp] -= 1

# 转换为DataFrame
result_df = pd.DataFrame.from_dict(nest_dict, orient='columns')
print(result_df)

关键修正点说明

  • 字典初始化:使用字典推导式为每个年份创建独立的公司字典,避免引用重复。
  • 累计逻辑:维护current_counts变量,逐年继承上一年的活跃数,再叠加当年的增减量。
  • NaT处理:通过pd.notna()跳过终止日期为空的记录,避免错误判断。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 12:31:01