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

在Pandas中应用自定义函数修改列值及计算平均时间间隔

看起来你已经有了核心的解析思路,不过目前的代码在批量处理DataFrame行和实现最终平均值计算上还有点小问题,咱们一步步来解决:

处理Pandas中ISO时间间隔字符串并计算平均值

一、重构解析函数

你的parse函数目前只能返回单个值就提前退出,没法批量处理每行数据。咱们把它改成可以接收单个时间间隔字符串的独立函数,同时加入空值处理:

import re
import pandas as pd

def parse_timespan(timespan_str):
    # 处理空值或无效值的情况
    if pd.isna(timespan_str) or not timespan_str.startswith(('-', 'P')):
        return 0
    is_negative = timespan_str.startswith('-')
    # 根据正负截取需要匹配的字符串部分
    target_str = timespan_str[1:] if is_negative else timespan_str
    # 用正则匹配年(Y)、月(M)、日(D)的数值
    date_info = re.findall(r"P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)D)?$", target_str)
    if not date_info:
        return 0
    # 把匹配到的数值转成整数,空值则设为0
    year, month, day = [int(num) if num else 0 for num in date_info[0]]
    # 计算总天数(这里用365天/年、30天/月是简化计算,你可以根据需求调整)
    daystotal = (year * 365) + (month * 30) + day
    return -daystotal if is_negative else daystotal

二、生成新列(不修改原DataFrame)

要在不改动原timespan列的前提下得到转换后的数值列,直接用Pandas的apply()方法就可以了——它会把函数应用到列的每一行,生成新列:

def do_process_citation_data(f_path):
    # 读取CSV时直接用skiprows=1跳过首行,比iloc[1:]更简洁
    my_ocan = pd.read_csv(
        f_path,
        names=['oci', 'citing', 'cited', 'creation', 'timespan', 'journal_sc', 'author_sc'],
        skiprows=1,
        parse_dates=['creation']  # timespan是间隔字符串,不用解析为日期
    )
    # 统一转换creation列的日期格式
    my_ocan['creation'] = pd.to_datetime(my_ocan['creation'], format="%Y-%m", yearfirst=True)
    # 生成新列timespan_days,完全保留原timespan列
    my_ocan['timespan_days'] = my_ocan['timespan'].apply(parse_timespan)
    return my_ocan

# 调用函数处理你的CSV文件
df = do_process_citation_data("citations.csv")

现在df里既有原始的timespan字符串列,又有新增的timespan_days整数列,完全不会修改原数据。

三、按年份计算timespan平均值

你的最终目标是计算特定年份的平均值,咱们可以先从creation列提取年份,再分组聚合:

1. 计算所有年份的平均值

# 从creation日期列提取年份,生成单独的year列
df['year'] = df['creation'].dt.year
# 按年份分组,计算每个年份的timespan平均值
yearly_avg_timespan = df.groupby('year')['timespan_days'].mean()
print(yearly_avg_timespan)

2. 计算单个特定年份的平均值

比如要计算1985年的平均值:

target_year = 1985
# 筛选出creation年份为1985的行,再计算平均值
avg_1985 = df[df['creation'].dt.year == target_year]['timespan_days'].mean()
print(f"1985年的timespan平均值:{avg_1985}")

小提示

  • 为什么不用手动循环?:Pandas的apply是矢量化操作的简化写法,比手动写for循环效率高得多,尤其是处理几万行以上的数据时差距明显。
  • 如果不想修改原DataFrame副本?:可以先复制一份原数据:df_copy = df.copy(),然后在df_copy上生成新列,原df就完全不受影响。
  • 日期计算更精准?:如果需要更精准的天数计算(比如考虑闰年、不同月份的天数差异),可以用dateutil.relativedelta模块来解析ISO间隔字符串,不过你的简化计算已经能满足大部分场景需求啦。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 18:42:43