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.8
和 0.3*3 = 0.9
都舍入为 1。
您可以动态 return 一个随机样本数据帧,每组定义不同的样本百分比。您可以通过传递 replace=True
使用低于 100% (参见示例 1) 和高于 100% (参见示例 2) 的百分比来执行此操作:
- 使用
np.select
,创建一个新列 c
,其中 returns 每组的行数根据 20%、40% 等百分比随机抽样你设置的。
- 从那里,您可以根据这些百分比条件
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
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.8
和 0.3*3 = 0.9
都舍入为 1。
您可以动态 return 一个随机样本数据帧,每组定义不同的样本百分比。您可以通过传递 replace=True
使用低于 100% (参见示例 1) 和高于 100% (参见示例 2) 的百分比来执行此操作:
- 使用
np.select
,创建一个新列c
,其中 returns 每组的行数根据 20%、40% 等百分比随机抽样你设置的。 - 从那里,您可以根据这些百分比条件
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