[英]How to extract useful features from time-series data (e.g., users' daily activities in a forum)
[英]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.
似乎您将Period
和Value
(同一周的总和)分组在同一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.