Pandas:平衡

2024-06-06 16:59:46 发布

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

注意:这个问题与这里的答案不同:“熊猫:分组后每组取样”

试图找出如何使用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

我需要得到每个类的随机样本(c1,c2。。c9)其中sample size等于实例数最少的类的大小。在这个例子中,样本大小应该是c9=1324类的大小。

用熊猫做这个有什么简单的方法吗?

更新

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

c1    9170
c2    5266
c3    4523
...

数字是c1,c2,c3,。。。类,因此实际数据如下所示:

c1 'foo'
c2 'bar'
c1 'foo-2'
c1 'foo-145'
c1 'xxx-07'
c2 'zzz'
...

等等

更新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

看起来这很管用。主要问题:

如何g.apply(lambda x: x.sample(g.size().min()))工作?我知道“lambda”是什么,但是:

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

Tags: 数据samplelambdadataframedfsizefoovalue
3条回答

这个方法随机得到每个类的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)
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

后续问题的答案

  1. lambda中的x最终成为一个数据帧,它是由组表示的df的子集。每个数据帧(每组一个)都通过这个lambda
  2. ggroupby对象。我把它放在一个命名变量中,因为我计划使用它两次。df.groupby('class').size()df['class'].value_counts()的另一种方法,但是由于我要groupby无论如何,我也可以重用相同的groupby,使用size获取值计数。。。节省时间。
  3. 这些数字是df中与采样一起的索引值。我加了reset_index(drop=True)来摆脱它。

上面的答案是正确的,但我想指定上面的g不是用户最希望的Pandas DataFrame对象。它是一个对象。若要查看此信息,请尝试在g上调用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

要解决这个问题,我们需要在按如下方式分组数据后将g转换为Pandas DataFrame

g = d.groupby('class')
g = pd.DataFrame(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

这很可能是用户想要的。

相关问题 更多 >