簡體   English   中英

Python:將不同列的值分組為時間桶

[英]Python: Grouping values of different columns into time buckets

假設你有這個DataFrame:

Name    Item    Date    value1  value2
Marc    bike    21-Dec-17   7   1000
Marc    bike    05-Jan-18   9   2000
Marc    bike    27-Jul-18   4   500
John    house   14-Dec-17   4   500
John    house   02-Feb-18   6   500
John    house   07-Feb-18   8   1000
John    house   16-Feb-18   2   1000
John    house   05-Dec-21   7   1000
John    house   27-Aug-25   8   500
John    car     17-Apr-18   4   500

我想將value1和value2分成每個名稱 - 項目組合的月度桶(每個第3個星期三,接下來的48個月)。

所以每個組合有49個時間段,每個月的值1和值2之和:Marc / bike,John / house,John / car,...

John / house的解決方案如下:

Name    Item    TimeBucket  value1  value2
John    house   20-Dec-17   4   500
John    house   17-Jan-18   0   0
John    house   21-Feb-18   16  2500
John    house   21-Mar-18   0   0
John    house   18-Apr-18   0   0
John    house   …           0   0
John    house   17-Nov-21   0   0
John    house   15-Dec-21   7   1000
John    house   rest        8   500

我不能用大熊貓得到一個結果。 我能想到的唯一解決方案是在數據幀中逐行迭代,但我真的想避免這樣做。 有一種優雅的方式嗎?

問題實際上歸結為三個步驟:

1.如何找到每個月的第三個星期三?

這可能不是最優雅的解決方案,但您可以通過屏蔽包含時間范圍內每天的大熊貓DatetimeIndex過濾掉每個月的第三個星期三

# generate a DatetimeIndex for all days in the relevant time frame
from datetime import datetime
start = datetime(2017, 12, 1)
end = datetime(2022, 1, 31)
days = pd.date_range(start, end, freq='D')

# filter out only the third wednesday of each month
import itertools
third_wednesdays = []
for year, month in itertools.product(range(2017, 2023), range(1,13)):
    mask = (days.weekday == 2) & \
        (days.year == year) & \
        (days.month == month)
    if len(days[mask]) > 0:
        third_wednesdays.append(days[mask][2])
bucket_lower_bounds = pd.DatetimeIndex(third_wednesdays)

將結果列表轉換為DatetimeIndex以便在步驟2中將其用作bin的下限。

2.如何存儲DataFrame的值?

然后,一旦您將桶列表作為DatetimeIndex ,您只需使用panda的cut函數將每個日期分配給存儲桶 在將日期列傳遞給cut之前將其轉換為整數,然后將結果轉換回日期:

time_buckets = pd.to_datetime(
    pd.cut(
        x = pd.to_numeric(df['Date']), 
        bins = pd.to_numeric(bucket_lower_bounds), 
        labels = bucket_lower_bounds[:-1]
    )
)

系列time_buckets將原始數據框的每個索引值分配給存儲桶的下限。 我們現在可以簡單地將它添加到原始數據框中:

df['TimeBucket'] = time_buckets

結果應該看起來像這樣(不是說NaT代表“休息”桶):

    Name    Item    Date    value1  value2  TimeBucket
0   Marc    bike    2017-12-21  7   1000    2017-12-20
1   Marc    bike    2018-01-05  9   2000    2017-12-20
2   Marc    bike    2018-07-27  4   500     2018-07-18
3   John    house   2017-12-14  4   500     NaT
4   John    house   2018-02-02  6   500     2018-01-17
5   John    house   2018-02-07  8   1000    2018-01-17
6   John    house   2018-02-16  2   1000    2018-01-17
7   John    house   2021-12-05  7   1000    2021-11-17
8   John    house   2025-08-27  8   500     NaT
9   John    car     2018-04-17  4   500     2018-03-21

3.如何聚合分箱的DataFrame?

現在就像使用groupby獲取 name,item和bucket的每個組合的總和一樣簡單:

df.groupby(['Name','Item','TimeBucket']).sum()

結果:

Name    Item    TimeBucket  value1  value2
John    car     2018-03-21  4       500
        house   2018-01-17  16      2500
                2021-11-17  7       1000
Marc    bike    2017-12-20  16      3000
                2018-07-18  4       500

不幸的是, NaT值被排除在groupby之外 如果您還需要對這些進行求和,也許最簡單的方法是確保您的存儲桶列表在輸入范圍內的每個日期都至少有一個存儲桶。

編輯:步驟2需要pandas版本> = 0.18.1。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM