【问题标题】:How to count pandas datetime months by continuous season如何按连续季节计算熊猫日期时间月
【发布时间】:2021-01-30 19:21:26
【问题描述】:

我有一个大的时间序列数据框。该列已被格式化为日期时间。比如

2017-10-06T00:00:00+00:00
2020-04-29 00:00:00+00:00

我想绘制每个季节的样本数。比如下面这样。这些值是该季节的样本计数。

1997 Winter 4
1997 Spring 8
1997 Summer 8
...
2020 Winter 32

我确实进行了一些搜索,并意识到我可以创建一个字典来将月份转换为季节。然而,自“真正的冬季”以来最棘手的部分包含两年的数据。例如,1997 年冬季实际上应该包含 1997 年 12 月、1998 年 1 月和 1998 年 2 月。

请注意,我希望将“1997 年一月,1997 年二月”排除在 1997 年冬季之外,因为它们是“1996 年冬季”。

我想知道最有效的方法是什么?它不必命名为'1997 Winter',只要计数从头到尾连续,任何索引都应该对我有用。

非常感谢!

【问题讨论】:

    标签: python pandas


    【解决方案1】:

    有一个快速的方法来解决它,但它不是很正统...... 您创建一个“季节”列,并使用 np.where() 分配季节。一开始,你说前 3 个月是冬天,下一个 3 个月是春天,依此类推。然后,在列上应用 shift(-1) 以将其向后移动一行。然后,你已经有了你的季节(只需填写 las nan)。然后,您可以以一种懒惰的方式解决您的问题。 如果您对代码不满意,请告诉我,我会修改它。

    编辑:

    我假设日期在索引中。如果没有,您应该应用 dt.month 而不是 .month。 我将其分解以使其清楚

    _condtion_spring = (df.index.month>=4)&(df.index.month<=6)
    _condition_summer = (df.index.month>7)&(df.index.month<=9)
    _condition_automn = (df.index.month>=10)@(df.index.month<=12)
    df['Season'] = np.where(_condition_winter,'Winter',np.where(_condtion_spring,'Spring',np.where(_condition_summer,'Summer',np.where(_condition_automn,'Automn',np.nan))))
    df['Season'] = df['Season'].shift(-1).fillna(method='ffill')
    

    编辑 2:

    这里有一个完整的例子:

    dates = pd.date_range("1983-09-01","1985-12-31",freq="1M")
    df = pd.DataFrame(np.random.randint(100, 200,size=28)/100,index =dates,columns=["Sample"])
    df = df.sort_index()
    _condition_winter = (df.index.month>=1)&(df.index.month<=3)
    _condtion_spring = (df.index.month>=4)&(df.index.month<=6)
    _condition_summer = (df.index.month>=7)&(df.index.month<=9)
    _condition_automn = (df.index.month>=10)@(df.index.month<=12)
    df['Season'] = np.where(_condition_winter,'Winter',np.where(_condtion_spring,'Spring',np.where(_condition_summer,'Summer',np.where(_condition_automn,'Automn',np.nan))))
    df['Season'] = df['Season']+'_'+df.index.strftime(date_format='%Y')
    df['Season'] = df['Season'].shift(-1).fillna(method='ffill')
    print('Sample for winter 1984 = ',df[df.Season=='Winter_1984'].Sample.sum())
    

    编辑 3:

    如果您在同一个月有几行,这里是完整的示例:

    #### Build our df
    #### This is just to make it clear that we will have 2 rows of each month. It could be more or less.
    dates = pd.date_range("1983-09-01","1985-12-31",freq="1M")
    dates2 = pd.date_range("1983-09-01","1985-12-31",freq="1M")
    df1 = pd.DataFrame(np.random.randint(100, 200,size=28)/100,index =dates,columns=["Sample"]).append(pd.DataFrame(np.random.randint(100, 200,size=28)/100,index =dates2,columns=["Sample"]))
    df1 = df1.sort_index()
    #### Now, to keep it clear, even if we could do faster, let's do a dataframe with 1 row per month with total of sample each time
    df = pd.DataFrame()
    df = df1.groupby(df1.index).sum()
    #### Let's sort by date to be sure that it won't me messy
    #### If you've got a 'Date' column and not the index, apply a .sort_values('Date') instead of sort_index
    df = df.sort_index()
    #### If youve got a 'Date' column, it will be df.Date.dt.month istead of df.index.month
    _condition_winter = (df.index.month>=1)&(df.index.month<=3)
    _condtion_spring = (df.index.month>=4)&(df.index.month<=6)
    _condition_summer = (df.index.month>=7)&(df.index.month<=9)
    _condition_automn = (df.index.month>=10)@(df.index.month<=12)
    df['Season'] = np.where(_condition_winter,'Winter',np.where(_condtion_spring,'Spring',np.where(_condition_summer,'Summer',np.where(_condition_automn,'Automn',np.nan))))
    df['Season'] = df['Season']+'_'+df.index.strftime(date_format='%Y')
    df['Season'] = df['Season'].shift(-1).fillna(method='ffill')
    print('Sample for winter 1984 = ',df[df.Season=='Winter_1984'].Sample.sum())
    

    【讨论】:

    • 是的,你能提供代码吗?我相信它也会对其他人有所帮助!
    • 或者我认为还有另一种方法,在 1 个月后转移每个样本。然后我可以根据季度对它们进行分组。你怎么看?
    • 我已经编辑过了。告诉我这是不是你的想法。
    • 嗨,在使用该代码之前,我是否需要按日期时间对 DataFrame 进行排序?如果某个月份没有样品定位,会不会出问题?
    • @Xudong,我不确定你的问题。我编辑了一个完整的例子。我假设 1984 年冬天是从 1983 年 12 月到 1984 年 2 月。这是你想要的吗?例如编辑 1984 年冬季的样本总数?
    【解决方案2】:

    我认为你应该创建一个 lambda 函数,根据月份和日期的值选择正确的季节。

    def seasons(date):
        m = date.month
        d = date.day
        season=None
        if (3==m and d>=21) or m==4 or m==5 or (m==6 and 20<=d):
            season = 'spring'
        elif (6==m and d>=21 ) or m==7 or m==8 or (m==9 and 20<=d):
            season = 'sommer'
        elif (9==m and d>=21 ) or m==10 or m==11 or (m==12 and 20<=d):
            season = 'autumn'
        elif (12==m and d>=21 ) or m==1 or m==2 or (m==3 and 20<=d):
            season = 'winter'
        return season
    
    df['season'] = df.apply(lambda x: seasons(x['date']), axis=1)
    

    请注意,季节也是按天选择的。因为冬季是从 12 月 21 日到 3 月 20 日,以此类推。

    【讨论】:

      【解决方案3】:

      我找到了另一种解决方法。所以我想把它留在这里。

      1. 将所有样本移到 1 个月后
      2. 按月附加季节
      3. 然后您可以以任何您想要的方式处理样本。例如

      如果你编写它,它可能看起来像这样:

      from dateutil.relativedelta import *
          
      df.loc[:, 'shift_time'] = df.apply(lambda x: x['real_datetime'] + relativedelta(months=+1), axis=1)
      df.loc[:, 'season'] = df['shift_time'].dt.quarter
      grouped = df.groupby([(df['shift_time'].dt.year), (df['season'])]).count()
      

      【讨论】:

        猜你喜欢
        • 2020-06-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-08-22
        • 2019-02-16
        • 2021-12-06
        • 2019-03-04
        • 1970-01-01
        相关资源
        最近更新 更多