看过来
《pandas 教程》 持续更新中,提供建议、纠错、催更等加作者微信: gairuo123(备注:pandas教程)和关注公众号「盖若」ID: gairuo。跟作者学习,请进入 Python学习课程。欢迎关注作者出版的书籍:《深入浅出Pandas》 和 《Python之光》。
本例有三列数据,全部为时间数据,需要从其中筛选出按行日期连续的数据,对连续的定义为不论数据在哪个列只要可以连续就可以,我们将利用 pandas 来解决这个需求。本案例是一个关于判断时间是否连续的问题,特殊的是,源数据中的时间是没有按先后的,需要我们自己重新排序。通过这个案例我们要学习的知识点有:时间类型的转移、时间的位差、时间间隔类型的表示、排序、删除缺失值、对比值相等的方法、all()方法的使用、apply()按行应用函数等知识。
以下为我们构造的源数据集:
import pandas as pd
from io import StringIO
data = '''
a,b,c
2022/9/23,2022/9/24,2022/9/27
2022/9/26,2022/9/27,2022/9/23
2022/9/21,2022/9/22,2022/9/26
2022/9/26,2022/9/22,2022/9/21
2022/9/26,2022/9/24,2022/9/27
2022/9/22,2022/9/21,2022/9/25
2022/9/26,2022/9/21,2022/9/27
2022/9/26,2022/9/21,2022/9/23
2022/9/25,2022/9/24,2022/9/27
2022/9/23,2022/9/25,2022/9/26
2022/9/27,2022/9/26,2022/9/23
2022/9/25,2022/9/24,2022/9/26
2022/9/25,2022/9/24,2022/9/27
2022/9/21,2022/9/26,2022/9/22
2022/9/24,2022/9/25,2022/9/26
2022/9/25,2022/9/21,2022/9/26
2022/9/24,2022/9/26,2022/9/23
2022/9/26,2022/9/22,2022/9/21
2022/9/22,2022/9/27,2022/9/23
2022/9/27,2022/9/21,2022/9/25
2022/9/27,2022/9/25,2022/9/26
2022/9/26,2022/9/24,2022/9/23
2022/9/25,2022/9/26,2022/9/23
2022/9/25,2022/9/21,2022/9/26
2022/9/23,2022/9/25,2022/9/26
2022/9/22,2022/9/26,2022/9/23
2022/9/26,2022/9/27,2022/9/21
2022/9/25,2022/9/21,2022/9/24
2022/9/26,2022/9/21,2022/9/27
2022/9/22,2022/9/21,2022/9/27
2022/9/27,2022/9/26,2022/9/23
2022/9/22,2022/9/26,2022/9/27
2022/9/22,2022/9/27,2022/9/26
'''
df = pd.read_csv(StringIO(data))
df
# ...
共 a、b、c 三列,全部为时间数据,需求为筛选出不分位置日期连续的行。
我们用布尔序列筛选数据,因此需要构造一个和源数据列相同长度的布尔序列。
由于需求的逻辑是按行进行的,我们的解决思路是按行处理得到布尔值,然后应用到所有行上。
以行为一个 Series,先将它排序,然后求位差,如果时间间隔均为一天就说明它是连续的日期。
我们先以某行为实例来按思路编写代码,比如索引20(先转为时间类型):
(
df.iloc[20]
.astype('>M8')
)
'''
a 2022-09-27
b 2022-09-25
c 2022-09-26
Name: 20, dtype: datetime64[ns]
'''
排序数据,让时间按早到晚:
(
df.iloc[20]
.astype('>M8')
.sort_values()
)
'''
b 2022-09-25
c 2022-09-26
a 2022-09-27
Name: 20, dtype: datetime64[ns]
'''
求各日期间的位差:
(
df.iloc[20]
.astype('>M8')
.sort_values()
.diff()
)
'''
b NaT
c 1 days
a 1 days
Name: 20, dtype: timedelta64[ns]
'''
第一个值永远是Nan,因此删除掉缺失值:
(
df.iloc[20]
.astype('>M8')
.sort_values()
.diff()
.dropna()
)
'''
c 1 days
a 1 days
Name: 20, dtype: timedelta64[ns]
'''
然后判断值是否为1天:
(
df.iloc[20]
.astype('>M8')
.sort_values()
.diff()
.dropna()
.eq(pd.Timedelta('1days'))
)
'''
c True
a True
Name: 20, dtype: bool
'''
最后判断所有值是否全为True:
(
df.iloc[20]
.astype('>M8')
.sort_values()
.diff()
.dropna()
.eq(pd.Timedelta('1days'))
.all()
)
将以上这个方法封装为一个函数:
def func(ser: pd.Series) -> bool:
return (
ser.astype('>M8')
.sort_values()
.diff()
.dropna()
.eq(pd.Timedelta('1days'))
.all()
)
按行调用这个函数:
df.apply(func, axis=1)
'''
0 False
1 False
2 False
3 False
4 False
5 False
6 False
7 False
8 False
9 False
10 False
11 True
12 False
13 False
14 True
15 False
16 False
17 False
18 False
19 False
20 True
21 False
22 False
23 False
24 False
25 False
26 False
27 False
28 False
29 False
30 False
31 False
32 False
dtype: bool
'''
最后将这个布尔序列应用到数据筛选中:
df[df.apply(func, axis=1)]
'''
a b c
11 2022/9/25 2022/9/24 2022/9/26
14 2022/9/24 2022/9/25 2022/9/26
20 2022/9/27 2022/9/25 2022/9/26
'''
可以看到,筛选出的数据均为符合要求的数据。
(完)
更新时间:2024-08-18 16:07:51 标签:pandas python 日期 连续