Pandas 在 groupby 之后对每组采样不同的分数

Pandas sample different fractions for each group after groupby

import pandas as pd

df = pd.DataFrame({'a': [1,2,3,4,5,6,7],
                   'b': [1,1,1,0,0,0,0],
})

grouped = df.groupby('b')

现在从每个组中抽样,例如,我想从组 b = 1 中抽取 30%,从组 b = 0 中抽取 20%。我该怎么做? 如果我想为某个团体提供 150%,我可以这样做吗?

您可以从 GroupBy 对象中获取 DataFrame,例如grouped.get_group(0)。如果你想从中取样,你可以使用 .sample 方法。例如 grouped.get_group(0).sample(frac=0.2) 给出:

   a
5  6

对于您给出的示例,两个样本将只给出一个元素,因为这些组有 4 个和 3 个元素,并且 0.2*4 = 0.80.3*3 = 0.9 都舍入为 1。

您可以动态 return 一个随机样本数据帧,每组定义不同的样本百分比。您可以通过传递 replace=True 使用低于 100% (参见示例 1) 和高于 100% (参见示例 2) 的百分比来执行此操作:

  1. 使用 np.select,创建一个新列 c,其中 returns 每组的行数根据 20%、40% 等百分比随机抽样你设置的。
  2. 从那里,您可以根据这些百分比条件 sample 每组 x 行。从这些行中,return 行中的 .index 行并筛选出具有 .loc 的行以及列 'a','b'。代码 grouped.apply(lambda x: x['c'].sample(frac=x['c'].iloc[0])) 创建了您要查找的输出的多索引系列,但它需要进行一些清理。这就是为什么对我来说更容易获取 .index 并使用 .loc 过滤原始数据帧,而不是尝试清理混乱的多索引系列。

grouped = df.groupby('b', group_keys=False)
df['c'] = np.select([df['b'].eq(0), df['b'].eq(1)], [0.4, 0.2])
df.loc[grouped.apply(lambda x: x['c'].sample(frac=x['c'].iloc[0])).index, ['a','b']]
Out[1]: 
   a  b
6  7  0
8  9  0
3  4  1

如果您想 return 使用现有 c 值的副本进行更大的随机样本,只需传递 replace=True。然后,进行一些清理以获得输出。

grouped = df.groupby('b', group_keys=False)
v = df['b'].value_counts()
df['c'] = np.select([df['b'].eq(0), df['b'].eq(1)],
                    [int(v.loc[0] * 1.2), int(v.loc[1] * 2)]) #frac parameter doesn't work with sample when frac > 1, so we have to calcualte the integer value for number of rows to be sampled.
(grouped.apply(lambda x: x['b'].sample(x['c'].iloc[0], replace=True))
        .reset_index()
        .rename({'index' : 'a'}, axis=1))
Out[2]: 
    a  b
0   7  0
1   8  0
2   9  0
3   7  0
4   7  0
5   8  0
6   1  1
7   3  1
8   3  1
9   1  1
10  0  1
11  0  1
12  4  1
13  2  1
14  3  1
15  0  1