确定分组后

时间:2019-02-06 20:07:28

标签: python pandas

我有一个数据集,其中每一行代表一个事件,并带有日期和有关该事件的一些信息。我想知道在按一列(a)分组之后,是否在短时间内(例如b)出现了另一种列(+/- 60 days)的多种类型并保留行在这种情况下。

具有如下所示的熊猫数据框:

     a      b          date
    foo    blue     2018-02-17
    foo    blue     2018-02-22
    foo    red      2018-04-28
    foo    blue     2018-04-29
    foo    blue     2018-05-02
    foo    red      2018-08-01
    bar    yellow   2018-01-25
    bar    red      2018-04-07
    bar    yellow   2018-07-11
    bar    yellow   2018-07-14
    baz    red      2018-03-11
    baz    blue     2018-04-14
    baz    red      2018-07-05
    baz    blue     2018-10-01

我想选择以下几行:

     a      b          date
    foo    red      2018-04-28
    foo    blue     2018-04-29
    foo    blue     2018-05-02
    baz    red      2018-03-11
    baz    blue     2018-04-14

1 个答案:

答案 0 :(得分:0)

从您粘贴的示例开始:

df = pd.DataFrame(columns=['a','b','date'],
                  data=[['foo','blue','2018-02-17'],['foo','blue','2018-02-22'],['foo','red','2018-04-28'],['foo','blue','2018-04-29'],['foo','blue','2018-05-02'],
                        ['foo','red','2018-08-01'],['bar','yellow','2018-01-25'],['bar','red','2018-04-07'],['bar','yellow','2018-07-11'],
                        ['bar','yellow','2018-07-14'],['baz','red','2018-03-11'],['baz','blue','2018-04-14'],['baz','red','2018-07-05'],['baz','blue','2018-10-01']])

df['date'] = pd.to_datetime(df['date'])
df

    a    b       date
0   foo  blue    2018-02-17
1   foo  blue    2018-02-22
2   foo  red     2018-04-28
3   foo  blue    2018-04-29
4   foo  blue    2018-05-02
5   foo  red     2018-08-01
6   bar  yellow  2018-01-25
7   bar  red     2018-04-07
8   bar  yellow  2018-07-11
9   bar  yellow  2018-07-14
10  baz  red     2018-03-11
11  baz  blue    2018-04-14
12  baz  red     2018-07-05
13  baz  blue    2018-10-01

在给定的时间范围内,我确定了需要在df中搜索哪些行子集。我使用与您的示例相同的60天(+/- 30天)的时间范围。

win_sz = pd.Timedelta(days=60)
start = df['date'].min() + win_sz/2
end = df['date'].max() - win_sz/2
to_search_over = df[(df['date'] > start) & (df['date'] <= end)]['date']

下一步

  • 对于上面to_search_over列表中的每一行,我抓取了df的子集,该子集的所有行的日期都在与我们的日期窗口大小相对应的日期范围内(在这种情况下为60天)。
  • 对于此窗口,我使用groupby()nunique()检查列a中的给定元素是否与列b中的值相关联。 / li>
  • 最后,我将满足此条件的所有行索引添加到列表(res)。
res = []

for d in to_search_over:
    mask = (df['date'] > d-(win_sz/2)) & (df['date'] <= d+(win_sz/2))
    window = df.loc[mask]
    a = window.groupby('a')['b'].nunique()
    a = a[a>1].index.values
    if a.any():
        res += list(window[window['a'].isin(a)].index)

我将此索引列表转换为集合,然后返回列表以仅保留唯一的行值。然后,我可以对df进行切片以返回满足我们条件的所有行:

df.iloc[list(set(res))]

    a    b      date
2   foo  red    2018-04-28
3   foo  blue   2018-04-29
4   foo  blue   2018-05-02
10  baz  red    2018-03-11
11  baz  blue   2018-04-14

我很高兴看到是否有人有一种更优雅的方法来完成此操作(这种方法不需要明确地在df行的子集上逐行迭代)。我花了一段时间试图找到一种使用pd.rolling的方法,但无济于事。