在 pandas 中使用 groupby 索引的方法

Way to use groupby over indices in pandas

[编辑以提供更好的工作示例数据]

假设我在 pandas 中有一个面板,每个 id_var 有多个 time_vars。例如,假设数据包含一个状态变量和一个年份变量:

                   var1      var2
stcode year                      
WY     1996-01-01    14  0.000059
       1995-01-01     8  0.000059
       1994-01-01    21  0.000182
       1993-01-01    17  0.000063
       1992-01-01     9  0.000000
AK     1964-01-01    11  0.000213
       1965-01-01     6  0.000100
       1966-01-01    10  0.000189
       1967-01-01     9  0.000267
       1968-01-01     9  0.000084

有没有办法使用 pd.groupby 并在多索引的 year 级别上作为对象进行操作,或者我是否受限于 groupby 变量中定义的列?

举个例子,假设我想检查日期是否排序,但我只关心 year 级别是否排序,而不关心 stcode 级别。我目前会这样实现:

# unsetting year from the index, so that I can groupby the remaining level and 
# check if year is monotonically increasing
df.reset_index('year').groupby('stcode').year.is_monotonic_increasing

这个returns(如你所见):

stcode
AK     True
WY    False
Name: year, dtype: bool

但是,以这种方式取消设置索引似乎非常低效。有没有通用的方法来做类似的事情:

df.groupby(level=0)[ -- the other level -- ].apply( -- operation -- )

类似地,有没有一种方法可以按第二级排序而忽略第一级?在这个例子中,我可能需要在每个 stcode 块中排序的时间变量来执行与时间相关的操作,比如移位,但我不关心外层是按字母顺序还是数字顺序排序。换句话说,这最终会像:

                   var1      var2
stcode year                      
WY     1992-01-01     9  0.000000
       1993-01-01    17  0.000063
       1994-01-01    21  0.000182
       1995-01-01     8  0.000059
       1996-01-01    14  0.000059
AK     1964-01-01    11  0.000213
       1965-01-01     6  0.000100
       1966-01-01    10  0.000189
       1967-01-01     9  0.000267
       1968-01-01     9  0.000084

这是原始 DataFrame 的 dict

{'var1': {('WY', Timestamp('1996-01-01 00:00:00')): 14,
  ('WY', Timestamp('1995-01-01 00:00:00')): 8,
  ('WY', Timestamp('1994-01-01 00:00:00')): 21,
  ('WY', Timestamp('1993-01-01 00:00:00')): 17,
  ('WY', Timestamp('1992-01-01 00:00:00')): 9,
  ('AK', Timestamp('1964-01-01 00:00:00')): 11,
  ('AK', Timestamp('1965-01-01 00:00:00')): 6,
  ('AK', Timestamp('1966-01-01 00:00:00')): 10,
  ('AK', Timestamp('1967-01-01 00:00:00')): 9,
  ('AK', Timestamp('1968-01-01 00:00:00')): 9},
 'var2': {('WY', Timestamp('1996-01-01 00:00:00')): 5.855486597283743e-05,
  ('WY', Timestamp('1995-01-01 00:00:00')): 5.91261159570422e-05,
  ('WY', Timestamp('1994-01-01 00:00:00')): 0.00018243736121803522,
  ('WY', Timestamp('1993-01-01 00:00:00')): 6.34477473795414e-05,
  ('WY', Timestamp('1992-01-01 00:00:00')): 0.0,
  ('AK', Timestamp('1964-01-01 00:00:00')): 0.0002131750516127795,
  ('AK', Timestamp('1965-01-01 00:00:00')): 0.00010040206689154729,
  ('AK', Timestamp('1966-01-01 00:00:00')): 0.0001891511055873707,
  ('AK', Timestamp('1967-01-01 00:00:00')): 0.00026726152282208204,
  ('AK', Timestamp('1968-01-01 00:00:00')): 8.391729352297261e-05}}

我个人认为您使用的方法简洁合理。

但是,您可以使用:

df.groupby(level=0).apply(lambda g: g.index.is_monotonic_increasing)

因为第一层必然是每组单调递增的。

或者,如果需要(此处不需要),要真正降低第一级:

df.groupby(level=0).apply(lambda g: g.index.droplevel(0).is_monotonic_increasing)

输出:

AK     True
WY    False
dtype: bool

只排序第二层

groupbygroup_keys=False, sort=False一起使用:

df.groupby(level=0, group_keys=False, sort=False).apply(lambda g: g.sort_index())

输出:

               var1      var2
WY 1992-01-01     9  0.000000
   1993-01-01    17  0.000063
   1994-01-01    21  0.000182
   1995-01-01     8  0.000059
   1996-01-01    14  0.000059
AK 1964-01-01    11  0.000213
   1965-01-01     6  0.000100
   1966-01-01    10  0.000189
   1967-01-01     9  0.000267
   1968-01-01     9  0.000084