前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >『数据分析』pandas计算连续行为天数的几种思路

『数据分析』pandas计算连续行为天数的几种思路

作者头像
可以叫我才哥
发布2021-08-05 15:15:51
7.1K2
发布2021-08-05 15:15:51
举报
文章被收录于专栏:可以叫我才哥可以叫我才哥
我们的第72篇原创

作者:才哥


大家好,我是才哥。

最近在处理数据的时候遇到一个需求,核心就是求取最大连续行为天数。类似需求在去年笔者刚接触pandas的时候也做过《利用Python统计连续登录N天或以上用户》,这里我们可以用同样的方法进行实现。

这里我们用北京空气质量数据作为案例进行演示,需求是找出北京空气质量连续污染最长持续多久并确定其周期。

图1:案例数据

以上图中数据来算,我们可以看到从1月21日-1月26日空气质量连续污染持续了6天。

不过,在实际的数据处理中,我们的原始数据往往会较大,并不一定能直接看出来。接下来,我们介绍几种解决方案供大家参考。

1. 获取案例数据

大家可以直接在后台回复 0427 获取案例数据,同样也可以通过以下方式获取案例数据。

代码语言:javascript
复制
import akshare as ak

air_quality_hist_df = ak.air_quality_hist(city="北京", period="day", start_date="2021-01-01", end_date="2021-04-26")
air_quality_hist_df.head()

图2:akshare数据预览

由于我们只需要用到aqi,并按照国际标准进行优良与污染定级,这里简单做下数据处理如下:(后台直接回复0427获取的数据是处理后的数据哈)

代码语言:javascript
复制
import pandas as pd

# 重置索引
aqi = air_quality_hist_df['aqi'].reset_index()
# 将aqi列改为int类型
aqi.aqi = aqi.aqi.astype('int')
# 使用分箱进行空气质量定级
aqi['空气质量'] = pd.cut(aqi.aqi,
                        bins=[0,100,500],
                        labels=['优良','污染'])
# 取10个样本预览
aqi.sample(10)

图3:处理后数据

2. 求连续污染持续天数

结合上次的《利用Python统计连续登录N天或以上用户》案例,我们这里再提供1种新的解题思路,合计2种解题思路。

以下解法来自小明哥才哥

2.1. 思路1:按时间排序求差值再分组计数

才哥上次的解法就是这种思路,回看当初的代码显得比较稚嫩,今天我们看看小明哥的解法,非常精彩。

步骤1:筛选空气质量为污染的数据

代码语言:javascript
复制
t = aqi.query('空气质量=="污染"')
t.sample(5)

图4:筛选空气质量污染的数据

步骤2:新增辅助列(辅助列可以不用加到原数据t上)

这里的逻辑大概如下:

  • 辅助排名列(按照时间顺序排序)为间隔天数
  • 然后用时间字段(time)与间隔天数求差值得到一个日期
  • 如果得到的这个日期相同,则这几天是连续污染天
代码语言:javascript
复制
groupids = pd.to_datetime(aqi.time)-pd.to_timedelta(aqi.time.rank(),unit='d')
groupids.sample(5)

图5:辅助列

步骤3:分组计数获得连续天数,分组求最小最大值获得连续 污染起止日期

代码语言:javascript
复制
t.groupby(groupids).agg({
    'time': lambda x:f'{x.min()}~{x.max()}', # 求起止日期
    '空气质量':"count", # 求连续天数
}).nlargest(5,'空气质量') # 取 空气质量 字段最大的前5组数据

图6:解法1的结果

以上完整代码如下:

代码语言:javascript
复制
t = aqi.query('空气质量=="污染"')
t.groupby(
    pd.to_datetime(t.time)-pd.to_timedelta(t.time.rank(),unit='d')
         ).agg(
    {
    'time': lambda x:f'{x.min()}~{x.max()}',
    '空气质量':"count",
    }
).nlargest(5,'空气质量')

2.2. 思路2:比对相邻两天空气质量标记

思路2有两种解法,其一是利用循环创建辅助列,其二是利用shift和cumsum创建辅助列,具体我们可以往下看。

解法1:利用循环创建辅助列

  • 创建一个辅助列,辅助列的值按照以下思路创建函数获取
  • 如果空气质量为优良,则辅助列值+1;若当前空气质量和上一日不同,则辅助列值也+1
  • 以上均不满足,则辅助列值不变
代码语言:javascript
复制
last = None
num = 0
groupids = []
for v in aqi.空气质量.values:
    if v != last or v != '污染':
        num += 1
    groupids.append(num)
    last = v

我们根据这个逻辑可以得到辅助列数据如下:

图7:辅助列值预览

我们可以发现,按照辅助列分组进行计数即可获得连续污染天数,如上红色标记区域。

代码语言:javascript
复制
aqi.groupby(groupids).agg(
    {
    'time': lambda x:f'{x.min()}~{x.max()}',
    '空气质量':"count",
    }
).nlargest(5,'空气质量')

图8:思路2的解法1结果

解法2:利用shift和cumsum创建辅助列

  • 先创建空气质量的shift列,下移动一位
  • 如果shift列和空气质量列相等,则判断列为0,否则为1
  • 辅助列为判断列累加求和

图9:辅助列创建思路预览

我们也可以发现,按照辅助列分组计数即可获取空气质量连续天数(优良和污染均可),如上红色区域。

代码语言:javascript
复制
(
    aqi.query('空气质量=="污染"') # 这里筛选 污染 天气
    .groupby((aqi.空气质量.shift() != aqi.空气质量).cumsum()) # 辅助列
    .time.agg(['count','min','max']) # 计数及获取日期区间
    .nlargest(5,'count')
)

图9:思路2的解法2结果

按照小明哥的输出结果,调整代码如下:

代码语言:javascript
复制
(
    aqi.query("空气质量=='污染'")
    .groupby((aqi.空气质量 != aqi.空气质量.shift()).cumsum())
    .agg(
    {
        'time': lambda x: f"{x.min()}~{x.max()}", 
        '空气质量': "count"}
    ).nlargest(5, '空气质量')
)

图10:思路2的解法2小明哥结果

以上就是本次全部内容,其实我们在日常工作生活中还可能遇到类似场景如:计算用户连续登录天数计算用户连续付费天数计算南方梅雨季节连续下雨天数等等!

如果你有更好的方案,欢迎添加作者微信一起交流学习!

作者微信号:gdc2918

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-04-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 可以叫我才哥 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 获取案例数据
  • 2. 求连续污染持续天数
    • 2.1. 思路1:按时间排序求差值再分组计数
      • 2.2. 思路2:比对相邻两天空气质量标记
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档