作者:才哥
☆
大家好,我是才哥。
最近在处理数据的时候遇到一个需求,核心就是求取最大连续行为天数。类似需求在去年笔者刚接触pandas的时候也做过《利用Python统计连续登录N天或以上用户》,这里我们可以用同样的方法进行实现。
这里我们用北京空气质量数据作为案例进行演示,需求是找出北京空气质量连续污染最长持续多久并确定其周期。
图1:案例数据
以上图中数据来算,我们可以看到从1月21日-1月26日空气质量连续污染持续了6天。
不过,在实际的数据处理中,我们的原始数据往往会较大,并不一定能直接看出来。接下来,我们介绍几种解决方案供大家参考。
大家可以直接在后台回复 0427
获取案例数据,同样也可以通过以下方式获取案例数据。
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
获取的数据是处理后的数据哈)
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:处理后数据
结合上次的《利用Python统计连续登录N天或以上用户》案例,我们这里再提供1种新的解题思路,合计2种解题思路。
以下解法来自小明哥
和才哥
才哥上次的解法就是这种思路,回看当初的代码显得比较稚嫩,今天我们看看小明哥的解法,非常精彩。
步骤1:筛选空气质量为污染的数据
t = aqi.query('空气质量=="污染"')
t.sample(5)
图4:筛选空气质量污染的数据
步骤2:新增辅助列(辅助列可以不用加到原数据t
上)
这里的逻辑大概如下:
groupids = pd.to_datetime(aqi.time)-pd.to_timedelta(aqi.time.rank(),unit='d')
groupids.sample(5)
图5:辅助列
步骤3:分组计数获得连续天数,分组求最小最大值获得连续 污染起止日期
t.groupby(groupids).agg({
'time': lambda x:f'{x.min()}~{x.max()}', # 求起止日期
'空气质量':"count", # 求连续天数
}).nlargest(5,'空气质量') # 取 空气质量 字段最大的前5组数据
图6:解法1的结果
以上完整代码如下:
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有两种解法,其一是利用循环创建辅助列,其二是利用shift和cumsum创建辅助列,具体我们可以往下看。
解法1:利用循环创建辅助列
last = None
num = 0
groupids = []
for v in aqi.空气质量.values:
if v != last or v != '污染':
num += 1
groupids.append(num)
last = v
我们根据这个逻辑可以得到辅助列数据如下:
图7:辅助列值预览
我们可以发现,按照辅助列分组进行计数即可获得连续污染天数,如上红色标记区域。
aqi.groupby(groupids).agg(
{
'time': lambda x:f'{x.min()}~{x.max()}',
'空气质量':"count",
}
).nlargest(5,'空气质量')
图8:思路2的解法1结果
解法2:利用shift和cumsum创建辅助列
图9:辅助列创建思路预览
我们也可以发现,按照辅助列分组计数即可获取空气质量连续天数(优良和污染均可),如上红色区域。
(
aqi.query('空气质量=="污染"') # 这里筛选 污染 天气
.groupby((aqi.空气质量.shift() != aqi.空气质量).cumsum()) # 辅助列
.time.agg(['count','min','max']) # 计数及获取日期区间
.nlargest(5,'count')
)
图9:思路2的解法2结果
按照小明哥的输出结果,调整代码如下:
(
aqi.query("空气质量=='污染'")
.groupby((aqi.空气质量 != aqi.空气质量.shift()).cumsum())
.agg(
{
'time': lambda x: f"{x.min()}~{x.max()}",
'空气质量': "count"}
).nlargest(5, '空气质量')
)
图10:思路2的解法2小明哥结果
以上就是本次全部内容,其实我们在日常工作生活中还可能遇到类似场景如:计算用户连续登录天数、计算用户连续付费天数、计算南方梅雨季节连续下雨天数等等!
如果你有更好的方案,欢迎添加作者微信一起交流学习!
作者微信号:gdc2918