【pandas】计算最大连续间隔时间

import pandas as pd 

问题说明

数据中样本年份不连续,所以想办法知道每个样本的最大连续年份,比如说下面的df中A是3年,B是5年
df = pd.DataFrame({'id': 'A', 'year': [2000, 2001, 2003, 2005, 2006, 2007]}).append(
    pd.DataFrame({'id': 'B', 'year': [2001, 2003, 2004, 2005, 2006, 2007, 2009]}))
df
idyear
0A2000
1A2001
2A2003
3A2005
4A2006
5A2007
0B2001
1B2003
2B2004
3B2005
4B2006
5B2007
6B2009

方法1:使用分组循环

参考 : https://www.jianshu.com/p/718eb7a83c8e
思路,通过标记前后两个年份差大于1的为1,然后记性累计加总,最后使用value_counts得到小组最多的
计算较慢,但是方便得到其他信息
%%time
for name,group in df.groupby('id'):
    group['s'] = ((group['year'].shift(1).fillna(0) + 1).astype(int) != group['year']).cumsum()
    print('group:{}'.format(name))
    print(group['s'].value_counts()) 
group:A
3    3
1    2
2    1
Name: s, dtype: int64
group:B
2    5
3    1
1    1
Name: s, dtype: int64
Wall time: 1.99 s

方法2:使用agg聚合计算

使用agg,改善上一个方法计算太慢的缺陷
速度较大提升
%%time
df.groupby('id').agg(lambda x:(x.diff().fillna(0) -1 ).cumsum().value_counts().max())
Wall time: 13 ms
year
id
A3
B5
% % time
# 计算得出最大连续年份的起始和终点时间
df_min_year = df.groupby('id').agg(lambda x: x[(x.diff().fillna(0) - 1).cumsum() == (
    x.diff().fillna(0) - 1).cumsum().value_counts().nlargest(1).index[0]].values.min())
df_max_year = df.groupby('id').agg(lambda x: x[(x.diff().fillna(0) - 1).cumsum() == (
    x.diff().fillna(0) - 1).cumsum().value_counts().nlargest(1).index[0]].values.max())
df_min_year.join(df_max_year, rsuffix='_max')
Wall time: 32 ms
yearyear_max
id
A20052007
B20032007

方法3:使用agg加numpy

咨询大佬的答案,速度更快但
%%time
df.groupby('id').agg(lambda x: np.diff(np.flatnonzero(np.diff(
    np.r_[0, (x.diff().fillna(1)-1) == 0, 0])).reshape(-1, 2), axis=1).max()+1)
Wall time: 9 ms
year
id
A3
B5

tips:apply和agg

对于df.groupby.apply(lambda x:fun(x)中x为dataframe,即对dataframe操作
对于df.groupby.agg(lambda x:fun(x)中x为(n-1)个series,n是列数量
使用内置函数速度大于自定义函数
df['make'] = 3
df
idyearmake
0A20003
1A20013
2A20033
3A20053
4A20063
5A20073
0B20013
1B20033
2B20043
3B20053
4B20063
5B20073
6B20093
df.groupby('id').agg(lambda x:print(x))
0    2000
1    2001
2    2003
3    2005
4    2006
5    2007
Name: year, dtype: int64
0    2001
1    2003
2    2004
3    2005
4    2006
5    2007
6    2009
Name: year, dtype: int64
0    3
1    3
2    3
3    3
4    3
5    3
Name: make, dtype: int64
0    3
1    3
2    3
3    3
4    3
5    3
6    3
Name: make, dtype: int64
yearmake
id
ANoneNone
BNoneNone
df.groupby('id').apply(lambda x:print(x))
  id  year  make
0  A  2000     3
1  A  2001     3
2  A  2003     3
3  A  2005     3
4  A  2006     3
5  A  2007     3
  id  year  make
0  A  2000     3
1  A  2001     3
2  A  2003     3
3  A  2005     3
4  A  2006     3
5  A  2007     3
  id  year  make
0  B  2001     3
1  B  2003     3
2  B  2004     3
3  B  2005     3
4  B  2006     3
5  B  2007     3
6  B  2009     3
%%time
df.groupby('id').agg('sum')
Wall time: 6 ms
yearmake
id
A1202218
B1403521
%%time
df.groupby('id').agg(lambda x:x.sum())
Wall time: 12 ms
yearmake
id
A1202218
B1403521
%%time
df.groupby('id').apply(lambda x:x.sum())
Wall time: 9.01 ms
idyearmake
id
AAAAAAA1202218
BBBBBBBB1403521

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值