在 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
只排序第二层
将groupby
与group_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
[编辑以提供更好的工作示例数据]
假设我在 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
只排序第二层
将groupby
与group_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