连续活跃天数统计

连续活跃天数统计

需求说明

什么是连续出现?

假设有如下日期信息: 20230401,20230402,20230403,20230405,20230406,20230407,20230410,20230411
则:
20230401-20230403 为一次连续出现,连续出现天数为 3
20230405-20230407 为一次连续出现,连续出现天数为 3
20230410-20230411 为一次连续出现,连续出现天数为 2


在一些业务场景下,我们需要找符合类似规则的的对象。这里基于Python和SQL尝试进行解决。

python版本解决方案

import pandas as pd# 计算连续出现天数
def calculate_consecutive_days(df):results = []df['日期'] = pd.to_datetime(df['日期'], format='%Y%m%d')df = df.sort_values(by=['对象ID', '日期'])# 遍历每个号码for number, group in df.groupby('对象ID''):consecutive_days = 1start_date = group['日期'].iloc[0]prev_date = group['日期'].iloc[0]details = []# 遍历每个日期for date in group['日期'].iloc[1:]:if date == prev_date + pd.Timedelta(days=1):consecutive_days += 1else:if consecutive_days > 1:details.append((start_date, prev_date, consecutive_days))consecutive_days = 1start_date = dateprev_date = date# 添加最后一个连续天数if consecutive_days > 1:details.append((start_date, prev_date, consecutive_days))# 添加结果for start, end, days in details:results.append({'对象ID': number,'连续出现天数': days,'首次发现日期': start.strftime('%Y%m%d'),'末次发现日期': end.strftime('%Y%m%d'),'连续天数详情': f"{start.strftime('%Y%m%d')}-{end.strftime('%Y%m%d')}"})return results

模拟数据这里就不提供了,下面是运行结果。
在这里插入图片描述

SQL版本解决方案

【基于mysql8+版本,用到了一些mysql5版本不支持的语法~】

创建模拟数据

CREATE TABLE OccurrenceDays (uid VARCHAR(100),dt DATE );INSERT INTO OccurrenceDays (uid, dt) VALUES  
('1234567890', '2023-04-01'),  
('1234567890', '2023-04-02'),  
('1234567890', '2023-04-03'),  
('1234567890', '2023-04-05'),  
('1234567890', '2023-04-06'),  
('1234567890', '2023-04-07'),  
('1234567890', '2023-04-10'),  
('1234567890', '2023-04-11'),  
('9876543210', '2023-04-02'),  
('9876543210', '2023-04-03'),  
('9876543210', '2023-04-04');

查询脚本:

WITH RankedDays AS (  SELECT   uid,  dt,  DATE_SUB(dt, INTERVAL ROW_NUMBER() OVER (PARTITION BY uid ORDER BY dt) DAY) AS grp  FROM   OccurrenceDays  
),  
GroupedDays AS (  SELECT   uid,  MIN(dt) AS start_dt,  MAX(dt) AS end_dt,  COUNT(*) AS consecutive_days  FROM   RankedDays  GROUP BY   uid, grp  HAVING   COUNT(*) > 1  
),  
ConsecutiveDetails AS (  SELECT   g.uid,  g.consecutive_days,  g.start_dt,  g.end_dt,  GROUP_CONCAT(od.dt ORDER BY od.dt SEPARATOR ',') AS consecutive_details  FROM   GroupedDays g  JOIN   OccurrenceDays od ON g.uid = od.uid AND od.dt BETWEEN g.start_dt AND g.end_dt  GROUP BY   g.uid, g.consecutive_days, g.start_dt, g.end_dt  
)  
SELECT   uid,  consecutive_days,  DATE_FORMAT(start_dt, '%Y%m%d') AS first_discovery_date,  DATE_FORMAT(end_dt, '%Y%m%d') AS last_discovery_date,  consecutive_details  
FROM   ConsecutiveDetails  
ORDER BY   uid, start_dt;

查询结果:

uidconsecutive_daysfirst_discovery_datelast_discovery_dateconsecutive_details
1234567890320230401202304032023-04-01,2023-04-02,2023-04-03
1234567890320230405202304072023-04-05,2023-04-06,2023-04-07
1234567890220230410202304112023-04-10,2023-04-11
9876543210320230402202304042023-04-02,2023-04-03,2023-04-04

不使用CTE语法

