熊猫:平衡数据

dok*_*ndr 12 python pandas

注意:这个问题与答案不一样:"Pandas:在groupby之后对每个组进行抽样"

试图弄清楚如何使用pandas.DataFrame.sample或任何其他功能来平衡这些数据:

df[class].value_counts()

c1    9170
c2    5266
c3    4523
c4    2193
c5    1956
c6    1896
c7    1580
c8    1407
c9    1324
Run Code Online (Sandbox Code Playgroud)

我需要得到每个类(c1,c2,.. c9)的随机样本,其中样本大小等于具有最小实例数的类的大小.在此示例中,样本大小应为类c9 = 1324的大小.

用熊猫做任何简单的方法吗?

更新

为澄清我的问题,请在上表中:

c1    9170
c2    5266
c3    4523
...
Run Code Online (Sandbox Code Playgroud)

数字是c1,c2,c3,...类的实例计数,因此实际数据如下所示:

c1 'foo'
c2 'bar'
c1 'foo-2'
c1 'foo-145'
c1 'xxx-07'
c2 'zzz'
...
Run Code Online (Sandbox Code Playgroud)

等等

更新2

澄清更多:

d = {'class':['c1','c2','c1','c1','c2','c1','c1','c2','c3','c3'],
     'val': [1,2,1,1,2,1,1,2,3,3]
    }

df = pd.DataFrame(d)

    class   val
0   c1  1
1   c2  2
2   c1  1
3   c1  1
4   c2  2
5   c1  1
6   c1  1
7   c2  2
8   c3  3
9   c3  3

df['class'].value_counts()

c1    5
c2    3
c3    2
Name: class, dtype: int64

g = df.groupby('class')
g.apply(lambda x: x.sample(g.size().min()))

        class   val
class           
c1  6   c1  1
    5   c1  1
c2  4   c2  2  
    1   c2  2
c3  9   c3  3
    8   c3  3
Run Code Online (Sandbox Code Playgroud)

看起来像这样.主要问题:

怎么样g.apply(lambda x: x.sample(g.size().min()))?我知道'lambda`是什么,但是:

  • 什么是传递给lambdax这种情况下?
  • 什么gg.size()
  • 为什么输出包含6,5,4,1,8,9个数字?他们的意思是什么?

piR*_*red 15

g = df.groupby('class')
g.apply(lambda x: x.sample(g.size().min()).reset_index(drop=True)

  class  val
0    c1    1
1    c1    1
2    c2    2
3    c2    2
4    c3    3
5    c3    3
Run Code Online (Sandbox Code Playgroud)

您的后续问题的答案

  1. xlambda最终被一个数据帧是子集df由所述基团表示.这些数据帧中的每一个,每个组都有一个,通过它lambda.
  2. ggroupby对象.我把它放在一个命名变量中因为我打算两次使用它. df.groupby('class').size()是另一种方法,df['class'].value_counts()但是因为groupby无论如何,我不得不重复使用它groupby,使用a size来获取值计数...节省时间.
  3. 这些数字是df采样的指数值.我添加reset_index(drop=True)了摆脱它.


Sam*_*Nde 6

上面的答案是正确的,但我很想指定上面的g不是Pandas DataFrame用户最可能想要的对象。它是一个pandas.core.groupby.groupby.DataFrameGroupBy对象。看到这一点,尝试调用head,结果将是如下图所示。

import pandas as pd
d = {'class':['c1','c2','c1','c1','c2','c1','c1','c2','c3','c3'],
     'val': [1,2,1,1,2,1,1,2,3,3]
    }

d = pd.DataFrame(d)
g = d.groupby('class')
g.apply(lambda x: x.sample(g.size().min()).reset_index(drop=True))
g.head()
>>> class val
0    c1    1
1    c2    2
2    c1    1
3    c1    1
4    c2    2
5    c1    1
6    c1    1
7    c2    2
8    c3    3
9    c3    3
Run Code Online (Sandbox Code Playgroud)

为了解决这个问题,我们需要在将数据分组之后将g转换为a Pandas DataFrame,如下所示:

g = d.groupby('class')
g = pd.DataFrame(g.apply(lambda x: x.sample(g.size().min()).reset_index(drop=True)))
Run Code Online (Sandbox Code Playgroud)

现在调用head将产生:

g.head()

>>>class val
0   c1   1
1   c2   2
2   c1   1
3   c1   1
4   c2   2
Run Code Online (Sandbox Code Playgroud)

用户最想要的是哪个。

  • `g.apply` 的结果是一个 `DataFrame`,不需要这种转换。自己检查一下:`type(g.apply(lambda x: x.sample(g.size().min()).reset_index(drop=True)))`。您在示例中看到此行为的原因是因为“apply”不会就地修改对象——它_返回_一个“DataFrame”。 (2认同)

小智 5

该方法随机获取每个类的k个元素。

def sampling_k_elements(group, k=3):
    if len(group) < k:
        return group
    return group.sample(k)

balanced = df.groupby('class').apply(sampling_k_elements).reset_index(drop=True)
Run Code Online (Sandbox Code Playgroud)