2016-11-17 67 views
2

This is the closest to what i'm looking for that I've found计数行与大熊猫GROUPBY内连续日期

比方说,我的数据框看起来是这样的:

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) 

我想算在同一item_numberComp_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 

显然基于位置的索引只允许整数?我怎么能解决这个问题?

回答

0

一种解决方案将是使用透视表来计数的次数Comp_ID数目和观察在连续天数的item_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 
0

However, I would need to extract the day from each date as an int before comparing, which I'm also having trouble with.

为什么?

要解决你的代码,你需要:

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. 上面的代码避免重复。这是一个基本的编程原则:Don't Repeat Yourself
  2. 它将1转换为timedelta以进行正确比较。
  3. 它需要绝对的差异。

提示,写一个顶级功能为您的工作,而不是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) 

说明:

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

+0

我得到这个错误:TypeError:不支持的操作数类型为 - :'str'和'str' –

+0

显然,您需要将'date'列转换为'Timestamp'类型。在分组之前,使用此[连续['日期'] = pd.to_datetime(连续['日期'])''。我也会在答案中进行编辑。 – Kartik

+0

太棒了!从我的第一轮质量保证看起来,这个工作很好。我并没有想象中那么遥远。如果你可以添加一些关于你的代码中发生的事情的解释,我会非常感激。 @Kartik –