繁体   English   中英

如何从 pandas 中的每日数据创建每周时间序列

[英]How to create a weekly time-series from a daily data in pandas

我在 python 中有以下每日级别的数据表(不是数据点之间的常规间隙),我想将其转换为每周级别(从给定日期开始,每 7 天滚动一次数据)。 数据表如下所示:

ID Date Value
1  8/9/2018 2857
1  8/15/2018 2194
1  8/23/2018 226
1  8/30/2018 685
-     ----    --
2  8/6/2018 1390
2  8/17/2018 1162
2  8/27/2018 6320
2  8/30/2018 1150

所需的 Output 如下:

Data rolling starts from 1st Jul'2018

ID       Period             Value
1  8/1/2018-8/7/2018          0
1  8/8/2018-8/14/2018        2857
1  8/15/2018-8/21/2018       2194
-   ----------------          --
2  8/1/2018-8/7/2018         1390
2  8/8/2018-8/14/2018         0
2  8/15/2018-8/21/2018       1162
-   ----------------          -
 till 31st Jul'2020.

似乎您将PeriodValue (同一周的总和)分组在同一ID下。 因此,如果不按ID分组,该解决方案将无法工作。

对于每个月,从您的数据中可以看出,分割周不是从任何周日或周一开始,而是每周从每月的 1 日、8 日、15 日、22 日、29 日开始。 因此,我们必须为这样的周范围特别定制。

我们可以这样做:

df['Date1'] = pd.to_datetime(df['Date'])
df['week_start'] = df['Date1'] - pd.to_timedelta((df['Date1'].dt.day - 1) % 7, unit='d')
df['week_finish'] = df['week_start'] + pd.Timedelta('6D')
df['Period'] = df['week_start'].dt.strftime('%m/%d/%Y').astype(str) + '-' + df['week_finish'].dt.strftime('%m/%d/%Y').astype(str)
df.groupby(['ID', 'week_start', 'Period'])['Value'].sum().reset_index([0,2]).reset_index(drop=True)

演示

测试数据构建由于您的样本数据无法测试汇总同一周的 2 个条目的条件,因此我添加了ID等于3的新数据,如下所示:

data = {'ID': [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],
 'Date': ['8/9/2018',
  '8/15/2018',
  '8/23/2018',
  '8/30/2018',
  '8/6/2018',
  '8/17/2018',
  '8/27/2018',
  '8/30/2018',
  '8/6/2018',
  '8/7/2018',
  '8/27/2018',
  '8/28/2018'],
 'Value': [2857,
  2194,
  226,
  685,
  1390,
  1162,
  6320,
  1150,
  1000,
  2000,
  6320,
  1150]}

df = pd.DataFrame(data)

print(df)

    ID       Date  Value
0    1   8/9/2018   2857
1    1  8/15/2018   2194
2    1  8/23/2018    226
3    1  8/30/2018    685
4    2   8/6/2018   1390
5    2  8/17/2018   1162
6    2  8/27/2018   6320
7    2  8/30/2018   1150
8    3   8/6/2018   1000
9    3   8/7/2018   2000
10   3  8/27/2018   6320
11   3  8/28/2018   1150

运行新代码

df['Date1'] = pd.to_datetime(df['Date'])
df['week_start'] = df['Date1'] - pd.to_timedelta((df['Date1'].dt.day - 1) % 7, unit='d')
df['week_finish'] = df['week_start'] + pd.Timedelta('6D')
df['Period'] = df['week_start'].dt.strftime('%m/%d/%Y').astype(str) + '-' + df['week_finish'].dt.strftime('%m/%d/%Y').astype(str)
df.groupby(['ID', 'week_start', 'Period'])['Value'].sum().reset_index([0,2]).reset_index(drop=True)

Output

   ID                 Period  Value
0   1  08/08/2018-08/14/2018   2857
1   1  08/15/2018-08/21/2018   2194
2   1  08/22/2018-08/28/2018    226
3   1  08/29/2018-09/04/2018    685
4   2  08/01/2018-08/07/2018   1390
5   2  08/15/2018-08/21/2018   1162
6   2  08/22/2018-08/28/2018   6320
7   2  08/29/2018-09/04/2018   1150
8   3  08/01/2018-08/07/2018   3000
9   3  08/22/2018-08/28/2018   7470

