首页 > 解决方案 > 计算某个值出现之间的行数

问题描述

首先,我不确定我是否正确地表达了这个问题,这可能就是我没有在网上找到解决方案的原因。

我有一个示例数据框,使用以下代码生成:

import pandas as pd
import numpy as np

data1 = list(np.arange(24)) * 2
data2 = ['A'] * 24 + ['B'] * 24
data3 = [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
         0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0]
  
df = pd.DataFrame(data=zip(data1, data2, data3), columns=['day', 'group',
                  'value'])

days_with_one = df.groupby('group').apply(lambda x: x.loc[df['value'] == 1,
                          'day'])

我想要做的是对于值为“1”的每一天,找出自上次该值为“1”以来经过了多少天(分别针对每个组)。

df
Out[49]: 
    day group  value
0     0     A      0
1     1     A      0
2     2     A      0
3     3     A      0
4     4     A      0
5     5     A      1
6     6     A      0
7     7     A      0
8     8     A      0
9     9     A      0
10   10     A      1
11   11     A      0
12   12     A      0
13   13     A      0
14   14     A      0
15   15     A      0
16   16     A      0
17   17     A      0
18   18     A      0
19   19     A      1
20   20     A      0
21   21     A      0
22   22     A      0
23   23     A      0
24    0     B      0
25    1     B      0
26    2     B      0
27    3     B      1
28    4     B      0
29    5     B      0
30    6     B      0
31    7     B      0
32    8     B      0
33    9     B      0
34   10     B      0
35   11     B      0
36   12     B      0
37   13     B      1
38   14     B      0
39   15     B      0
40   16     B      1
41   17     B      0
42   18     B      0
43   19     B      0
44   20     B      1
45   21     B      0
46   22     B      0
47   23     B      0

我已经将 df 减少到只有值为 1 的行。因此,示例输出如下所示:

group  day    days_since
A      5       0
       10      5
       19      9
B      3       0
       13     10
       16      3
       20      4

标签: pythonpandaspandas-groupby

解决方案


1首先,您可以通过比较bySeries.eq和创建组的新列GroupBy.cumsum,这里如果存在一些0值,则意味着在每个组的第一个之前有一些值,因此使用第一个重复的行1过滤,最后用于每个组的差异,将缺失值替换为:Series.neDataFrame.duplicatedDataFrameGroupBy.diff0

df['days_since'] = df['value'].eq(1).groupby(df['group']).cumsum()
mask = ~df.duplicated(['group', 'days_since']) & df['days_since'].ne(0)

df1 = df.loc[mask, ['group','day']].copy()
df1['days_since'] = df1.groupby('group')['day'].diff().fillna(0).astype(int)
print (df1)
   group  day  days_since
5      A    5           0
10     A   10           5
19     A   19           9
27     B    3           0
37     B   13          10
40     B   16           3
44     B   20           4

编辑:谢谢@Henry Yik 的简化答案-您可以只过滤带有1in 的行value,然后得到差异:

mask = df['value'].eq(1)
df1 = df.loc[mask, ['group','day']].copy()
df1['days_since'] = df1.groupby('group')['day'].diff().fillna(0).astype(int)
print (df1)
   group  day  days_since
5      A    5           0
10     A   10           5
19     A   19           9
27     B    3           0
37     B   13          10
40     B   16           3
44     B   20           4

推荐阅读