计算以周日为第一天的周数

Python3.8

Python3.8

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

难点

python的datetime库中虽然有isocalendar()方法可以根据给定的日期直接计算年份、周数、星期几,但是它计算出的周数和星期几是以周一为每周的开始的。如果要以周日为一周的开始的话,就无法用这个方法直接计算得出。

但是除了要以周日为一周的开始,周数的计算还要符合ISO年的规定,即某周到底属于上一年还是这一年,要根据这周的周四属于哪一年来定,这样有些年份 有53周,有些年份有52周。所以对于给定的日期,也不能简单地加计算它与当年1月1日的差然后除以7,来计算周数。因为当年的1月1日在周数计算中,不一定会属于当年。
所以计算以周日为第一天的周数主要有两个难点:

  1. 可以计算周数的python库中的方法不是以周日为一周的开始的
  2. 计算出的周数还必须符合ISO年的规定,即每年的第一周的周四必须属于当年。

我写了两个方法,第一个方法比较机械,第二个方法更普适一点。大家可以直接看第二种方法,第一种方法我放这里更多的是自己做个记录。

第一种方法

这种方法比较机械,就是把有53周的年份都单独拎出来处理,需要人工标记这些年份。
虽然ISO周数计算以某周的周四是否属于某年而确定这周是上一年的最后一周还是下一年的第一周。但是这里的方法关注的是周日。因为借用isocalendar()的方法,要计算以周日为一周的开始的周数,大部分只需要将isocalendar()方法计算出的周数中周日的周数+1即可。但是对于靠近年末或年初的周日,就要考虑这个+1到底是加到这年的年末,还是要变为下一年的第一周。只要我们提前知道哪些年是有53周,哪些年是只有52周的,那么我们就可以根据iso周数来判断这个周日到底要怎么算。如果它的iso周数是这一年的最后一周(第53或52周),那么它就要算到下一年的第一周;如果不是,那就还算是当年的。

# df数据框中的'日期'列就是需要计算周数的所有日期字符串
def cal_week(df):
	 # 将日期字符串转换成datetime类型的日期数据
    df['日期'] = pd.to_datetime(df['日期'],
                                format='%Y.%m.%d',
                                errors='raise')
    # 借用isocalendar方法计算年份和ISO周数
    df['年份'] = df['日期'].dt.isocalendar().year
    df['周数'] = df['日期'].dt.isocalendar().week

	  # 循环,再根据每个给定的日期对上面计算出的年份和周数做修改
    for row in range(df.shape[0]):
        weekday = df['日期'][row].isocalendar().weekday
        week = df['日期'][row].isocalendar().week
        year = df['日期'][row].isocalendar().year
        if year in [2015, 2020]: # 人工标记有53周的年份
        		# 如果是周日,且iso周数不是53周,那么这个周日的周数+1
            if weekday == 7 and week <= 52:
                df['周数'][row] += 1
            # 如果是周日,但iso周数是53周,那么就算作下一年的第一周
            elif weekday == 7 and week == 53:
                df['周数'][row] = 1
                df['年份'][row] += 1
        else: # 没有53周的年份
            # 如果是周日,且不是第52周,那么这个周日的周数+1
            if weekday == 7 and week < 52:
                df['周数'][row] += 1
            # 如果是周日,且是第52周,那么这个周日算作下一年的第一周
            elif weekday ==7 and week == 52:
                df['周数'][row] = 1
                df['年份'][row] += 1
    return df

第二种方法

这种方法不用标记哪些年有53周,它直接将原来的日期都加一天,那原来的星期一就变成了星期二,一周的第一天就变成了第二天;而原来的周日就变成了周一,一周的最后一天变成了第一天。然后再用isocalendar()方法去计算周数,就能够计算出以周日为每周开始的符合ISO年的规定的周数了。
但是这个方法要考虑到怎么应用到数据框中,因为这里不仅要计算某一个日期的周数,而是数据框中的日期列中所有日期的周数。

# 对某一个日期计算年份和周数
def cal_year_weeks(some_date: datetime) -> list[int | Any] | list[Any]:
    # 将每个日期都往后移一天
    adjusted_date = some_date + timedelta(days=1)
    # 利用iso方法计算年份和周数
    iso_year, iso_week, iso_day = adjusted_date.isocalendar()
    return [iso_year, iso_week]

# 将上面的方法应用到日期列中的每个日期上
def date_parser(df: pd.DataFrame, date_col : str = '日期') -> pd.DataFrame:
	 # 将日期字符串转换成datetime类型的日期数据
	 df['日期'] = pd.to_datetime(df['日期'],
                                format='%Y.%m.%d',
                                errors='raise')
    # 用map方法将cal_year_week函数应用到日期列中的每一个日期上
    result = df[date_col].map(cal_year_weeks)
    # 由于cal_year_week函数返回的是包含年份和周数两个元素的列表,所以要分别将它们放到对应的列
    df.loc[:, '年份'] = [ x[0] for x in result ]
    df.loc[:, '周数'] = [ x[1] for x in result ]
    return df

您可能感兴趣的与本文相关的镜像

Python3.8

Python3.8

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值