23

我最近刚刚从 R 切换到 python,并且在再次习惯数据帧而不是使用 R 的 data.table 时遇到了一些麻烦。我遇到的问题是我想获取一个字符串列表,检查一个值,然后将该字符串的计数相加 - 由用户分解。所以我想获取这些数据:

   A_id       B    C
1:   a1    "up"  100
2:   a2  "down"  102
3:   a3    "up"  100
3:   a3    "up"  250
4:   a4  "left"  100
5:   a5 "right"  102

并返回:

   A_id_grouped   sum_up   sum_down  ...  over_200_up
1:           a1        1          0  ...            0
2:           a2        0          1                 0
3:           a3        2          0  ...            1
4:           a4        0          0                 0
5:           a5        0          0  ...            0

在我使用 R 代码(使用 data.table)之前

>DT[ ,list(A_id_grouped, sum_up = sum(B == "up"),
+  sum_down = sum(B == "down"), 
+  ...,
+  over_200_up = sum(up == "up" & < 200), by=list(A)];

然而,我最近对 ​​Python 的所有尝试都失败了:

DT.agg({"D": [np.sum(DT[DT["B"]=="up"]),np.sum(DT[DT["B"]=="up"])], ...
    "C": np.sum(DT[(DT["B"]=="up") & (DT["C"]>200)])
    })

先感谢您!这似乎是一个简单的问题,但我在任何地方都找不到。

4

4 回答 4

25

为了补充 unutbu 的答案,这是一种apply在 groupby 对象上使用的方法。

>>> df.groupby('A_id').apply(lambda x: pd.Series(dict(
    sum_up=(x.B == 'up').sum(),
    sum_down=(x.B == 'down').sum(),
    over_200_up=((x.B == 'up') & (x.C > 200)).sum()
)))
      over_200_up  sum_down  sum_up
A_id                               
a1              0         0       1
a2              0         1       0
a3              1         0       2
a4              0         0       0
a5              0         0       0
于 2013-03-07T02:45:52.397 回答
12

可能有更好的方法;我对熊猫很陌生,但这有效:

import pandas as pd
import numpy as np

df = pd.DataFrame({'A_id':'a1 a2 a3 a3 a4 a5'.split(),
                   'B': 'up down up up left right'.split(),
                   'C': [100, 102, 100, 250, 100, 102]})

df['D'] = (df['B']=='up') & (df['C'] > 200)
grouped = df.groupby(['A_id'])

def sum_up(grp):
    return np.sum(grp=='up')
def sum_down(grp):
    return np.sum(grp=='down')
def over_200_up(grp):
    return np.sum(grp)

result = grouped.agg({'B': [sum_up, sum_down],
                      'D': [over_200_up]})
result.columns = [col[1] for col in result.columns]
print(result)

产量

      sum_up  sum_down  over_200_up
A_id                               
a1         1         0            0
a2         0         1            0
a3         2         0            1
a4         0         0            0
a5         0         0            0
于 2013-03-06T23:07:59.043 回答
3

一个老问题;我觉得更好的方法,避免应用,是在分组和聚合之前创建一个新的数据框:


df = df.set_index('A_id')

outcome = {'sum_up' : df.B.eq('up'),
           'sum_down': df.B.eq('down'),
           'over_200_up' : df.B.eq('up') & df.C.gt(200)}

outcome = pd.DataFrame(outcome).groupby(level=0).sum()

outcome
 
      sum_up  sum_down  over_200_up
A_id                               
a1         1         0            0
a2         0         1            0
a3         2         0            1
a4         0         0            0
a5         0         0            0

另一种选择是在分组之前取消堆叠;但是,我觉得这是一个更长且不必要的过程:

(df
  .set_index(['A_id', 'B'], append = True)
  .C
  .unstack('B')
  .assign(gt_200 = lambda df: df.up.gt(200))
  .groupby(level='A_id')
  .agg(sum_up=('up', 'count'), 
       sum_down =('down', 'count'), 
       over_200_up = ('gt_200', 'sum')
      )
)

      sum_up  sum_down  over_200_up
A_id                               
a1         1         0            0
a2         0         1            0
a3         2         0            1
a4         0         0            0
a5         0         0            0
于 2021-10-01T04:44:34.873 回答
0

在这里,我最近使用 df assign 和 numpy 的 where 方法学到了什么:

df3=

A_id       B    C
1:   a1    "up"  100
2:   a2  "down"  102
3:   a3    "up"  100
3:   a3    "up"  250
4:   a4  "left"  100
5:   a5 "right"  102
df3.assign(sum_up= np.where(df3['B']=='up',1,0),sum_down= np.where(df3['B']=='down',1,0),
          over_200_up= np.where((df3['B']=='up') & (df3['C']>200),1,0)).groupby('A_id',as_index=False).agg({'sum_up':sum,'sum_down':sum,'over_200_up':sum})

结果=

   A_id  sum_up   sum_down  over_200_up
0   a1    1        0         0
1   a2    0        1         0
2   a3    2        0         1
3   a4    0        0         0
4   a5    0        0         0

如果您熟悉 SQL 案例并希望在 pandas 中应用相同的逻辑,这也类似于

select a,
       sum(case when B='up' then 1 else 0 end) as sum_up
       ....
from   table
group by a
于 2021-12-04T18:50:31.843 回答