我看到了这个问题的一个变体,要求将每个组的前n行保留在pandas数据框中,而解决方案在这里Pandas get topmost n records within each group使用n作为绝对数字而不是百分比。但是,在我的数据框中,每个组中都有不同数量的行,我想保留每个组中前n%个行。我将如何解决这个问题?
答案 0 :(得分:1)
在groupby
之前,您可以构造一系列布尔标志和过滤器。首先,让我们创建一个示例数据框,并查看第一个系列中每个唯一值的行数:
np.random.seed(0)
df = pd.DataFrame(np.random.randint(0, 2, (10, 3)))
print(df[0].value_counts())
0 6
1 4
Name: 0, dtype: int64
然后定义一个分数,例如低于50%,并构造一个布尔级数进行过滤:
n = 0.5
g = df.groupby(0)
flags = (g.cumcount() + 1) <= g[1].transform('size') * n
然后应用条件,将索引设置为第一个序列,并(如果需要)对索引进行排序:
df = df.loc[flags].set_index(0).sort_index()
print(df)
1 2
0
0 1 1
0 1 1
0 1 0
1 1 1
1 1 0
如您所见,结果数据帧仅具有3个0
索引和2个1
索引,在每种情况下均为原始数据帧中数字的一半。
答案 1 :(得分:1)
这是您提到的帖子中某些答案的另一种选择
首先,这里是一个快速功能,可以向上或向下取整。如果我们希望数据框的前30%的行长8行,那么我们将尝试使用2.4行。因此,我们将需要向上或向下取整。
我的首选是四舍五入。这是因为,对于eaxample,如果我们要占据50%的行,但是只有一组只有一行,那么我们仍然会保留那一行。我将其分开放置,以便您可以根据需要更改舍入
def round_func(x, up=True):
'''Function to round up or round down a float'''
if up:
return int(x+1)
else:
return int(x)
接下来,我制作一个要使用的数据框,并将参数p
设置为每个组中应保留的行的分数。一切都遵循了,我已经对其进行了评论,希望您可以遵循。
import pandas as pd
df = pd.DataFrame({'id':[1,1,1,2,2,2,2,3,4],'value':[1,2,3,1,2,3,4,1,1]})
p = 0.30 # top fraction to keep. Currently set to 80%
df_top = df.groupby('id').apply( # group by the ids
lambda x: x.reset_index()['value'].nlargest( # in each group take the top rows by column 'value'
round_func(x.count().max()*p))) # calculate how many to keep from each group
df_top = df_top.reset_index().drop('level_1', axis=1) # make the dataframe nice again
df看起来像这样
id value
0 1 1
1 1 2
2 1 3
3 2 1
4 2 2
5 2 3
6 2 4
7 3 1
8 4 1
df_top看起来像这样
id value
0 1 3
1 2 4
2 2 3
3 3 1
4 4 1