【问题标题】:How to exclude current date in a group by value rolling window execution in pandas?如何在熊猫中按值滚动窗口执行排除组中的当前日期?
【发布时间】:2019-06-21 13:54:49
【问题描述】:

我有一个包含 ID、日期和数值的数据框。我将每个 ID 的数据分组,然后计算前面行的累积量,时间窗口为 30 天。在下面的数据框中,这是使用下面的代码完成的(实际的数据框包含多个 ID 和多个日期)。

简而言之,SUM_AMOUNT 列是基于其他列创建的。

代码:

def get_rolling_amount(grp, freq, on_name, column_name):
    return grp.rolling(freq, on=on_name, closed='left')[column_name].sum()

df[new_column_name] = df.groupby('ID', as_index=False, group_keys=False)\
                         .apply(get_rolling_amount, '30D', 'DATE', 'AMOUNT')

数据框:

         ID       DATE                  AMOUNT                SUM_AMOUNT
111935   100000   2015-02-18            455.00                    NaN
111936   100000   2015-02-18            455.00                 455.00
111937   100000   2015-04-02            455.00                    NaN
111938   100000   2015-04-02            925.00                 455.00
111939   100000   2015-04-02           2780.00                1380.00
111940   100000   2015-04-09            895.00                4160.00
111941   100000   2015-04-09            425.00                5055.00
111942   100000   2015-04-09            425.00                5480.00
111943   100000   2015-04-09            925.00                5905.00
111944   100000   2015-04-09            455.00                6830.00
111947   100000   2015-05-21           1003.00                    NaN
111945   100000   2015-05-26            455.00                1003.00
111946   100000   2015-05-26            925.00                1458.00
111948   100000   2015-05-26            455.00                2383.00
111949   100000   2015-05-26           2780.00                2838.00
111950   100000   2015-05-26            425.00                5618.00
111951   100000   2015-05-26           1000.00                6043.00
111952   100000   2015-05-26            455.00                7043.00
111953   100000   2015-05-26            455.00                7498.00
111954   100000   2015-06-19            925.00                7953.00
111955   100000   2015-06-19           1820.00                8878.00
111956   100000   2015-06-19            925.00               10698.00

如您所见,每个 ID 都有具有相同日期的行。我无法以更详细的形式获得日期。我不想在计算中考虑相同日期的值,因为如果它们在同一日期并且顺序很重要,我不知道它们的顺序是什么。

我真正想要的

我希望能够获得过去 30 天范围内的所有数据点的累积总和,不包括当前行的日期。 我已更改数据框以反映我想要的内容:

         ID       DATE                  AMOUNT                SUM_AMOUNT
111935   100000   2015-02-18            455.00                    NaN
111936   100000   2015-02-18            455.00                    NaN
111937   100000   2015-04-02            455.00                    NaN
111938   100000   2015-04-02            925.00                    NaN
111939   100000   2015-04-02           2780.00                    NaN
111940   100000   2015-04-09            895.00                4160.00
111941   100000   2015-04-09            425.00                4160.00
111942   100000   2015-04-09            425.00                4160.00
111943   100000   2015-04-09            925.00                4160.00
111944   100000   2015-04-09            455.00                4160.00
111947   100000   2015-05-21           1003.00                    NaN
111945   100000   2015-05-26            455.00                1003.00
111946   100000   2015-05-26            925.00                1003.00
111948   100000   2015-05-26            455.00                1003.00
111949   100000   2015-05-26           2780.00                1003.00
111950   100000   2015-05-26            425.00                1003.00
111951   100000   2015-05-26           1000.00                1003.00
111952   100000   2015-05-26            455.00                1003.00
111953   100000   2015-05-26            455.00                1003.00
111954   100000   2015-06-19            925.00                7953.00
111955   100000   2015-06-19           1820.00                7953.00
111956   100000   2015-06-19            925.00                7953.00

因此,如果该行的日期为 2015-06-19,我希望在 30 天的窗口中获得所有先前行的总和,但日期为 2015-06-19 的行不应包含在该窗口中.

