python - 在 Pandas Dataframe中,两个日期之间的GroupBy行的python 计数数

  显示原文与译文双语对照的内容

我有一个 dataframe df,可以用下面的代码创建它:


import random


from datetime import timedelta


import pandas as pd


import datetime



#create test range of dates


rng=pd.date_range(datetime.date(2015,7,15),datetime.date(2015,7,31))


rnglist=rng.tolist()


testpts = range(100,121)


#create test dataframe


d={'jid':[i for i in range(100,121)], 


 'cid':[random.randint(1,2) for _ in testpts],


 'ctid':[random.randint(3,4) for _ in testpts], 


 'stdt':[rnglist[random.randint(0,len(rng))] for _ in testpts]}


df=pd.DataFrame(d)[['jid','cid','ctid','stdt']]


df['enddt'] = df['stdt']+timedelta(days=random.randint(2,16))



df的外观如下:


 jid cid ctid stdt enddt


0 100 1 4 2015-07-28 2015-08-11


1 101 2 3 2015-07-31 2015-08-14


2 102 2 3 2015-07-31 2015-08-14


3 103 1 3 2015-07-24 2015-08-07


4 104 2 4 2015-07-27 2015-08-10


5 105 1 4 2015-07-27 2015-08-10


6 106 2 4 2015-07-24 2015-08-07


7 107 2 3 2015-07-22 2015-08-05


8 108 2 3 2015-07-28 2015-08-11


9 109 1 4 2015-07-20 2015-08-03


10 110 2 3 2015-07-29 2015-08-12


11 111 1 3 2015-07-29 2015-08-12


12 112 1 3 2015-07-27 2015-08-10


13 113 1 3 2015-07-21 2015-08-04


14 114 1 4 2015-07-28 2015-08-11


15 115 2 3 2015-07-28 2015-08-11


16 116 1 3 2015-07-26 2015-08-09


17 117 1 3 2015-07-25 2015-08-08


18 118 2 3 2015-07-26 2015-08-09


19 119 2 3 2015-07-19 2015-08-02


20 120 2 3 2015-07-22 2015-08-05



我需要做的是: 计数( cnt ) 由 cid 由产生的jid 数,对于 min(stdt)max(enddt) 之间的每个日期( newdate ),其中 newdatestdtenddt 之间的。

生成的DataFrame应该像( 这只适用于 1 cid,使用 1 ctid 上数据) ( 在本例中为 cid 1/ctid 4,cid 2/ctid 3,cid/ctid ):


cid ctid newdate cnt


1 3 7/21/2015 1


1 3 7/22/2015 1


1 3 7/23/2015 1


1 3 7/24/2015 2


1 3 7/25/2015 3


1 3 7/26/2015 4


1 3 7/27/2015 5


1 3 7/28/2015 5


1 3 7/29/2015 6


1 3 7/30/2015 6


1 3 7/31/2015 6


1 3 8/1/2015 6


1 3 8/2/2015 6


1 3 8/3/2015 6


1 3 8/4/2015 6


1 3 8/5/2015 5


1 3 8/6/2015 5


1 3 8/7/2015 5


1 3 8/8/2015 4


1 3 8/9/2015 3


1 3 8/10/2015 2


1 3 8/11/2015 1


1 3 8/12/2015 1



前一个问题( 我也是) 计数 # 日期之间的行非常相似,并用进行了回答。 我们已经很确定可以再次使用 melt,或者有更好的选项,但是我无法确定如何获得每个 ctid的每个 cidjid的大小,每个的大小为1. 喜欢你的输入。

时间: 原作者:

在尝试 @Scott 波士顿答案后,对于 1.8条记录 df,第一行


df_out = pd.concat([pd.DataFrame(index=pd.date_range(df.iloc[i].stdt,df.iloc[i].enddt)).assign(**df.iloc[i,0:3]) for i in pd.np.arange(df.shape[0])]).reset_index()



在 1小时后仍在运行并且慢慢地蚕食着记忆。 所以我想我应该尝试一下:


def reindex_by_date(df):


 dates = pd.date_range(df.index.min(), df.index.max())


 return df.reindex(dates)


def replace_last_0(group):


 group.loc[max(group.index),'change']=0


 return group



def ctidloop(partdf): 


 coid=partdf.cid.max()


 cols=['cid', 'stdt', 'enddt']


 partdf=partdf[cols]


 partdf['jid']=partdf.index


 partdf = pd.melt(partdf, id_vars=['ctid', 'jid'],var_name='change', value_name='newdate')


 partdf['change'] = partdf['change'].replace({'stdt': 1, 'enddt': -1})


 partdf.newdate=pd.DatetimeIndex(partdf['newdate'])


 partdf=partdf.groupby(['ctid', 'newdate'],as_index=False)['change'].sum()


 partdf=partdf.groupby('ctid').apply(replace_last_0).reset_index(drop=True)


 partdf['cnt'] = partdf.groupby('ctid')['change'].cumsum()


 partdf.index=partdf['newdate']


 cols=['ctid', 'change', 'cnt', 'newdate']


 partdf=partdf[cols]


 partdf=partdf.groupby('ctid').apply(reindex_by_date).reset_index(0, drop=True)


 partdf['newdate']=partdf.index


 partdf['ctid']=partdf['ctid'].fillna(method='ffill')


 partdf.cnt=partdf.cnt.fillna(method='ffill')


 partdf.change=partdf.change.fillna(0)


 partdf['cid']=coid


 return partdf


gb=df.groupby('cid').apply(ctidloop)



这里代码返回了正确的结果:


%timeit gb=df.groupby('cid').apply(ctidloop)


1 loop, best of 3: 9.74 s per loop 



说明:基本上,melt 非常快速。 所以我把第一个 groupby 分成几个组并在它上面运行一个函数。 所以这个代码接受 df,然后 groupsbycidapply 函数 cidloop

cidloop 中,以下一行发生: 1 ) 获取 cid 以便将来使用。 2,3通过分配所需的列( 4 ) 创建核心 partdf ) 从索引 5创建 jid ) 运行 flattens,为 stdtenddt 创建每个 jid的flattens 。 6 ) 创建一个 'change' 列,将 +1分配给 stdt,-1为 enddt 。 7 makes makes makes,groups,replacing,filling,filling,filling,filling,filling,replacing,replacing,replacing,replacing,replacing,replacing,replacing,replacing,makes,makes,makes,makes,makes,makes,makes,makes,makes 。 15 ) 从新的reindex 值 16,17 assign 18 ) 填充各种值填充间隙( 我需要这种增强) 19 ) 从第 1行中收集的顶部变量 coid 再次分配 cid

通过最后一行代码 gb=df.groupby..... 对每个 cid 执行这里操作

感谢 @Scott 波士顿尝试。 当然可以但对我来说太长了。

在这里,@DSM 为他的解决方案 Kudos,这是我解决方案的基础。

原作者:
...