drop  table OccurrenceDays;   
CREATE TABLE OccurrenceDays (uid VARCHAR(100),dt VARCHAR(100)
);
-- 模拟数据
INSERT INTO OccurrenceDays (uid, dt) VALUES ('1234567890', '20230401');
INSERT INTO OccurrenceDays (uid, dt) VALUES ('1234567890', '20230402');
INSERT INTO OccurrenceDays (uid, dt) VALUES ('1234567890', '20230403');
INSERT INTO OccurrenceDays (uid, dt) VALUES ('1234567890', '20230405');
INSERT INTO OccurrenceDays (uid, dt) VALUES ('1234567890', '20230406');
INSERT INTO OccurrenceDays (uid, dt) VALUES ('1234567890', '20230407');
INSERT INTO OccurrenceDays (uid, dt) VALUES ('1234567890', '20230410');
INSERT INTO OccurrenceDays (uid, dt) VALUES ('1234567890', '20230411');
INSERT INTO OccurrenceDays (uid, dt) VALUES ('9876543210', '20230402');
INSERT INTO OccurrenceDays (uid, dt) VALUES ('9876543210', '20230403');
INSERT INTO OccurrenceDays (uid, dt) VALUES ('9876543210', '20230404');
INSERT INTO OccurrenceDays (uid, dt) VALUES ('9876543210', '20230405');
INSERT INTO OccurrenceDays (uid, dt) VALUES ('9876543210', '20230406');-- 查询脚本   
SELECT  uid,  COUNT(*) AS consecutive_days,  MIN(dt) AS first_occurrence_date,  MAX(dt) AS last_occurrence_date,  GROUP_CONCAT(dt ORDER BY dt) AS consecutive_days_detail  
FROM (  SELECT  uid,  dt,  dt - ROW_NUMBER() OVER (PARTITION BY uid ORDER BY STR_TO_DATE(dt, '%Y%m%d')) AS grp  FROM  OccurrenceDays  
) AS ranked_dates  
GROUP BY  uid, grp  
HAVING  COUNT(*) > 1  
ORDER BY  uid, MIN(dt);

输出结果:

uidconsecutive_daysfirst_occurrence_datelast_occurrence_dateconsecutive_days_detail
12345678903202304012023040320230401,20230402,20230403
12345678903202304052023040720230405,20230406,20230407
12345678902202304102023041120230410,20230411
98765432105202304022023040620230402,20230403,20230404,20230405,20230406

补充:模拟数据生成脚本

import random  
import datetime  def generate_sql_inserts(uid):  # 获取当前日期  today = datetime.date.today()  # 设定近3个月的开始日期  start_date = today - datetime.timedelta(days=90)  # 初始化SQL语句列表  sql_inserts = []  # 设定要插入的数据条数,这里可以调整  num_inserts = 30  # 用于追踪连续日期的计数器  consecutive_counter = 0  last_date = None  for _ in range(num_inserts):  # 生成随机日期,在最近三个月内  random_date = start_date + datetime.timedelta(days=random.randint(0, (today - start_date).days))  random_date_str = random_date.strftime('%Y%m%d')  # 以一定概率生成连续日期  if last_date and random.random() < 0.5:  # 假设有50%的概率生成连续日期  random_date_str = (last_date + datetime.timedelta(days=1)).strftime('%Y%m%d')  consecutive_counter += 1  else:  consecutive_counter = 0  last_date = datetime.datetime.strptime(random_date_str, '%Y%m%d').date()  # 生成SQL INSERT语句  sql_insert = f"INSERT INTO OccurrenceDays (uid, dt) VALUES ('{uid}', '{random_date_str}');"  sql_inserts.append(sql_insert)  return "\n".join(sql_inserts)  # 示例使用  
uid = "a"  
sql_script = generate_sql_inserts(uid)  
print(sql_script)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/679009.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

二层交换机与防火墙连通上网实验

防火墙是一种网络安全设备&#xff0c;用于监控和控制网络流量。它可以帮助防止未经授权的访问&#xff0c;保护网络免受攻击和恶意软件感染。防火墙可以根据预定义的规则过滤流量&#xff0c;例如允许或阻止特定IP地址或端口的流量。它也可以检测和阻止恶意软件、病毒和其他威…

Mysql基础(五)外键约束

