连续活跃天数统计

news2025/1/15 14:17:14

连续活跃天数统计

需求说明

什么是连续出现?

假设有如下日期信息: 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 = 1
        start_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 += 1
            else:
                if consecutive_days > 1:
                    details.append((start_date, prev_date, consecutive_days))
                consecutive_days = 1
                start_date = date
            prev_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.coloradmin.cn/o/1653965.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Qt QML】ComboBox组件

ComboBox 是一个组合的按钮和弹出列表。它提供了一种以最小的屏幕空间呈现选项列表给用户的方式。ComboBox 使用数据模型填充。数据模型通常是一个 JavaScript 数组、一个 ListModel 或一个整数&#xff0c;但也支持其他类型的数据模型。 下面是一个简单的使用方式。 import …

关于Anaconda常用的命令

常用命令 查看当前环境下的环境&#xff1a;conda env list查看当前conda的版本&#xff1b;conda --version conda create -n your_env_name pythonX.X&#xff08;2.7、3.6等)命令创建python版本为X.X。名字为your_env_name的虚拟环境。your_env_name文件可以在Anaconda安装…

专题五_位运算(3)

目录 137. 只出现一次的数字 II 解析 题解 面试题 17.19. 消失的两个数字 解析 题解 137. 只出现一次的数字 II 137. 只出现一次的数字 II - 力扣&#xff08;LeetCode&#xff09; 解析 注意这里指的是比特位上的01来进行统计的 题解 class Solution { public:int sin…

二叉排序树(二叉搜索树)BST增删改查操作

一、定义 二叉搜索树&#xff08;Binary Search Tree&#xff0c;BST&#xff09;是一种常用的二叉树数据结构&#xff0c;具有以下特点&#xff1a; 1. **排序性质**&#xff1a;对于树中的每个节点&#xff0c;其左子树中的所有节点值都小于该节点的值&#xff0c;而右子树…

类和对象(中篇)(未完结)

文章目录 类的6个默认成员函数构造函数析构函数 类的6个默认成员函数 如果一个类中什么成员都没有&#xff0c;简称为空类。 class Date {};空类中真的什么都没有吗&#xff1f;并不是&#xff0c;任何类在什么都不写时&#xff0c;编译器会自动生成以下6个默认成员函数。 默…

《QT实用小工具·六十一》带动画的三角形指示箭头

1、概述 源码放在文章末尾 该项目实现了一个带动画效果的三角形指示箭头&#xff0c;项目demo演示如下所示&#xff1a; 用法 interestingindicate.h interestingindicate.cpp 放到工程中&#xff0c;直接使用即可。 注意&#xff1a;建议绝对布局&#xff0c;手动指定 wid…

分红76.39亿,分红率再创新高,成长活力无限的伊利带来丰厚回报

伊利47万股东&#xff0c;又等来了一个好消息。 4月29日&#xff0c;伊利股份发布2023年报&#xff0c;实现营业总收入1261.79亿元&#xff0c;归母净利润104.29亿元&#xff0c;双创历史新高&#xff0c;实现连续31年稳健增长。 在递交亮眼成绩单的同时&#xff0c;乳业巨头伊…

Linux系统编程--网络编程

一、OSI网络七层模型 OSI模型将整个网络通信过程分解为七个层次&#xff0c;每个层次都为网络通信提供了特定的功能。以下是OSI模型的七个层次&#xff0c;从上到下依次是&#xff1a; 应用层&#xff08;Application Layer&#xff09;&#xff1a;为应用软件提供网络服务&am…

MySQL部署系列-centos离线安装MySQL

MySQL部署系列-centos离线安装MySQL 文章目录 MySQL部署系列-centos离线安装MySQL1. 查看是否已经安装 Mysql3. 下载官方 Mysql 包3. 下载之后上传到服务器4. 创建用户组5. 创建数据目录并赋予权限6. 修改配置文件 vim /etc/my.cnf7. 初始化数据库(数据库安装)8. 加入到系统服务…

多个开源的js补环境框架测试

