通过与连续组进行比较来过滤pandas groupby

时间:2017-01-06 16:37:02

标签: python pandas

我有一个像这样的pandas数据框:

In [5]: df
Out[5]:
       date1      date2
0 2015-01-01 2014-12-11
1 2015-01-01 2014-12-30
2 2015-01-01 2015-01-01
3 2015-01-02 2015-12-30
4 2015-01-02 2015-01-01
5 2015-01-02 2015-01-02
6 2015-01-03 2015-01-01
7 2015-01-03 2015-01-02
8 2015-01-03 2015-01-03

我想在date1上对此数据框进行分组,然后按照date2> = PREVIOUS组date1的记录过滤每个组(并且没有任何记录date1 {1}}将被过滤掉)。我的最终目标是计算应用过滤器后每组中剩余的项目数。

过滤将留下以下行:

       date1    date2
0 2015-01-01  2014-12-11
1 2015-01-01  2014-12-30
2 2015-01-02  2015-01-01
4 2015-01-02  2015-01-01
5 2015-01-02  2015-01-02
7 2015-01-03  2015-01-02
8 2015-01-03  2015-01-03

然后计数将是:

    date1    count
0 2015-01-01 3
1 2015-01-02 2
2 2015-01-03 2

我可以按如下方式获取群组:

groups = df.sort('timestamp', ascending=False).groupby('timestamp')

但是我想不出一种方法来进行过滤和计数,以便比较连续的组。

3 个答案:

答案 0 :(得分:2)

使用pd.merge_asof

的一行
pd.merge_asof(
    df, df[['date1']].assign(d_=df.date1),
    allow_exact_matches=False
).fillna(0).query('date2 >= d_').groupby('date1').size()

date1
2015-01-01    3
2015-01-02    2
2015-01-03    2
dtype: int64

<强> 解释

from the docs

  

对于左侧DataFrame中的每一行,我们选择右侧DataFrame中的最后一行,其中“on”键小于或等于左侧的键。两个DataFrame必须按键排序。

因此,dfdate1allow_exact_matches合并为Falsequerygroupby。这让我可以轻松访问“上一组”。

从那里开始,我需要size来过滤,UseDefaultCredentials + <system.net> <mailSettings> <smtp deliveryMethod="network"> <network host="localhost" port="25" defaultCredentials="true" /> </smtp> </mailSettings> </system.net> 才能获得点数。

答案 1 :(得分:1)

我认为您可以Series为地图之前的值创建s groups,并且NaN的值也会替换为min(更快为{{} 1}}使用fillna):

at

然后groupby并过滤值,用于计数sum布尔值掩码:

#if df is not sorted by column date1
df = df.sort_values('date1')

s = pd.Series(df.date1.values, index = df.date1).drop_duplicates().shift()
s.at[s.index[0]] = pd.Timestamp.min
print (s)
date1
2015-01-01   1677-09-21 00:12:43.145225
2015-01-02   2015-01-01 00:00:00.000000
2015-01-03   2015-01-02 00:00:00.000000
dtype: datetime64[ns]

答案 2 :(得分:1)

我首先会创建一个名为previous_group的列,以便您可以直观地看到每个date1分组的上一个组。

df['previous_group'] = df['date1'].drop_duplicates().shift(1)
df['previous_group'] = df['previous_group'].fillna(method='ffill')

输出

注意:我将第3行的date2更改为2014年,这是我的意图。

       date1      date2 previous_group
0 2015-01-01 2014-12-11            NaT
1 2015-01-01 2014-12-30            NaT
2 2015-01-01 2015-01-01            NaT
3 2015-01-02 2014-12-30     2015-01-01
4 2015-01-02 2015-01-01     2015-01-01
5 2015-01-02 2015-01-02     2015-01-01
6 2015-01-03 2015-01-01     2015-01-02
7 2015-01-03 2015-01-02     2015-01-02
8 2015-01-03 2015-01-03     2015-01-02

过滤掉行

然后,您可以使用布尔索引过滤掉不需要的行,仅保留满足条件的行和第一个每次都缺少值的行。

df1 = df[(df['date2'] >= df['previous_group']) | df['previous_group'].isnull()]

输出

       date1      date2 previous_group
0 2015-01-01 2014-12-11            NaT
1 2015-01-01 2014-12-30            NaT
2 2015-01-01 2015-01-01            NaT
4 2015-01-02 2015-01-01     2015-01-01
5 2015-01-02 2015-01-02     2015-01-01
7 2015-01-03 2015-01-02     2015-01-02
8 2015-01-03 2015-01-03     2015-01-02

计算日期

然后您可以使用value_counts来计算日期

df1['date1'].value_counts()

输出

2015-01-01    3
2015-01-03    2
2015-01-02    2

总而言之,它将是:

df['previous_group'] = df['date1'].drop_duplicates().shift(1)
df['previous_group'] = df['previous_group'].fillna(method='ffill')
df1 = df[(df['date2'] >= df['previous_group']) | df['previous_group'].isnull()]
df1['date1'].value_counts()