Multiindex pandas groupby + aggregate,保留全索引
Multiindex pandas groupby + aggregate, keep full index
我有一个两级层次索引整数序列。
>> s
id1 id2
1 a 100
b 10
c 9
2 a 2000
3 a 5
b 10
c 15
d 20
...
我想按 id1 和 select 最大值分组,但结果中有 full 索引。我尝试了以下方法:
>> s.groupby(level=0).aggregate(np.max)
id1
1 100
2 2000
3 20
但结果仅由 id1 索引。我希望我的输出看起来像这样:
id1 id2
1 a 100
2 a 2000
3 d 20
这里提出了一个相关但更复杂的问题:
Multiindexed Pandas groupby, ignore a level?
正如它所说,答案有点像黑客。
有人知道更好的解决方案吗?如果不是,那么 id2 的每个值都是唯一的特殊情况呢?
在 groupby 之后 select 整行的一种方法是使用 groupby/transform
构建一个布尔掩码,然后使用掩码 select 来自 [=15= 的整行]:
In [110]: s[s.groupby(level=0).transform(lambda x: x == x.max()).astype(bool)]
Out[110]:
id1 id2
1 a 100
2 a 2000
3 d 20
Name: s, dtype: int64
另一种在某些情况下更快的方法——例如当有很多组时——是将最大值 m
与 [=15= 中的值一起合并到 DataFrame 中],然后 select 行基于 m
和 s
之间的相等性:
def using_merge(s):
m = s.groupby(level=0).agg(np.max)
df = s.reset_index(['id2'])
df['m'] = m
result = df.loc[df['s']==df['m']]
del result['m']
result = result.set_index(['id2'], append=True)
return result['s']
这是一个显示 using_merge
的示例,虽然更复杂,但可能比 using_transform
更快:
import numpy as np
import pandas as pd
def using_transform(s):
return s[s.groupby(level=0).transform(lambda x: x == x.max()).astype(bool)]
N = 10**5
id1 = np.random.randint(100, size=N)
id2 = np.random.choice(list('abcd'), size=N)
index = pd.MultiIndex.from_arrays([id1, id2])
ss = pd.Series(np.random.randint(100, size=N), index=index)
ss.index.names = ['id1', 'id2']
ss.name = 's'
使用 IPython 的 %timeit
函数对这两个函数进行计时得到:
In [121]: %timeit using_merge(ss)
100 loops, best of 3: 12.8 ms per loop
In [122]: %timeit using_transform(ss)
10 loops, best of 3: 45 ms per loop
我有一个两级层次索引整数序列。
>> s
id1 id2
1 a 100
b 10
c 9
2 a 2000
3 a 5
b 10
c 15
d 20
...
我想按 id1 和 select 最大值分组,但结果中有 full 索引。我尝试了以下方法:
>> s.groupby(level=0).aggregate(np.max)
id1
1 100
2 2000
3 20
但结果仅由 id1 索引。我希望我的输出看起来像这样:
id1 id2
1 a 100
2 a 2000
3 d 20
这里提出了一个相关但更复杂的问题: Multiindexed Pandas groupby, ignore a level? 正如它所说,答案有点像黑客。
有人知道更好的解决方案吗?如果不是,那么 id2 的每个值都是唯一的特殊情况呢?
在 groupby 之后 select 整行的一种方法是使用 groupby/transform
构建一个布尔掩码,然后使用掩码 select 来自 [=15= 的整行]:
In [110]: s[s.groupby(level=0).transform(lambda x: x == x.max()).astype(bool)]
Out[110]:
id1 id2
1 a 100
2 a 2000
3 d 20
Name: s, dtype: int64
另一种在某些情况下更快的方法——例如当有很多组时——是将最大值 m
与 [=15= 中的值一起合并到 DataFrame 中],然后 select 行基于 m
和 s
之间的相等性:
def using_merge(s):
m = s.groupby(level=0).agg(np.max)
df = s.reset_index(['id2'])
df['m'] = m
result = df.loc[df['s']==df['m']]
del result['m']
result = result.set_index(['id2'], append=True)
return result['s']
这是一个显示 using_merge
的示例,虽然更复杂,但可能比 using_transform
更快:
import numpy as np
import pandas as pd
def using_transform(s):
return s[s.groupby(level=0).transform(lambda x: x == x.max()).astype(bool)]
N = 10**5
id1 = np.random.randint(100, size=N)
id2 = np.random.choice(list('abcd'), size=N)
index = pd.MultiIndex.from_arrays([id1, id2])
ss = pd.Series(np.random.randint(100, size=N), index=index)
ss.index.names = ['id1', 'id2']
ss.name = 's'
使用 IPython 的 %timeit
函数对这两个函数进行计时得到:
In [121]: %timeit using_merge(ss)
100 loops, best of 3: 12.8 ms per loop
In [122]: %timeit using_transform(ss)
10 loops, best of 3: 45 ms per loop