Python 在groupby中计算具有连续日期的行

Python 在groupby中计算具有连续日期的行,python,pandas,dataframe,Python,Pandas,Dataframe,假设我的数据框看起来像这样: d = {'item_number':['K208UL','AKD098008','DF900A','K208UL','AKD098008'] 'Comp_ID':['998798098','988797387','12398787','998798098','988797387'] 'date':['2016-11-12','2016-11-13','2016-11-17','2016-11-13','2016-11-14']} df = p

假设我的数据框看起来像这样:

d = {'item_number':['K208UL','AKD098008','DF900A','K208UL','AKD098008']
     'Comp_ID':['998798098','988797387','12398787','998798098','988797387']
     'date':['2016-11-12','2016-11-13','2016-11-17','2016-11-13','2016-11-14']}

df = pd.DataFrame(data=d)
我想计算连续几天观察到相同
项目编号
Comp\u ID
的次数

我想这看起来会像是:

g = df.groupby(['Comp_ID','item_number'])
g.apply(lambda x: x.loc[x.iloc[i,'date'].shift(-1) - x.iloc[i,'date'] == 1].count())
然而,在比较之前,我需要从每个日期中提取日期作为int,这也是我遇到的问题

for i in df.index:
    wbc_seven.iloc[i, 'day_column'] = datetime.datetime.strptime(df.iloc[i,'date'],'%Y-%m-%d').day

显然,基于位置的索引只允许整数?如何解决此问题?

一种解决方案是使用数据透视表来计算连续几天观察到的
Comp\u ID
item\u number
的次数

import pandas as pd

d = {'item_number':['K208UL','AKD098008','DF900A','K208UL','AKD098008'],'Comp_ID':['998798098','988797387','12398787','998798098','988797387'],'date':['2016-11-12','2016-11-13','2016-11-17','2016-11-13','2016-11-14']}

df = pd.DataFrame(data=d).sort_values(['item_number','Comp_ID'])
df['date'] = pd.to_datetime(df['date'])
df['delta'] = (df['date'] - df['date'].shift(1))
df = df[(df['delta']=='1 days 00:00:00.000000000') & (df['Comp_ID'] == df['Comp_ID'].shift(1)) & 
        (df['item_number'] == df['item_number'].shift(1))].pivot_table( index=['item_number','Comp_ID'],
           values=['date'],aggfunc='count').reset_index()
df.rename(columns={'date':'consecutive_days'},inplace =True)
导致

  item_number    Comp_ID  consecutive_days
0   AKD098008  988797387                 1
1      K208UL  998798098                 1 
但是,我需要从每个日期中提取日期作为int 在比较之前,我也有问题

为什么? 要修复代码,您需要:

consecutive['date'] = pd.to_datetime(consecutive['date'])
g = consecutive.groupby(['Comp_ID','item_number'])
g['date'].apply(lambda x: sum(abs((x.shift(-1) - x)) == pd.to_timedelta(1, unit='D')))
注意以下几点:

  • 上面的代码避免了重复。这是一个基本的编程原则:
  • 它将1转换为
    timedelta
    ,以便进行适当的比较
  • 它需要绝对的差异

  • 提示:为您的工作编写顶级函数,而不是
    lambda
    ,因为它符合更好的可读性、简洁性和美观性:

    def differencer(grp, day_dif):
        """Counts rows in grp separated by day_dif day(s)"""
        d = abs(grp.shift(-1) - grp)
        return sum(d == pd.to_timedelta(day_dif, unit='D'))
    g['date'].apply(differencer, day_dif=1)
    

    说明:
    这很简单。然后减去日期。差异将导致a,它还需要与
    timedelta
    对象进行比较,因此将1(或
    day_dif
    )转换为
    timedelta
    。该转换的结果将是布尔级数。布尔值表示为0表示
    False
    ,1表示
    True
    。布尔数列之和将返回该数列中
    True
    值的总数。

    我遇到了以下错误:TypeError:-:“str”和“str”的操作数类型不受支持。显然,您需要将“date”列转换为
    Timestamp
    类型。分组前使用此
    连续['date']=pd.to_datetime(连续['date'])
    。我也会编辑答案。太棒了!从我的第一轮QA来看,它看起来工作得很好。我并没有想象的那么远。如果您能就代码中发生的事情添加一些解释,我将不胜感激@卡尔蒂基补充了一个解释。另外,稍微简化一下,您不需要使用比较返回的布尔序列再次建立索引。一个简单的
    sum
    就足够了。你肯定离得不远了,干得好:-)。请接受答案,若你们觉得有用,请投票表决。那些控件在答案的左边。我还没有投票的代表点数,但def正是我想要的!