按月份对组进行分组

3

假设我有一个pd.DataFrame,其中索引由pd.DateTimeIndex给出。

现在我想按月份分组成对,即获取所有成对数据。也就是说,我想要一个组,其中包含(日期在(一月、二月)之间),然后是(日期在(二月、三月)之间)等等。自然的方式应该是pd.TimeGrouper,但我找不到使其工作的方法。

这是一个样本数据集。请注意每个月有多个观测值(数字随时间变化而异),因此pd.rolling()pd.rolling_apply()似乎不是有效的替代方案:

            year  month          cpsidp
date                                   
2000-01-01  2000      1  19981003169301
2000-02-01  2000      2  20000200000101
2000-02-01  2000      2  20000200000102
2000-02-01  2000      2  20000200000103
2000-02-01  2000      2  20000200000104
2000-02-01  2000      2  20000200000105
2000-03-01  2000      3  19981203124802
2000-04-01  2000      4  20000400000101
2000-05-01  2000      5  19990200854301
2000-06-01  2000      6  19990300018604
2000-07-01  2000      7  20000400000101
2000-08-01  2000      8  19990502683801
2000-09-01  2000      9  19990600006901
2000-10-01  2000     10  19990700006501
2000-11-01  2000     11  19990800083001
2000-12-01  2000     12  19991100000301
2001-01-01  2001      1  19991100000301
2001-02-01  2001      2  19991100002701
2001-03-01  2001      3  20000205949101
2001-04-01  2001      4  20010100107701
2001-05-01  2001      5  20000204516501
2001-06-01  2001      6  20000300112801
2001-07-01  2001      7  20000400000101
2001-08-01  2001      8  20000505217801

以下是我用非pandas和非花哨的方式创建组的方法:

    dates = df.index.unique()
    for i, date in enumerate(dates):
        if i == len(dates) - 1:
            # last group: no next-group, break
            break
        date1, date2 = date, dates[i+1]
        group = pd.concat((df.loc[date1], df.loc[date2]), axis=0)
        print(group)

1
那么像 df.groupby(pd.TimeGrouper(freq='2M')).mean() 这样的东西不是你需要的吗? - MaxU - stand with Ukraine
@MaxU 不行,因为这会给我 (一月,二月)(三月,四月) - 而不是 (一月,二月)(二月,三月)(三月,四月) - FooBar
1
你能提供一个小的数据集样本以及期望的数据集吗? - MaxU - stand with Ukraine
2个回答

3
试试这个:
In [171]: (df.assign(m1=df.index.year*10**2+df.index.month, m2=df.index.year*10**2+df.index.month+1)
     ...:    .groupby(['m1', 'm2'])
     ...:    .agg({'month':['min','max','size']})
     ...: )
     ...:
Out[171]:
              month
                min max size
m1     m2
200001 200002     1   1    1
200002 200003     2   2    5
200003 200004     3   3    1
200004 200005     4   4    1
200005 200006     5   5    1
200006 200007     6   6    1
200007 200008     7   7    1
200008 200009     8   8    1
200009 200010     9   9    1
200010 200011    10  10    1
200011 200012    11  11    1
200012 200013    12  12    1
200101 200102     1   1    1
200102 200103     2   2    1
200103 200104     3   3    1
200104 200105     4   4    1
200105 200106     5   5    1
200106 200107     6   6    1
200107 200108     7   7    1
200108 200109     8   8    1

抱歉,我应该表达得更清楚。每个月可能有多个观察结果。 - FooBar
当每个月有多个观测值时,此方法无效。 - FooBar
@FooBar,我已经更新了我的答案 - 这是你需要的吗?我不确定 - 对于缺失的月份会如何处理... - MaxU - stand with Ukraine

3
很遗憾rolling('2M')无法使用。无论如何,您不能使用rolling(2)的主要原因是每个月有多个观测值。根据您想要如何按月对成对数据聚合,您可以首先聚合每个月(每月一个观测值),然后使用rolling(2)
df.groupby(pd.TimeGrouper('M')).first().rolling(2).mean()

enter image description here


这对于像'max''min''sum''count''size''first''last'这样的聚合统计数据非常有效。

'mean''std'等需要特别注意。例如,您需要使用'sum''count'来计算'mean''std',但这是可行的。


我能在rolling_apply中使用stack吗? - FooBar
@FooBar 是的。如果您提供更多具体信息,我们可以直接回答您的问题。现在,我们正在猜测您想要什么。您希望最终输出的样子是什么?如果您有答案,请编辑您的问题以反映它。 - piRSquared
这是一个有趣的想法! - MaxU - stand with Ukraine
我有一些复杂的事情要为每个组做,因此我在问题中询问一种分组数据的方法,以便我可以对分组应用任何想要的函数。 - FooBar
那么@MaxU的答案更为恰当。 - piRSquared

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接