在 pandas 数据帧中对多个 class 训练示例(行)进行过采样和欠采样以指定值
Over and under sample multi-class training examples (rows) in a pandas dataframe to specified values
我想使多 class pandas 数据帧更加平衡以进行训练。我的训练集的简化版本如下所示:
不平衡数据帧:class 0、1 和 2 的计数分别为 7、3 和 1
animal class
0 dog1 0
1 dog2 0
2 dog3 0
3 dog4 0
4 dog5 0
5 dog6 0
6 dog7 0
7 cat1 1
8 cat2 1
9 cat3 1
10 fish1 2
我用代码做了这个:
import pandas as pd
data = {'animal': ['dog1', 'dog2', 'dog3', 'dog4','dog5', 'dog6', 'dog7', 'cat1','cat2', 'cat3', 'fish1'], 'class': [0,0,0,0,0,0,0,1,1,1,2]}
df = pd.DataFrame(data)
现在我想对大多数 class(es) 随机抽样不足,并随机对少数 class(es) 抽样到每个 class 的指定值以获得更多平衡数据框。
问题是我可以在网上找到的所有 pandas 教程或关于此主题的 Whosebug 上的其他问题都涉及随机对少数 class 抽样到多数 class(例如:)或随机抽样多数 class 到少数 class.
的水平
由于我面临极度不平衡,我无法使多数class的大小等于少数class的大小。因此,我能找到的这些代码片段通常对我不起作用。理想情况下,我将能够指定每个 class 的样本的确切数量,然后通过过度或欠采样生成(取决于我为 class 指定的数量和样本数量class 包含)。
例如,
如果我指定:
- counts_0 = 5(是 7,所以意味着随机 under 抽样 2 个样本),
- counts_1 = 4(是 3,所以意味着随机 over 抽样 1 个样本),
- counts_2 = 3(1 表示随机 over 采样 2 个样本)
我想成为这样的人:
更平衡的数据帧:class 0、1 和 2 的计数分别为 5、4 和 3
animal class
0 dog2 0
1 dog3 0
2 dog5 0
3 dog6 0
4 dog7 0
5 cat1 1
6 cat2 1
7 cat3 1
8 cat2 1
9 fish1 2
10 fish1 2
11 fish1 2
解决这个问题的最佳方法是什么?
因为 groupby.sample
不允许 n
大于组大小,如果 replace
不是 True
但替换为 True
意味着即使在本可以下采样的组中也会发生替换。
让我们尝试使用 groupby.apply
+ sample
并有条件地为每个组启用 replace
。
创建一个字典,将每个 class 映射到样本数,并使用条件逻辑来确定是否替换:
sample_amounts = {0: 5, 1: 4, 2: 3}
s = (
df.groupby('class').apply(lambda g: g.sample(
# lookup number of samples to take
n=sample_amounts[g.name],
# enable replacement if len is less than number of samples expected
replace=len(g) < sample_amounts[g.name]
))
)
s
:
animal class
class
0 5 dog6 0
3 dog4 0
6 dog7 0
4 dog5 0
2 dog3 0
1 9 cat3 1
8 cat2 1
7 cat1 1
8 cat2 1
2 10 fish1 2
10 fish1 2
10 fish1 2
droplevel
可用于保留初始索引(如果重要):
sample_amounts = {0: 5, 1: 4, 2: 3}
s = (
df.groupby('class').apply(lambda g: g.sample(
n=sample_amounts[g.name],
replace=len(g) < sample_amounts[g.name]
))
.droplevel(0)
)
s
:
animal class
6 dog7 0
3 dog4 0
2 dog3 0
4 dog5 0
1 dog2 0
7 cat1 1
8 cat2 1
8 cat2 1
8 cat2 1
10 fish1 2
10 fish1 2
10 fish1 2
reset_index
如果索引不重要可以用:
sample_amounts = {0: 5, 1: 4, 2: 3}
s = (
df.groupby('class').apply(lambda g: g.sample(
n=sample_amounts[g.name],
replace=len(g) < sample_amounts[g.name]
))
.reset_index(drop=True)
)
s
:
animal class
0 dog1 0
1 dog2 0
2 dog4 0
3 dog5 0
4 dog3 0
5 cat3 1
6 cat2 1
7 cat1 1
8 cat3 1
9 fish1 2
10 fish1 2
11 fish1 2
我想使多 class pandas 数据帧更加平衡以进行训练。我的训练集的简化版本如下所示:
不平衡数据帧:class 0、1 和 2 的计数分别为 7、3 和 1
animal class
0 dog1 0
1 dog2 0
2 dog3 0
3 dog4 0
4 dog5 0
5 dog6 0
6 dog7 0
7 cat1 1
8 cat2 1
9 cat3 1
10 fish1 2
我用代码做了这个:
import pandas as pd
data = {'animal': ['dog1', 'dog2', 'dog3', 'dog4','dog5', 'dog6', 'dog7', 'cat1','cat2', 'cat3', 'fish1'], 'class': [0,0,0,0,0,0,0,1,1,1,2]}
df = pd.DataFrame(data)
现在我想对大多数 class(es) 随机抽样不足,并随机对少数 class(es) 抽样到每个 class 的指定值以获得更多平衡数据框。
问题是我可以在网上找到的所有 pandas 教程或关于此主题的 Whosebug 上的其他问题都涉及随机对少数 class 抽样到多数 class(例如:
由于我面临极度不平衡,我无法使多数class的大小等于少数class的大小。因此,我能找到的这些代码片段通常对我不起作用。理想情况下,我将能够指定每个 class 的样本的确切数量,然后通过过度或欠采样生成(取决于我为 class 指定的数量和样本数量class 包含)。
例如,
如果我指定:
- counts_0 = 5(是 7,所以意味着随机 under 抽样 2 个样本),
- counts_1 = 4(是 3,所以意味着随机 over 抽样 1 个样本),
- counts_2 = 3(1 表示随机 over 采样 2 个样本)
我想成为这样的人:
更平衡的数据帧:class 0、1 和 2 的计数分别为 5、4 和 3
animal class
0 dog2 0
1 dog3 0
2 dog5 0
3 dog6 0
4 dog7 0
5 cat1 1
6 cat2 1
7 cat3 1
8 cat2 1
9 fish1 2
10 fish1 2
11 fish1 2
解决这个问题的最佳方法是什么?
因为 groupby.sample
不允许 n
大于组大小,如果 replace
不是 True
但替换为 True
意味着即使在本可以下采样的组中也会发生替换。
让我们尝试使用 groupby.apply
+ sample
并有条件地为每个组启用 replace
。
创建一个字典,将每个 class 映射到样本数,并使用条件逻辑来确定是否替换:
sample_amounts = {0: 5, 1: 4, 2: 3}
s = (
df.groupby('class').apply(lambda g: g.sample(
# lookup number of samples to take
n=sample_amounts[g.name],
# enable replacement if len is less than number of samples expected
replace=len(g) < sample_amounts[g.name]
))
)
s
:
animal class
class
0 5 dog6 0
3 dog4 0
6 dog7 0
4 dog5 0
2 dog3 0
1 9 cat3 1
8 cat2 1
7 cat1 1
8 cat2 1
2 10 fish1 2
10 fish1 2
10 fish1 2
droplevel
可用于保留初始索引(如果重要):
sample_amounts = {0: 5, 1: 4, 2: 3}
s = (
df.groupby('class').apply(lambda g: g.sample(
n=sample_amounts[g.name],
replace=len(g) < sample_amounts[g.name]
))
.droplevel(0)
)
s
:
animal class
6 dog7 0
3 dog4 0
2 dog3 0
4 dog5 0
1 dog2 0
7 cat1 1
8 cat2 1
8 cat2 1
8 cat2 1
10 fish1 2
10 fish1 2
10 fish1 2
reset_index
如果索引不重要可以用:
sample_amounts = {0: 5, 1: 4, 2: 3}
s = (
df.groupby('class').apply(lambda g: g.sample(
n=sample_amounts[g.name],
replace=len(g) < sample_amounts[g.name]
))
.reset_index(drop=True)
)
s
:
animal class
0 dog1 0
1 dog2 0
2 dog4 0
3 dog5 0
4 dog3 0
5 cat3 1
6 cat2 1
7 cat1 1
8 cat3 1
9 fish1 2
10 fish1 2
11 fish1 2