请注意,output 与您所需的 output 略有不同,其中每周,即使没有值,仍应显示 0 值。 为了支持这一点,代码将更加复杂。 您现在已经可以看到按 ID 和星期按正确日历顺序分组的值(日期的排序顺序由 YYYY-MM-DD 格式的临时字段week_start保证,以便确保按时间顺序的排序顺序。以下Period order 将导致不同年份的同一月份排序在一起,从而破坏了时间顺序。

编辑

如果星期是相对于2018-08-01而不是每个月的第一天,我们可以修改行设置df['week_start'] ,如下所示:

df['week_start'] = df['Date1'] - pd.to_timedelta((df['Date1'] - pd.Timestamp('2018-08-01')).dt.days % 7, unit='d')

测试运行

ID等于3现在设置为 2018 年 9 月。

data = {'ID': [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],
 'Date': ['8/9/2018',
  '8/15/2018',
  '8/23/2018',
  '8/30/2018',
  '8/6/2018',
  '8/17/2018',
  '8/27/2018',
  '8/30/2018',
  '9/6/2018',
  '9/7/2018',
  '9/27/2018',
  '9/28/2018'],
 'Value': [2857,
  2194,
  226,
  685,
  1390,
  1162,
  6320,
  1150,
  1000,
  2000,
  6320,
  1150]}

df = pd.DataFrame(data)

print(df)


    ID       Date  Value
0    1   8/9/2018   2857
1    1  8/15/2018   2194
2    1  8/23/2018    226
3    1  8/30/2018    685
4    2   8/6/2018   1390
5    2  8/17/2018   1162
6    2  8/27/2018   6320
7    2  8/30/2018   1150
8    3   9/6/2018   1000
9    3   9/7/2018   2000
10   3  9/27/2018   6320
11   3  9/28/2018   1150

运行新代码:

df['Date1'] = pd.to_datetime(df['Date'])
df['week_start'] = df['Date1'] - pd.to_timedelta((df['Date1'] - pd.Timestamp('2018-08-01')).dt.days % 7, unit='d')
df['week_finish'] = df['week_start'] + pd.Timedelta('6D')
df['Period'] = df['week_start'].dt.strftime('%m/%d/%Y').astype(str) + '-' + df['week_finish'].dt.strftime('%m/%d/%Y').astype(str)
df.groupby(['ID', 'week_start', 'Period'])['Value'].sum().reset_index([0,2]).reset_index(drop=True)

Output

   ID                 Period  Value
0   1  08/08/2018-08/14/2018   2857
1   1  08/15/2018-08/21/2018   2194
2   1  08/22/2018-08/28/2018    226
3   1  08/29/2018-09/04/2018    685
4   2  08/01/2018-08/07/2018   1390
5   2  08/15/2018-08/21/2018   1162
6   2  08/22/2018-08/28/2018   6320
7   2  08/29/2018-09/04/2018   1150
8   3  09/05/2018-09/11/2018   3000
9   3  09/26/2018-10/02/2018   7470

尝试这个:

def get_week(x,start_date):
    return ((x.date()-start_date.date()).days)//7

df['formatted_date'] = pd.to_datetime(df['date'])
start_date = pd.to_datetime('Add your start date')

df["week"] = df["formatted_date"].apply(lambda x:get_week(x,start_date))
df["year"] = df.formatted_date.apply(lambda x: x.year)
    
df.groupby(['week','year']).sum() 

使用 groupby() 方法。 确保值是数字(int,float 不是 object)

        date  value
0 2018-08-09   2857
1 2018-08-15   2194
2 2018-08-23    226
3 2018-08-30    685
4 2018-08-06   1390
5 2018-08-17   1162
6 2018-08-27   6320
7 2018-08-30   1150
>>> df['week']=df['date'].transform(lambda x: x.week)
>>> df.groupby('week').sum()
      value
week       
32     4247
33     3356
34      226
35     8155

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM