[Pandas精进]判断连续时间序列范围并分组应用

大家好,我是Brook。
最近在处理数据的时候遇到一个需求,核心就是求取最大连续行为天数。

这里从数据库中导出的监测设备数据离线预警日志,需求是找出各监测对象设备掉线最长持续多久并确定其离线时长。

图1:案例数据

以上某监测对象数据显示:最长离线天数从5月7日-5月10日持续4天。
程序每天定时检测一次数据在线情况,很明显只有数据掉线才会向数据库中插入日志,时间并不连续,因此,本文分享一种思路来统计时间序列连续时间段和天数。

案例数据较简单,大家可以自行虚拟构造演示数据集,定义的字段相同即可。
整体思路如下:

构造日期天数辅助列(定义日期转天数函数)
然后用辅助列生成列表作为输入,构造时间序列处理函数生成可分段时间范围和天数
如果掉线天数与最大掉线天数相同,则这几天是最长连续离线日期范围(当然还可以求最近多少天内掉线情况、连续掉线最长时间段等,根据需要增加过滤条件)

具体代码如下:

import pandas as pd
from itertools import groupby

#日期-天数转换函数
def which_day(x):
    year=x.year
    month=x.month
    day=x.day
    list=[31,28,31,30,31,30,31,31,30,31,30,31]
    whichday=0
    if (year%4)==0 and (year%100)!=0 or (year%400)==0:
        list[1]=29
    for i in range(1,month):
        if month == 1:
            print(day)
        whichday=whichday+list[i-1]
    whichday=whichday+day
    return whichday

#连续掉线时间范围及天数处理函数
def data_preprocess_dactory(lst,BUILD_ID):
    result1 = []
    result2 = []
    for k, g in groupby(enumerate(lst), lambda x: x[1] - x[0]):
        l1 = [k_v.get(j).strftime('%Y-%m-%d') for i, j in g]  # 连续时间的列表
        if len(l1) > 1:
            scop = str(min(l1)) + '-' + str(max(l1))  # 连续时间范围用"-"连接
            result1.append(scop)
            result2.append(len(l1))  #连续天数
        else:
            scop = l1[0]
            result1.append(scop)
            result2.append(len(l1))   #连续天数
    df = pd.DataFrame({'时间': result1, '连续掉线天数': result2})

    return df.reindex(columns=["建筑编号", "时间", "连续掉线天数"], fill_value="{0}".format(BUILD_ID))


# 数据源
df = pd.read_excel(r".\test.xlsx")
df1=pd.DataFrame(df[["BUILD_ID","BUILD_NAME","OFF_TIME"]])
id_name =df1.set_index("BUILD_ID")["BUILD_NAME"].to_dict()  #ID-名称映射字典
Build_list=df1.BUILD_ID.unique().tolist()

# 构建空表,存储处理的对象
df_empty = pd.DataFrame(columns=["建筑编号", "建筑名称", "时间", "连续掉线天数"])
data_list = [] 
for k in range(len(Build_list)):
    df2=df1[df1.BUILD_ID=="{0}".format(Build_list[k])].copy()

    df2["OFF_TIME"]=pd.to_datetime(df2['OFF_TIME'])
    df2["辅助列-天数"]=df2["OFF_TIME"].map(lambda x:which_day(x))

    lst = df2["辅助列-天数"].tolist()   # 连续数字
    # lst1=df2["OFF_TIME"].dt.strftime('%Y-%m-%d').tolist()
    k_v = df2.set_index("辅助列-天数")["OFF_TIME"].to_dict()  #辅助列-天数映射字典

    df3=data_preprocess_dactory(lst,Build_list[k])

    df3.insert(1,'建筑名称',df3["建筑编号"].map(lambda x:id_name.get(x)))  # 指定第2列插入建筑名称
    # df3["建筑名称"]=df3["建筑编号"].map(lambda x:id_name.get(x))

    data_list.append(df3)

res = pd.concat(data_list, axis=0, ignore_index=True,sort=False)
print(res)

res["max_连续掉线天数"]=res.groupby("建筑编号")["连续掉线天数"].transform('max')
res1=res[res.连续掉线天数==res.max_连续掉线天数]

print(res1)


以上为本次分享全部内容,类似场景可触类旁通如:计算用户连续打卡天数、计算用户连续登录天数等!

AI悦创·推出辅导班啦,包括「Python 语言辅导班、C++辅导班、算法/数据结构辅导班、少儿编程、pygame 游戏开发」,全部都是一对一教学:一对一辅导 + 一对一答疑 + 布置作业 + 项目实践等。QQ、微信在线,随时响应!V:Jiabcdefh
AI悦创 » [Pandas精进]判断连续时间序列范围并分组应用

发表评论