Pandas groupby with categorical and apply copy index to additional column

时间:2016-06-27 17:21:14

标签: python pandas

考虑以下具有三个替代最后一行的MWE:

.sum

所以我有一个带浮点数的DataFrame。我想分组列'a'的bin并进行一些计算。当我使用a函数时,它按预期工作,它将bin作为索引返回,并将每个bin的总和作为列值返回。

现在,当我使用apply函数计算总和时,不知何故,groupby索引也被转换为数据框中的附加列'mybins',并且总和将应用于两列。所以现在我有一个列'a',其总和为sum(a),列为'mybins',其中bin边缘列表的时间为apply。这不是我想要/期望的。

我的最终目标是使用locationRef.child(locItemId).child(senderId).observeSingleEventOfType(.Value, withBlock: { (snapshot) in let locationId = snapshot.value!["location"] as! String }) { (error) in print(error.localizedDescription) } 来计算百分比,但后来我得到一个错误(不支持的操作数类型),所以我需要修复这个奇怪的行为。我错过了什么?

1 个答案:

答案 0 :(得分:2)

就是你想要的 - 关注.groupby('mybins')['a'] [' a'] ):

In [270]: %paste
(df.assign(mybins = lambda df: pd.cut(df['a'],bins=np.linspace(0,300,6)))
   .groupby('mybins')['a']
   #.sum()
   #.apply(lambda x: x.sum())
   .apply(lambda x: x.sum()/float(len(x))*100)
)
## -- End pasted text --
Out[270]:
mybins
(0, 60]        3150.0
(60, 120]      9150.0
(120, 180]    15150.0
(180, 240]    21150.0
(240, 300]    27000.0
Name: a, dtype: float64

顺便说一句,你可以用更多的熊猫惯用法来达到同样的效果:

In [273]: %paste
(df.assign(mybins = lambda df: pd.cut(df['a'],bins=np.linspace(0,300,6)))
   .groupby('mybins')
   .mean() * 100
)
## -- End pasted text --
Out[273]:
                  a
mybins
(0, 60]      3150.0
(60, 120]    9150.0
(120, 180]  15150.0
(180, 240]  21150.0
(240, 300]  27000.0

<强>解释

下式给出:

In [33]: df
Out[33]:
   s         n s2        n2  n3
0  a  0.629772  a  6.297724   1
1  d  0.496197  d  4.961974   0
2  a  0.801868  a  8.018679   0
3  d  0.461914  d  4.619140   3
4  c  0.259175  c  2.591751   0
5  b  0.797740  b  7.977401   0
6  a  0.508496  a  5.084962   1
7  b  0.242306  b  2.423056   2
8  c  0.218082  c  2.180820   2
9  d  0.060125  d  0.601247   3

如果我们尝试使用.apply()来总结这些群组,我们会得到:

In [34]: df.groupby('s').apply(lambda x: x.sum())
Out[34]:
     s         n   s2         n2  n3
s
a  aaa  1.940136  aaa  19.401364   2
b   bb  1.040046   bb  10.400456   2
c   cc  0.477257   cc   4.772571   2
d  ddd  1.018236  ddd  10.182361   6

因为apply()将应用于所有列,包括此示例中的groupby列 - s

使用.apply(lambda x: print(x))代替.apply(lambda x: x.sum())

进行证明
In [35]: df.groupby('s').apply(lambda x: print(x))
   s         n s2        n2  n3
0  a  0.629772  a  6.297724   1
2  a  0.801868  a  8.018679   0
6  a  0.508496  a  5.084962   1
   s         n s2        n2  n3
0  a  0.629772  a  6.297724   1
2  a  0.801868  a  8.018679   0
6  a  0.508496  a  5.084962   1
   s         n s2        n2  n3
5  b  0.797740  b  7.977401   0
7  b  0.242306  b  2.423056   2
   s         n s2        n2  n3
4  c  0.259175  c  2.591751   0
8  c  0.218082  c  2.180820   2
   s         n s2        n2  n3
1  d  0.496197  d  4.961974   0
3  d  0.461914  d  4.619140   3
9  d  0.060125  d  0.601247   3
Out[35]:
Empty DataFrame
Columns: []
Index: []

注意1:您会看到所有列,包括groupby

注意2:您会看到5个组而不是预期的4个With groupby, the applied function is called one extra time to see if certain optimizations can be done.

现在让我们尝试使用.sum()函数:

In [37]: df.groupby('s').sum()
Out[37]:
          n         n2  n3
s
a  1.940136  19.401364   2
b  1.040046  10.400456   2
c  0.477257   4.772571   2
d  1.018236  10.182361   6

sum()非常聪明,可以删除所有非数字列,如果在应用groupby时也删除了sum列:

In [38]: df.groupby('n3').sum()
Out[38]:
           n         n2
n3
0   2.354980  23.549805
1   1.138269  11.382686
2   0.460388   4.603876
3   0.522039   5.220387

我们刚刚按其他数字列分组:n3并且sum()未应用于groupby