按指定的时间段获取计数

时间:2018-12-01 15:04:45

标签: python python-3.x pandas

示例数据框:

    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)都受到某种“影响”。每个人最多可以有两个时间段(总是至少有一个时间段(即start1end1),但是可能有第二个时间段(即{{ 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有一个更好的方法。 我正在寻找更好的方法。

1 个答案:

答案 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