原文链接&#xff1a;https://mp.weixin.qq.com/s/uEMFGpE5bqmTvzSgX2twvA 前言 在做js逆向时肯定会遇到补环境的情况&#xff0c;看到github开源了好几个补环境用的框架&#xff0c;这篇文章做个测试&#xff0c;看看哪个比较好用。 https://github.com/pysunday/sdenvhttp…

word格式技巧

文章目录 论文格式技巧论文交叉引用怎么弄论文的页码怎么弄 论文格式技巧 论文交叉引用怎么弄 1.取消文献原有的编号 2.定义新编号 3.具体编号设置 4.在引用的地方插入&#xff0c;具体引用选项卡–>交叉引用–>选择后插入 2. 4. 论文的页码怎么弄 假设我们有这样一…

探索DeepSeek平台:新一代MoE模型的深度体验

简介 DeepSeek是一个创新的人工智能平台&#xff0c;它最近推出了其最新版本的模型——DeepSeek-V2 MoE&#xff08;Mixture of Experts&#xff09;。这个平台不仅提供了一个交互式的聊天界面&#xff0c;还提供了API接口&#xff0c;让用户可以更深入地体验和利用这一先进的…

scala速通(精简版)

1.变量和常量 var name [:VariableType] value // variable val name [:ConstantType] value // constant1.声明变量时&#xff0c;类型可以省略 2.类型定义后就不能修改言 3.变量声明必须有初始值 4.变量&#xff0c;常量分别用var&#xff0c;val声明修饰 2.标识符命名…

构建自己的docker镜像node.js

学习资源&#xff1a; 构建自己的 Docker 镜像_哔哩哔哩_bilibili 针对其中的一些比较困难的点写篇文章。 以下是对app.js的注释&#xff1a; // 使用 Koa 框架搭建 Node.js 应用的示例代码// 这两行代码引入了 koa 模块&#xff0c;并创建了一个新的 Koa 应用实例&#xf…

vue2项目升级到vue3经历分享4

后端重构&#xff0c;如果接口做好抽象封装&#xff0c;只需要考虑jar之间的兼容性问题&#xff0c;jdk版本不变&#xff0c;基本不用做太大的调整&#xff0c;但是前端就不一样&#xff0c;除了vue框架本身&#xff0c;css的调整&#xff0c;改起来更是让人头疼。前面写了vue2…

如何让vim支持python3

首先删除旧的vim。 sudo apt-get remove vim //输入re按下tab直接显示remove sudo apt-get remove vim-runtime sudo apt-get remove vim -tiny sudo apt-get remove vim-common 然后下载vim8源码&#xff1a; git clone https://github.com/vim/vim.git 进行编译安装…

一键剪辑1000条视频的矩阵系统小魔推到底有多牛?

小魔推是一款短视频营销工具&#xff0c;主要针对想做短视频营销的实体商家与企业。通过BGC、PGC、UGC流量的打造&#xff0c;帮助更多实体行业实现流量裂变与转化。通过小魔推不需要做额外的拍摄剪辑创作动作&#xff0c;只需要通过小魔推宣传码&#xff0c;就能一键发布带有门…

20240508请问GTX2080TI的300和300A核心的差异?

20240508请问GTX2080TI的300和300A核心的差异&#xff1f; 在拼多多/淘宝上&#xff0c;GTX2080TI的300A核心的会比300核心的贵100&#xffe5;左右。 但是怎么区分呢&#xff1f; 300a核心和300请问怎么区分呢&#xff1f;[嘻嘻] devicr ID diviceid 1e07是300a 1e04是300 Gp…

2024 GESP6级 编程第一题 游戏

题目描述 你有四个正整数 &#xff0c;并准备用它们玩一个简单的小游戏。 在一轮游戏操作中&#xff0c;你可以选择将 减去 &#xff0c;或是将 减去 。游戏将会进行多轮操作&#xff0c;直到当 时游戏结束。 你想知道游戏结束时有多少种不同的游戏操作序列。两种游戏操作…

docker-compose部署gitlab

需要提前安装docker和docker-compose环境 参考&#xff1a;部署docker-ce_安装部署docker-ce-CSDN博客 参考&#xff1a;docker-compose部署_docker compose部署本地tar-CSDN博客 创建gitlab的数据存放目录 mkdir /opt/gitlab && cd mkdir /opt/gitlab mkdir {conf…