【问题标题】:pandas operation by grouppandas 分组操作
【发布时间】:2020-11-09 17:04:10
【问题描述】:

我有一个这样的数据框

df = pd.DataFrame({'id': [205,205,205, 211, 211, 211]
                  , 'date': pd.to_datetime(['2019-12-01','2020-01-01', '2020-02-01'
                                           ,'2019-12-01' ,'2020-01-01', '2020-03-01'])})
df

    id  date
0   205 2019-12-01
1   205 2020-01-01
2   205 2020-02-01
3   211 2019-12-01
4   211 2020-01-01
5   211 2020-03-01

date 的列是按连续月份为id 205 而不是id 211

我只想保留我有没有跳跃的月度数据的观察值 (id)。在这个例子中我想要:

    id  date
0   205 2019-12-01
1   205 2020-01-01
2   205 2020-02-01

这里我收集id留着:

keep_id = []
for num in pd.unique(df.index):
    temp = (df.loc[df['id']==num,'date'].dt.year - df.loc[df['id']==num,'date'].shift(1).dt.year) * 12 + df.loc[df['id']==num,'date'].dt.month - df.loc[df['id']==num,'date'].shift(1).dt.month
    temp.values[0] = 1.0 # here I correct the first entry
    if (temp==1.).all():
        keep_id.append(num)

我使用(df.loc[num,'date'].dt.year - df.loc[num,'date'].shift(1).dt.year) * 12 + df.loc[num,'date'].dt.month - df.loc[num,'date'].shift(1).dt.month 计算每个id 与前一个date 的月差。

df 的一小部分测试时,这似乎有效,但我确信有更好的方法来做到这一点,也许使用.groupby() 方法。

由于df 由数百万个观察组成,我的代码花费了太多时间(我想学习一种更高效和 Python 的方法)

【问题讨论】:

  • 强烈建议您不要将您的索引设置为id 列。如果这样做,您的索引将不再具有每一行的唯一值,并且会失去大部分功能和实用性。
  • 好的,谢谢。我在想。我现在就改!

标签: python pandas date data-manipulation


【解决方案1】:

您想要做的是使用 groupby-filter 而不是 groupby 应用。

df.groupby('id').filter(lambda x: not (x.date.diff() > pd.Timedelta(days=32)).any())

确切地提供:

    id       date
0  205 2019-12-01
1  205 2020-01-01
2  205 2020-02-01

确实,我会保持索引唯一,有太多有用的特征需要保留。

就输出而言,此响应和 Michael 的上述响应都是正确的。在性能方面,它们也非常相似:

%timeit df.groupby('id').filter(lambda x: not (x.date.diff() > pd.Timedelta(days=32)).any())
1.48 ms ± 12.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit df[df.groupby('id')['date'].transform(lambda x: x.diff().max() < pd.Timedelta(days=32))]
1.7 ms ± 163 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

对于大多数操作,这种差异可以忽略不计。

【讨论】:

  • 您能补充一下dt 的来源吗?是的,我做了一个.reset_index() 让它独一无二
  • 抱歉,编辑回复,我使用了 datetime timedelta,但 pandas 也可以正常工作。
  • 使用更大的数据帧,您的方法会明显更快。我试过df = pd.concat([df] * 10**5)。你的解决方案10 loops, best of 3: 57.2 ms per loop,我的解决方案10 loops, best of 3: 131 ms per loop。我以前不知道groupby.filter
  • 没想到会有这么大的不同,感谢您的检查。
  • 太棒了!这花了我 30 分钟,无法想象我的原始代码
【解决方案2】:

您可以使用以下方法。在我的测试中只快了约 3 倍。

df[df.groupby('id')['date'].transform(lambda x: x.diff().max() < pd.Timedelta(days=32))]

输出:

          date
id            
205 2019-12-01
205 2020-01-01
205 2020-02-01

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-31
    • 2017-03-17
    • 2021-11-07
    • 2013-05-17
    • 1970-01-01
    • 2015-05-06
    • 2022-12-22
    相关资源
    最近更新 更多