另一件重要的事情是我不能折叠行以使每个 ID 和 DATE 成为一行。

我该怎么做?

【问题讨论】:

  • 您可以使用DataFrame.drop_duplicates... I cannot collapse the rows to make one row per ID and DATE. - 为什么??
  • IIUC,索引为 111938 和 111937 的行应该是NaN,不是吗?
  • @Ben.T 你是对的,解决了这个问题。
  • @wwii 为了以后的处理,我需要将每一行分开。

标签: python pandas dataframe


【解决方案1】:

因为您在同一天有多个值,我会说您应该首先每天resample 以每天获得sum,然后在使用 @ 的日期之前的最后 30 个值上获得rolling 987654323@ 不包括今天。使用groupby 每个 ID 执行这些操作,然后在 ID 和 DATE 上使用 merge df

df = df.merge( (df.groupby('ID').resample('1D', on='DATE').sum()['AMOUNT'].shift()
                  .rolling(30, min_periods=1).sum().fillna(0).reset_index()), 
               on = ['ID', 'DATE'], how='left', suffixes=('', '_SUM'))

你会得到df,例如:

        DATE      ID  AMOUNT  AMOUNT_SUM
0  2015-02-18  100000   455.0         0.0
1  2015-02-18  100000   455.0         0.0
2  2015-04-02  100000   455.0         0.0
3  2015-04-02  100000   925.0         0.0
4  2015-04-02  100000  2780.0         0.0
5  2015-04-09  100000   895.0      4160.0
6  2015-04-09  100000   425.0      4160.0
7  2015-04-09  100000   425.0      4160.0
8  2015-04-09  100000   925.0      4160.0
9  2015-04-09  100000   455.0      4160.0
10 2015-05-21  100000  1003.0         0.0
11 2015-05-26  100000   455.0      1003.0
12 2015-05-26  100000   925.0      1003.0
13 2015-05-26  100000   455.0      1003.0
14 2015-05-26  100000  2780.0      1003.0
15 2015-05-26  100000   425.0      1003.0
16 2015-05-26  100000  1000.0      1003.0
17 2015-05-26  100000   455.0      1003.0
18 2015-05-26  100000   455.0      1003.0
19 2015-06-19  100000   925.0      7953.0
20 2015-06-19  100000  1820.0      7953.0
21 2015-06-19  100000   925.0      7953.0

【讨论】:

  • 谢谢,这是我需要的开箱即用的方法。像魅力一样工作。
【解决方案2】:

您可以迭代 df 的行并每次定义一个新掩码:

df = pd.DataFrame({'Date' : ["2015-02-18", "2015-02-18", "2015-04-02", "2015-04-02", "2015-04-02", "2015-04-09"],
                  'Amount' : [455, 455, 455, 925, 2780, 895]})
  Date  Amount
0  2015-02-18     455
1  2015-02-18     455
2  2015-04-02     455
3  2015-04-02     925
4  2015-04-02    2780
5  2015-04-09     895

# We make sure our type is date
df['Date'] = pd.to_datetime(df['Date'], format='%Y-%m-%d')

for index, row in df.iterrows():
    # We look on previous rows with dates within 30 days of our own
    mask = (df['Date'] <= row['Date']) & (df['Date'] >= row['Date'] - timedelta(days=30)) & (df.index<index)
    df.loc[index, 'sum'] = df.loc[mask,'Amount'].sum()

输出:

       Date  Amount     sum
0 2015-02-18     455     0.0
1 2015-02-18     455   455.0
2 2015-04-02     455     0.0
3 2015-04-02     925   455.0
4 2015-04-02    2780  1380.0
5 2015-04-09     895  4160.0

在您的预期输出中,您在汇总金额时并没有一致地采用或忽略同一天。我包括了它们,但您可以通过将掩码更改为来忽略它们:

# There is no need for the index condition either so we remove it
mask = (df['Date'] >= row['Date'] - timedelta(days=30))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-01-14
    • 2017-03-30
    • 2019-05-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-06
    相关资源
    最近更新 更多