熊猫:平衡数据

新手上路,请多包涵

注意:此问题与此处的答案不同:“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

我需要获取每个类(c1、c2、.. c9)的随机样本,其中样本大小等于实例数最少的类的大小。在此示例中,样本大小应为类 c9 的大小 = 1324。

有什么简单的方法可以用 Pandas 做到这一点吗?

更新

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

 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 的是什么?
  • gg.size() 中是什么?
  • 为什么输出包含 6、5、4、1、8、9 数字?他们的意思是什么?

原文由 dokondr 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 329
2 个回答
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. x 中的 lambda 最终成为一个数据帧,它是 df 的子集—由组代表。这些数据帧中的每一个,每组一个,都通过这个 lambda 传递。
  2. ggroupby 对象。我将它放在一个命名变量中,因为我计划使用它两次。 df.groupby('class').size() is an alternative way to do df['class'].value_counts() but since I was going to groupby anyway, I might as well reuse the same groupby ,使用 size 获取值计数…节省时间。
  3. 这些数字是来自 df 的索引值,与采样一起使用。我添加了 reset_index(drop=True) 来摆脱它。

原文由 piRSquared 发布,翻译遵循 CC BY-SA 4.0 许可协议

上面的答案是正确的,但我想指出上面的 g 不是 Pandas DataFrame 用户最可能想要的对象。它是一个 pandas.core.groupby.groupby.DataFrameGroupBy 对象。 Pandas apply 不会就地修改数据框,而是返回一个数据框。要查看这一点,请尝试在 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

要解决此问题,您可以创建一个新变量 or 如下所示将 g 分配给 应用 的结果,以便获得 Pandas DataFrame

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

现在调用 head 会产生:

 g.head()

>>>class val
0   c1   1
1   c2   2
2   c1   1
3   c1   1
4   c2   2

这很可能是用户想要的。

原文由 Samuel Nde 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Stack Overflow 翻译
子站问答
访问
宣传栏