将数据帧中的上下样本多类训练示例(行)设置为指定值

2024-09-30 03:24:11 发布

您现在位置:Python中文网/ 问答频道 /正文

我想为训练制作一个更平衡的多类熊猫数据框架。我的训练集的简化版本如下所示:

不平衡数据帧:类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)  

现在,我想对大多数类进行随机下采样,并对少数类进行随机上采样,使其达到每个类指定的值,以获得更平衡的数据帧

问题是,我可以在网上找到的所有pandas教程或其他有关stackoverflow的问题都涉及到将少数类随机过度采样到多数类的级别(例如:Duplicating training examples to handle class imbalance in a pandas data frame)或将多数类随机欠采样到少数类的级别

由于我面临着极端的不平衡,我无法使多数阶级的规模与少数阶级的规模相等。因此,我能找到的这些代码片段通常不适合我。理想情况下,我可以指定每个类通过过度采样或欠采样生成的样本的确切数量(取决于我为该类指定的数量以及该类包含的样本数量)

比如说,

如果我指明:

  • 计数_0=5(在2个样本的采样下为7,因此表示随机
  • 计数_1=4(为3表示随机超过采样1个样本)
  • 计数_2=3(was 1表示随机超过采样2个样本)

我想成为这样的人:

更平衡的数据帧:类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

解决这一问题的最佳方法是什么


Tags: 数据pandasclass计数样本cat1animalcat2
1条回答
网友
1楼 · 发布于 2024-09-30 03:24:11

由于^{}不允许n大于组大小,如果replace不是True,但具有replace be True,则意味着即使在本可以进行下采样的组中也会发生替换

相反,让我们尝试使用^{}+^{},并有条件地为每个组启用replace。 创建一个字典,将每个类映射到样本数,并使用条件逻辑确定是否替换:

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

^{}可用于保留初始索引(如果重要):

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

如果索引不重要,可以使用^a5}:

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

相关问题 更多 >

    热门问题