一 外键 激励&#xff1a; 每天进步一点点即可 ① 思考 1、在MySQL中,我们知道主键 PRIMARY KEY的主要作用是唯一区分表中的各个行 [记录];思考&#xff1a;但是对于外键 foreign key比较陌生? 那么外键作用以及限制条件和目的呢? ② 外键的定义 1、外键是某个表 A中…

【3dmax笔记】027:配置修改器集、工具栏自定义与加载

文章目录 一、配置修改器集二、自定义工具栏三、加载工具栏 一、配置修改器集 可以把自己常用的修改命令放到右边框中的部分&#xff0c;便于自己的操作&#xff0c;省去了每次都要花半天时间找命令的尴尬。新建一个二维或者三维物体&#xff0c;点击修改面板&#xff0c;点击…

4.26.7具有超级令牌采样功能的 Vision Transformer

Vision Transformer在捕获浅层的局部特征时可能会受到高冗余的影响。 在神经网络的早期阶段获得高效且有效的全局上下文建模&#xff1a; ①从超像素的设计中汲取灵感&#xff0c;减少了后续处理中图像基元的数量&#xff0c;并将超级令牌引入到Vision Transformer中。 超像素…

(五)JSP教程——response对象

response对象主要用于动态响应客户端请求&#xff08;request&#xff09;&#xff0c;然后将JSP处理后的结果返回给客户端浏览器。JSP容器根据客户端的请求建立一个默认的response对象&#xff0c;然后使用response对象动态地创建Web页面、改变HTTP标头、返回服务器端地状态码…

[iOS]从拾遗到Runtime(上)

[iOS]从拾遗到Runtime(上) 文章目录 [iOS]从拾遗到Runtime(上)写在前面名词介绍instance 实例对象class 类对象meta-class 元类对象为什么要有元类&#xff1f; runtimeMethod(objc_method)SEL(objc_selector)IMP 类缓存(objc_cache)Category(objc_category) 消息传递消息传递的…

【数字经济】上市公司供应链数字化数据(2000-2022)

数据来源&#xff1a; 时间跨度&#xff1a;2000-2022年 数据范围&#xff1a;各上市企业 数据指标&#xff1a; 样例数据&#xff1a; 参考文献&#xff1a;[1]刘海建,胡化广,张树山,等.供应链数字化的绿色创新效应[J].财经研究,2023,49(03):4-18. 下载链接&#xff1a;https:…

深度学习网络:设计、开发和部署

​书籍&#xff1a;Deep Learning Networks: Design, Development and Deployment 作者&#xff1a;Jayakumar Singaram&#xff0c;S. S. Iyengar&#xff0c;Azad M. Madni 出版&#xff1a;Springer书籍下载-《​深度学习网络&#xff1a;设计、开发和部署》该教材为学生和工…

无意的一次学习,竟让我摆脱了Android控制?

由于鸿蒙的爆火&#xff0c;为了赶上时代先锋。到目前为止也研究过很长一段时间。作为一名Android的研发人员&#xff0c;免不了对其评头论足&#xff0c;指导文档如何写才算专业&#xff1f;页面如何绘制&#xff1f;页面如何跳转&#xff1f;有没有四大组件等等。 而Harmony…

企业车辆管理系统参考论文(论文 + 源码)

【免费】关于企业车辆管理系统.zip资源-CSDN文库https://download.csdn.net/download/JW_559/89282550 企业车辆管理系统 摘 要 随着经济的日益增长,车辆作为最重要的交通工具,在企事业单位中得以普及,单位的车辆数目已经远远不止简单的几辆,与此同时就产生了车辆资源的合理…

VINS初始化原理及代码

文章目录 预备符号定义代码中常用的容器&#xff1a; 初始化原理及步骤初始化目的初始化原理初始化步骤 初始化详细流程、原理及代码。参考文献 预备 符号定义 ( ⋅ ) w \left(\cdot\right)^w (⋅)w表示世界坐标系下的表示&#xff0c;Z轴与重力方向重合。 ( ⋅ ) b \left(\c…

设置默认表空间和重命名

目录 设置默认表空间 创建的临时表空间 tspace4 修改为默认临时表空间 创建的永久性表空间 tspace3 修改为默认永久表空间 重命名表空间 将表空间 tspace3 修改为 tspace3_1 Oracle从入门到总裁:​​​​​​https://blog.csdn.net/weixin_67859959/article/details/13520…