熊猫数据框逐行迭代,并引用前一行的值进行条件匹配

时间:2018-09-27 06:23:42

标签: python-3.x pandas pandas-groupby

我必须找出一辆自行车超速的次数,以及每种情况下持续多长时间(为简单起见,要行驶几公里)

df = pd.DataFrame({'bike':['b1']*15, 'km':list(range(1,16)), 'speed':[20,30,38,33,28,39,26,33,35,46,53,27,37,42,20]})
>>> df
   bike  km  speed
0    b1   1     20
1    b1   2     30
2    b1   3     38
3    b1   4     33
4    b1   5     28
5    b1   6     39
6    b1   7     26
7    b1   8     33
8    b1   9     35
9    b1  10     46
10   b1  11     53
11   b1  12     27
12   b1  13     37
13   b1  14     42
14   b1  15     20
#Expected result is
bike  last_OS_loc  for_how_long_on_OS
b1      4                2km
b1      11               5km
b1      15               1km

Now Logic-

  1. 必须将> = 30的速度标记为Overspeed_Flag

  2. 如果1或1 + km的速度保持在30以上,则将这些继续视为超速行驶(例如:当b1在2至4 km,6to11、13-14km之间时,将其标记为当b1处于6 km时,它不是超速会话,因为它仅适用于该行,未发现> 30的延续。

  3. 然后测量一个会话,将他保持在超速极限多长时间/几公里。请参阅预期结果标签。

  4. 还发现超速行驶的最后一公里是什么。

请提出我该如何实现。并让我知道问题中是否有任何不清楚的地方。

P:S:我也在尝试,但是对我来说并没有什么复杂(在如何标记它是OS_flag的延续还是单个OS实例上相当困惑。),如果成功执行此操作将会返回。感谢ADV。

2 个答案:

答案 0 :(得分:2)

您可以使用:

#boolean mask
mask = df['speed'] >= 30
#consecutive groups
df['g'] = mask.ne(mask.shift()).cumsum()
#get size of each group
df['count'] = mask.groupby(df['g']).transform('size')
#filter by mask and remove unique rows
df = df[mask & (df['count'] > 1)]
print (df)
   bike  km  speed  g  count
1    b1   2     30  2      3
2    b1   3     38  2      3
3    b1   4     33  2      3
7    b1   8     33  6      4
8    b1   9     35  6      4
9    b1  10     46  6      4
10   b1  11     53  6      4
12   b1  13     37  8      2
13   b1  14     42  8      2

#aggregate first and last values
df1 = df.groupby(['bike','g'])['km'].agg([('last_OS_loc', 'last'), 
                                          ('for_how_long_on_OS','first')])
#substract last with first
df1['for_how_long_on_OS'] = df1['last_OS_loc'] - df1['for_how_long_on_OS']
#data cleaning
df1 = df1.reset_index(level=1, drop=True).reset_index()
print (df1)
  bike  last_OS_loc  for_how_long_on_OS
0   b1            4                   2
1   b1           11                   3
2   b1           14                   1

编辑:

print (pd.concat([mask,
                  mask.shift(), 
                  mask.ne(mask.shift()), 
                  mask.ne(mask.shift()).cumsum()], axis=1, 
                  keys=('mask', 'shifted', 'not equal (!=)', 'cumsum')))

     mask shifted  not equal (!=)  cumsum
0   False     NaN            True       1
1    True   False            True       2
2    True    True           False       2
3    True    True           False       2
4   False    True            True       3
5    True   False            True       4
6   False    True            True       5
7    True   False            True       6
8    True    True           False       6
9    True    True           False       6
10   True    True           False       6
11  False    True            True       7
12   True   False            True       8
13   True    True           False       8
14  False    True            True       9

答案 1 :(得分:1)

这是另一种使用几个助手Series和一个lambda函数的方法:

os_session = (df['speed'].ge(30) & (df['speed'].shift(-1).ge(30) | df['speed'].shift().ge(30))).astype(int)
groups =  (os_session.diff(1) != 0).astype('int').cumsum()

f_how_long = lambda x: x.max() - x.min()

grouped_df = (df.groupby([os_session, groups, 'bike'])['km']
           .agg([('last_OS_loc', 'max'),
                 ('for_how_long_on_OS',f_how_long)])
           .xs(1, level=0)
           .reset_index(level=0, drop=True))

print(grouped_df)

      last_OS_loc  for_how_long_on_OS
bike                                 
b1              4                   2
b1             11                   3
b1             14                   1