【问题标题】:Week of a month pandas大熊猫一周
【发布时间】:2014-10-04 14:54:36
【问题描述】:

我正在尝试以一个月为一周,有些月可能有 4 周,有些可能有 5 周。 对于每个日期,我想知道它属于哪一周。我最感兴趣的是这个月的最后一周。

data = pd.DataFrame(pd.date_range(' 1/ 1/ 2000', periods = 100, freq ='D'))

0  2000-01-01
1  2000-01-02
2  2000-01-03
3  2000-01-04
4  2000-01-05
5  2000-01-06
6  2000-01-07

【问题讨论】:

    标签: python pandas


    【解决方案1】:

    查看此answer 并决定您想要的月份中的哪一周。

    没有内置任何内容,因此您需要使用 apply 来计算它。例如,对于一个简单的“已经过去了多少个 7 天”度量。

    data['wom'] = data[0].apply(lambda d: (d.day-1) // 7 + 1)
    

    对于更复杂的(基于日历),使用该答案中的函数。

    import datetime
    import calendar
    
    def week_of_month(tgtdate):
        tgtdate = tgtdate.to_datetime()
    
        days_this_month = calendar.mdays[tgtdate.month]
        for i in range(1, days_this_month):
            d = datetime.datetime(tgtdate.year, tgtdate.month, i)
            if d.day - d.weekday() > 0:
                startdate = d
                break
        # now we canuse the modulo 7 appraoch
        return (tgtdate - startdate).days //7 + 1
    
    data['calendar_wom'] = data[0].apply(week_of_month)
    

    【讨论】:

    • 实际上这将是一个简单的增强(已经有 weekofyear),所以扩展(将在 cython 中):github.com/pydata/pandas/issues/7986,如果你想做一个拉请求。
    • 您的代码在应用于 OP 的示例代码时会导致“'Timestamp' object has no attribute 'to_datetime'”。
    • 结果也似乎不对。 91 2000-04-01 0 92 2000-04-02 0 93 2000-04-03 1 94 2000-04-04 1 -> 2000-04-03 应该是四月的第一周,而不是第二周?
    • 工作得很好,谢谢!
    【解决方案2】:

    在处理具有日期时间索引的数据帧时,我使用了下面的代码。

    import pandas as pd
    import math
    
    def add_week_of_month(df):
        df['week_in_month'] = pd.to_numeric(df.index.day/7)
        df['week_in_month'] = df['week_in_month'].apply(lambda x: math.ceil(x))
        return df
    

    如果你运行这个例子:

    df = test = pd.DataFrame({'count':['a','b','c','d','e']},
                         index = ['2018-01-01', '2018-01-08','2018-01-31','2018-02-01','2018-02-28'])
    df.index = pd.to_datetime(df.index)
    

    你应该得到以下数据帧

                   count  week_in_month
    
    2018-01-01     a              1
    2018-01-08     b              2
    2018-01-31     c              5
    2018-02-01     d              1
    2018-02-28     e              4
    

    【讨论】:

      【解决方案3】:

      TL;DR

      import pandas as pd
      
      def weekinmonth(dates):
          """Get week number in a month.
          
          Parameters: 
              dates (pd.Series): Series of dates.
          Returns: 
              pd.Series: Week number in a month.
          """
          firstday_in_month = dates - pd.to_timedelta(dates.dt.day - 1, unit='d')
          return (dates.dt.day-1 + firstday_in_month.dt.weekday) // 7 + 1
          
          
      df = pd.DataFrame(pd.date_range(' 1/ 1/ 2000', periods = 100, freq ='D'), columns=['Date'])
      weekinmonth(df['Date'])
      
      0     1
      1     1
      2     2
      3     2
      4     2
           ..
      95    2
      96    2
      97    2
      98    2
      99    2
      Name: Date, Length: 100, dtype: int64
      

      说明

      首先,计算一个月的第一天(来自这个答案:How floor a date to the first date of that month?):

      df = pd.DataFrame(pd.date_range(' 1/ 1/ 2000', periods = 100, freq ='D'), columns=['Date'])
      df['MonthFirstDay'] = df['Date'] - pd.to_timedelta(df['Date'].dt.day - 1, unit='d')
      df
      
               Date MonthFirstDay
      0  2000-01-01    2000-01-01
      1  2000-01-02    2000-01-01
      2  2000-01-03    2000-01-01
      3  2000-01-04    2000-01-01
      4  2000-01-05    2000-01-01
      ..        ...           ...
      95 2000-04-05    2000-04-01
      96 2000-04-06    2000-04-01
      97 2000-04-07    2000-04-01
      98 2000-04-08    2000-04-01
      99 2000-04-09    2000-04-01
      
      [100 rows x 2 columns]
      

      从第一天开始获取工作日:

      df['FirstWeekday'] = df['MonthFirstDay'].dt.weekday
      df
      
               Date MonthFirstDay  FirstWeekday
      0  2000-01-01    2000-01-01             5
      1  2000-01-02    2000-01-01             5
      2  2000-01-03    2000-01-01             5
      3  2000-01-04    2000-01-01             5
      4  2000-01-05    2000-01-01             5
      ..        ...           ...           ...
      95 2000-04-05    2000-04-01             5
      96 2000-04-06    2000-04-01             5
      97 2000-04-07    2000-04-01             5
      98 2000-04-08    2000-04-01             5
      99 2000-04-09    2000-04-01             5
      
      [100 rows x 3 columns]
      

      现在我可以用工作日的模计算得到一个月的周数:

      1. 通过df['Date'].dt.day 获取月份中的某天,并确保由于模计算df['Date'].dt.day-1 以0 开头。
      2. 添加工作日编号以确保从一个月的哪一天开始+ df['FirstWeekday']
      3. 请安全地使用一周中 7 天的整数除法,然后从 1 // 7 + 1 开始在月份中添加 1 开始周数。

      整模计算:

      df['WeekInMonth'] = (df['Date'].dt.day-1 + df['FirstWeekday']) // 7 + 1
      df
      
               Date MonthFirstDay  FirstWeekday  WeekInMonth
      0  2000-01-01    2000-01-01             5            1
      1  2000-01-02    2000-01-01             5            1
      2  2000-01-03    2000-01-01             5            2
      3  2000-01-04    2000-01-01             5            2
      4  2000-01-05    2000-01-01             5            2
      ..        ...           ...           ...          ...
      95 2000-04-05    2000-04-01             5            2
      96 2000-04-06    2000-04-01             5            2
      97 2000-04-07    2000-04-01             5            2
      98 2000-04-08    2000-04-01             5            2
      99 2000-04-09    2000-04-01             5            2
      
      [100 rows x 4 columns]
      

      【讨论】:

        【解决方案4】:

        这似乎对我有用

        df_dates = pd.DataFrame({'date':pd.bdate_range(df['date'].min(),df['date'].max())})
        df_dates_tues = df_dates[df_dates['date'].dt.weekday==2].copy()
        df_dates_tues['week']=np.mod(df_dates_tues['date'].dt.strftime('%W').astype(int),4)
        

        【讨论】:

          【解决方案5】:

          你可以减去当前周和当月第一天的周,但需要额外的逻辑来处理一年中的第一周和最后一周:

          def get_week(s):
              prev_week = (s - pd.to_timedelta(7, unit='d')).dt.week
              return (
                  s.dt.week
                  .where((s.dt.month != 1) | (s.dt.week < 50), 0)
                  .where((s.dt.month != 12) | (s.dt.week > 1), prev_week + 1)
              )
          
          def get_week_of_month(s):
              first_day_of_month = s - pd.to_timedelta(s.dt.day - 1, unit='d')
              first_week_of_month = get_week(first_day_of_month)
              current_week = get_week(s)
              return  current_week - first_week_of_month
          

          【讨论】:

            【解决方案6】:

            我获取一个月中星期几的逻辑取决于一年中的星期几。

            1. 在数据框中计算一年中的第一周
            2. 如果月份不为 1,则获取上一年的最大周月份,如果月份为 1,则返回一年中的一周
            3. 如果上个月的最大周数等于当前月的最大周数
            4. 然后返回当年当前周与上个月最大周月的差值加 1
            5. Else 返回当年当前周与上个月最大周月的差值

            希望这可以解决上面使用的多个逻辑有限制的问题,下面的函数也是如此。这里的 Temp 是使用 dt.weekofyear 计算一年中哪一周的数据框

            def weekofmonth(dt1):
                if dt1.month == 1:
                    return (dt1.weekofyear)
                else:
                    pmth = dt1.month - 1
                    year = dt1.year
                    pmmaxweek = temp[(temp['timestamp_utc'].dt.month == pmth) & (temp['timestamp_utc'].dt.year == year)]['timestamp_utc'].dt.weekofyear.max()
                    if dt1.weekofyear == pmmaxweek:
                        return (dt1.weekofyear - pmmaxweek + 1)
                    else:
                        return (dt1.weekofyear - pmmaxweek)
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2021-06-14
              • 2015-12-03
              • 1970-01-01
              • 2021-07-03
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2019-12-12
              相关资源
              最近更新 更多