示例数据框:
id start1 end1 start2 end2
0 Bob 2018-11-29 2018-11-30 2018-12-01 2018-12-31
1 James 2018-10-19 2018-10-31 NaT NaT
2 Jane 2018-04-05 2018-07-12 2018-11-29 2018-11-30
鉴于上述示例数据框,我想按月份和年份显示频率计数。假设在这些期间,每个人(id
)都受到某种“影响”。每个人最多可以有两个时间段(总是至少有一个时间段(即start1
和end1
),但是可能有第二个时间段(即{{ 1}}和start2
))。我想显示在整个时间范围内每个人都受到月和年影响的人数。
例如,上面的数据将导致类似这样的结果(不确定年月是同一列还是多列,无论如何):
end2
我最终的目标是查看不同时间段(例如,年份(在此示例数据中均为2018年),月/年,周等)中的这些时间。
我不确定如何将它们分解成一个系列,因此我可以在单个列上进行直方图处理。我知道一旦将它们放在一列中(例如 year-month count
0 2018-04 1
1 2018-05 1
2 2018-06 1
3 2018-07 1
4 2018-08 0
5 2018-09 0
6 2018-10 1
7 2018-11 2
8 2018-12 1
),我可以执行以下操作:
date
但是那只能是按月,并且假设我已经在单个列中输入了日期。
我可以只使用df.groupby(df["date"].dt.month).count().plot(kind="bar")
并保持循环添加天数(如果在每个时间段之间直到到达结束日期),但是每次我这样做时,我都知道pandas / numpy有一个更好的方法。 我正在寻找更好的方法。
答案 0 :(得分:1)
您可以先使用pd.wide_to_long重塑数据框
from pandas.tseries.offsets import MonthEnd
newdf=pd.wide_to_long(df,['start','end'],i='id',j='drop')
newdf=newdf.apply(pd.to_datetime)
newdf=newdf.dropna()
newdf.start=newdf.start.values.astype('datetime64[M]')
newdf.end=newdf.end+MonthEnd(0)
newdf
start end
id drop
Bob 1 2018-11-01 2018-11-30
James 1 2018-10-01 2018-10-31
Jane 1 2018-04-01 2018-07-31
Bob 2 2018-12-01 2018-12-31
Jane 2 2018-11-01 2018-11-30
然后我们使用date_range
l=[pd.date_range(x,y,freq='M',closed ='right').strftime('%Y-%m') for x ,y in zip(newdf.start,newdf.end)]
pd.Series(np.concatenate(l)).value_counts()
2018-11 2
2018-05 1
2018-12 1
2018-04 1
2018-06 1
2018-10 1
2018-07 1
dtype: int64