看过来
《pandas 教程》 持续更新中,提供建议、纠错、催更等加作者微信: gairuo123(备注:pandas教程)和关注公众号「盖若」ID: gairuo。跟作者学习,请进入 Python学习课程。欢迎关注作者出版的书籍:《深入浅出Pandas》 和 《Python之光》。
在数据分析中,经常会出现识别连续的需求,在本例中,我们不仅要找出连续相同的数,还需要在满足连续的位置处标记是第几个连续的,即连续情况的序号。
先构造数据如下:
import pandas as pd
l = [0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1,
1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1]
df = pd.DataFrame(l, columns=['a'])
df
'''
a
0 0
1 1
2 1
3 0
4 1
5 0
6 1
7 1
8 1
9 0
10 1
11 1
12 1
13 1
14 0
15 1
16 0
17 0
18 1
19 1
20 1
21 1
22 1
'''
a 列由 0 和 1 组成,我们需要关注 1 的情况,如果连续有 3 个 1 表示满足连续情况,再将第几次连续标记在这组数据的最后一个位置。
总体思路是,先得到一个 Series,索引为要标识的位置,值为序号值,最后将这个 Series 添加成新列。
先增加一列 b 作为辅助列,它的作用是对连续的数据进行分组,并填充组序号:
df.assign(b=df.a.ne(df.a.shift()).cumsum())
'''
a b
0 0 1
1 1 2
2 1 2
3 0 3
4 1 4
5 0 5
6 1 6
7 1 6
8 1 6
9 0 7
10 1 8
11 1 8
12 1 8
13 1 8
14 0 9
15 1 10
16 0 11
17 0 11
18 1 12
19 1 12
20 1 12
21 1 12
22 1 12
'''
以上代码判断当前值是否与它的下一个值不相同,为真表示不连续,得到的是一个布尔序列,累加方法 cumsum() 则对这个布尔序列计算,得到各连续组的序号。
由于要标记的是 1 的连续,接着筛选 a 列为 1 的数据:
(
df.assign(b=df.a.ne(df.a.shift()).cumsum())
.loc[df.a == 1]
)
'''
a b
1 1 2
2 1 2
4 1 4
6 1 6
7 1 6
8 1 6
10 1 8
11 1 8
12 1 8
13 1 8
15 1 10
18 1 12
19 1 12
20 1 12
21 1 12
22 1 12
'''
再按序号分组筛选出数据大于等于 3 的数据:
(
df.assign(b=df.a.ne(df.a.shift()).cumsum())
.loc[df.a == 1]
.groupby('b').filter(lambda g: g.b.count() >= 3)
)
'''
a b
6 1 6
7 1 6
8 1 6
10 1 8
11 1 8
12 1 8
13 1 8
18 1 12
19 1 12
20 1 12
21 1 12
22 1 12
'''
由于要标记在连续组的最后一个上,再按序号分组筛选出每组最后一个值:
(
df.assign(b=df.a.ne(df.a.shift()).cumsum())
.loc[df.a == 1]
.groupby('b').filter(lambda g: g.b.count() >= 3)
.groupby('b').tail(1)
)
'''
a b
8 1 6
13 1 8
22 1 12
'''
这时,我们即有要标识的位置信息(即索引标签值),最后再利用 a 的值全为 1 特征,累加获得标识序号,并将它赋值给一个标识符:
ser = (
df.assign(b=df.a.ne(df.a.shift()).cumsum())
.loc[df.a == 1]
.groupby('b').filter(lambda g: g.b.count() >= 3)
.groupby('b').tail(1)
.a.cumsum()
)
ser
'''
8 1
13 2
22 3
Name: a, dtype: int64
'''
最后用 eval 添加一列:
df.eval('b=@ser')
'''
a b
0 0 NaN
1 1 NaN
2 1 NaN
3 0 NaN
4 1 NaN
5 0 NaN
6 1 NaN
7 1 NaN
8 1 1.0
9 0 NaN
10 1 NaN
11 1 NaN
12 1 NaN
13 1 2.0
14 0 NaN
15 1 NaN
16 0 NaN
17 0 NaN
18 1 NaN
19 1 NaN
20 1 NaN
21 1 NaN
22 1 3.0
'''
# 将缺失值填充为空
df.eval('b=@ser').fillna('')
'''
a b
0 0
1 1
2 1
3 0
4 1
5 0
6 1
7 1
8 1 1.0
9 0
10 1
11 1
12 1
13 1 2.0
14 0
15 1
16 0
17 0
18 1
19 1
20 1
21 1
22 1 3.0
'''
这样就完成了以上需求。
(完)
更新时间:Aug. 18, 2024, 4:12 p.m. 标签:pandas python 连续 序号