我有一个pandas数据帧df
,其中每行包含start_date
(也是索引)和duration
(以天为单位)进行订阅。
import pandas as pd
df = pd.DataFrame({'start_date':['2018-01-01','2018-01-05']})
df['start_date'] = df['start_date'].astype('datetime64[ns]')
df['duration'] = pd.to_timedelta([10,8], unit='D')
df['end_date'] = df['start_date'] + df['duration']
我想绘制一段时间内的订阅者数量。
我的想法是创建另一个数据框架subscribers
:
active_subscribers = pd.DataFrame({
'Date': pd.date_range(start=df.index.min(),end=df['end_date'].max()),
'Number': 0,
})
active_subscribers.set_index('Date', inplace=True)
qazxs指出至少有一个用户处于活动状态的整个时间段。然后我想为每个订阅创建日期范围并将它们添加到Date
列,如下所示:
Number
但是这会返回以下错误:
for index, row in df.iterrows():
for this_date in pd.date_range(start=index, end=row['end_date']):
active_subscribers[this_date]['Number'] += 1
我希望得到的是一个KeyError: Timestamp('2018-01-01 00:00:00', freq='D')
column,看起来像这样:
Number
列qazxswpo表示那天活跃订阅者的数量。
如果您有任何建议,请告诉我
您可以使用Date Number
2018-01-01 1
2018-01-02 1
2018-01-03 1
2018-01-04 1
2018-01-05 2
2018-01-06 2
2018-01-07 2
2018-01-08 2
2018-01-09 2
2018-01-10 2
2018-01-11 1
2018-01-12 1
2018-01-13 1
的列表理解为新的Number
,然后通过itertuples
和DataFrame
获取新列:
groupby
它更快,因为size
解决方案:
df = pd.DataFrame(index=pd.to_datetime(['2018-01-01','2018-01-05']))
df['duration'] = pd.to_timedelta([10,8], unit='D')
df['end_date'] = df.index + df['duration']
print (df)
duration end_date
2018-01-01 10 days 2018-01-11
2018-01-05 8 days 2018-01-13
df = df.rename_axis('start_date').reset_index()
com = [pd.Series(r.Index,pd.date_range(r.start_date, r.end_date)) for r in df.itertuples()]
df1 = pd.concat(com).reset_index()
df1.columns=['Date','Number']
df1 = df1.groupby('Date')['Number'].size().reset_index()
print (df1)
Date Number
0 2018-01-01 1
1 2018-01-02 1
2 2018-01-03 1
3 2018-01-04 1
4 2018-01-05 2
5 2018-01-06 2
6 2018-01-07 2
7 2018-01-08 2
8 2018-01-09 2
9 2018-01-10 2
10 2018-01-11 2
11 2018-01-12 1
12 2018-01-13 1
样品:
iterrows
功能:
In [288]: %timeit (iterrows_sol(df))
10 loops, best of 3: 51.1 ms per loop
In [289]: %timeit (itertupl_sol(df))
100 loops, best of 3: 10.2 ms per loop