![](/img/trans.png)
[英]Keep running count of number of values greater than threshold in pandas dataframe
[英]Pandas - Count consecutive rows with column values greater than a threshold limit
我有一個數據框,其中在特定時間范圍內記錄了幾個人的速度。 下面是一個簡化版:
df = pd.DataFrame([["Mary",0,2.3], ["Mary",1,1.8], ["Mary",2,3.2],
["Mary",3,3.0], ["Mary",4,2.6], ["Mary",5,2.2],
["Steve",0,1.6], ["Steve",1,1.7], ["Steve",2,2.5],
["Steve",3,2.7], ["Steve",4,2.3], ["Steve",5,1.8],
["Jane",0,1.9], ["Jane",1,2.7], ["Jane",2,2.3],
["Jane",3,1.9], ["Jane",4,2.2], ["Jane",5,2.1]],
columns = [ "name","time","speed (m/s)" ])
print(df)
name time (s) speed (m/s)
0 Mary 0 2.3
1 Mary 1 1.8
2 Mary 2 3.2
3 Mary 3 3.0
4 Mary 4 2.6
5 Mary 5 2.2
6 Steve 0 1.6
7 Steve 1 1.7
8 Steve 2 2.5
9 Steve 3 2.7
10 Steve 4 2.3
11 Steve 5 1.8
12 Jane 0 1.9
13 Jane 1 2.7
14 Jane 2 2.3
15 Jane 3 1.9
16 Jane 4 2.2
17 Jane 5 2.1
我正在尋找一種方法來計算每個名稱的速度大於 2 m/s 的次數(連續 2 個或更多記錄),以及這些間隔時間的平均持續時間。 真實的數據幀有超過 150 萬行,這使得循環效率低下。
我期望的結果如下所示:
name count average_duration(s)
0 Mary 1 4 # from 2 to 5s (included) - 1 time, 4/1 = 4s
1 Steve 1 3 # from 2 to 4s (included) - 1 time, 3/1 = 3s
2 Jane 2 2 # from 1 to 2s & from 4 to 5s (included) - 2 times, 4/2 = 2s
我在這個問題上花了一天多的時間,但沒有成功......提前感謝您的幫助!
所以這是我的出發點:
df['over2'] = df['speed (m/s)']>2
df['streak_id'] = (df['over2'] != df['over2'].shift(1)).cumsum()
streak_groups = df.groupby(['name','over2','streak_id'])["time"].agg(['min','max']).reset_index()
positive_streaks = streak_groups[streak_groups['over2'] & (streak_groups['min'] != streak_groups['max'])].copy()
positive_streaks["duration"] = positive_streaks["max"] - positive_streaks["min"] + 1
result = positive_streaks.groupby('name')['duration'].agg(['size', 'mean']).reset_index()
print(result)
輸出:
name size mean
0 Jane 2 2
1 Mary 1 4
2 Steve 1 3
我基本上給每個 False/True 連勝一個唯一的 ID 以便能夠通過它進行分組,所以每個組都是這樣一個連續的結果。
然后我簡單地將持續時間作為最大時間 - 最小時間,去掉 len 1 的條紋,然后通過名稱獲得分組的大小和平均值。
如果你想更好地理解每一步,我建議打印我一路上的中間數據幀。
這是另外一種檢查條件(大於2),並創建了一個幫手系列版本s
來跟蹤重復的后,再使用series.where
和series.duplicated
我們組的name
使用這個結果和總count
和nunique
(數唯一值) ,然后除以:
c = df['speed (m/s)'].gt(2)
s = c.ne(c.shift()).cumsum()
u = (s.where(c&s.duplicated(keep=False)).groupby(df['name'],sort=False)
.agg(['count','nunique']))
out = (u.join(u['count'].div(u['nunique']).rename("Avg_duration")).reset_index()
.drop("count",1).rename(columns={"nunique":"Count"}))
print(out)
name Count Avg_duration
0 Mary 1 4.0
1 Steve 1 3.0
2 Jane 2 2.0
有趣的問題! 我發現使用dplyr
想出一個很好的解決方案非常困難,但如果你碰巧知道R
和dplyr
包,那么你可以寫這樣的東西:
library(tidyverse)
df %>%
mutate(indicator = `speed_(m/s)` > 2.0) %>%
group_by(name) %>%
mutate(streak = cumsum(!indicator)) %>%
group_by(streak, .add = TRUE) %>%
summarise(duration = sum(indicator)) %>%
filter(duration >= 2) %>%
summarise(count = n(), mean_duration = mean(duration))
#> # A tibble: 3 x 3
#> name count mean_duration
#> <chr> <int> <dbl>
#> 1 Jane 2 2
#> 2 Mary 1 4
#> 3 Steve 1 3
由reprex 包(v0.3.0) 於 2020 年 8 月 31 日創建
如果這太離題了,我提前道歉,但我認為其他 R 用戶(或者可能是大熊貓向導)會覺得這很有趣。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.