使用动态标准按 id 计数

count by id with dynamic criteria

我有一个 DataFrame,我想向其中添加一个新的列,其中说明每个 ID 和每年有多少次过去有正利润。例如:

   id  year  profit
0   1  2018       0
1   1  2019      10
2   1  2020      20
3   1  2021       0
4   2  2018       0
5   2  2019      20
6   2  2020      10

期望的结果应该是这样的:

   id  year  profit  past_profit
0   1  2018       0            0
1   1  2019      10            0
2   1  2020      20            1
3   1  2021       0            2
4   2  2018       0            0
5   2  2019      20            0
6   2  2020      10            1

有什么想法吗?

使用 datar,一个重新构想 pandas API 的 pandas 包装器,可以很容易地做到这一点:

>>> from datar.all import f, tibble, group_by, mutate, lag, cumsum, as_integer, coalesce
>>> 
>>> df = tibble(
...   id=[1,1,1,1,2,2,2], 
...   year=[2018,2019,2020,2021,2018,2019,2020], 
...   profit=[0,10,20,0,0,20,10]
... )
>>> 
>>> (
...   df 
...   >> group_by(f.id) 
...   >> mutate(
...     past_profit=cumsum(       # get the cumsum
...       as_integer(             # convert to integers
...         coalesce(             # replace NAs with 0
...           lag(f.profit > 0),  # shift the result
...           0
...         )
...       )
...     )
...   )
... )
       id    year  profit  past_profit
  <int64> <int64> <int64>      <int64>
0       1    2018       0            0
1       1    2019      10            0
2       1    2020      20            1
3       1    2021       0            2
4       2    2018       0            0
5       2    2019      20            0
6       2    2020      10            1
[TibbleGrouped: id (n=2)]

我们可以使用 groupby + shift 获取过去一年的数据并使用 groupby + cumsum 获取每个“id”出现正利润的次数".

df['past_profit'] = (df['profit']>0).groupby(df['id']).shift().fillna(False).groupby(df['id']).cumsum()

输出:

   id  year  profit  past_profit
0   1  2018       0            0
1   1  2019      10            0
2   1  2020      20            1
3   1  2021       0            2
4   2  2018       0            0
5   2  2019      20            0
6   2  2020      10            1

请注意,这假设数据按 year 排序。如果没有,我们可以先按 id 和 year 排序;然后使用上面的代码。

df = df.sort_values(by=['id','year'])