循环日期范围子+将天数分配到各自的月份

时间:2018-05-14 21:35:10

标签: python pandas date datetime

真的很感激这方面的一些帮助

对于以下数据集:


StartDate             EndDate               Days
0              2018-03-20 00:36:00       2018-05-01 00:42:00       42.004167
1              2018-05-01 00:42:00       2018-06-04 17:15:38       34.690023
2              2018-04-07 15:06:00       2018-05-09 17:01:00       32.079861
3              2018-03-21 04:36:00       2018-05-14 04:00:00       53.975000
4              2018-03-15 15:30:00       2018-05-08 08:30:00       53.708333
5              2018-05-08 08:30:00       2018-06-09 10:40:09       32.090382
6              2018-03-21 09:00:00       2018-05-16 13:40:00       56.194444
7              2018-03-31 06:00:00       2018-05-26 16:30:00       56.437500
8              2018-03-14 18:18:00       2018-04-27 01:00:00       43.279167
9              2018-04-07 15:00:00       2018-06-01 09:25:50       54.767940
10           2018-03-22 07:30:00       2018-05-20 19:00:00       59.479167

我能够找到开始日期和结束日期之间的差异,并像这样创建新列“天”:

df['StartDate'] = pd.to_datetime(df['StartDate'])
df['EndDate'] = pd.to_datetime(df['EndDate'])
df['Days'] = df['EndDate'].sub(df['StartDate'], axis=0)
df['Days'] = df['Days'] / np.timedelta64(1, 'D')

但是我需要找到它:

对于每一行,每个月的天数以及他们所在的特定月份

我认为最好的方法是为所有可能的月份创建列,并将日期归因于各自的列。但我来自excel背景,并且可能有更聪明的方法。

原因是;根据开始日期和结束日期之间的工作天数正确支付客户,并在此基础上对其进行归因。完整的数据集非常大,因此脚本必须以有效的方式处理各种日期差异。

感谢

black.mamba

2 个答案:

答案 0 :(得分:2)

让我们尝试一下。

首先使用pd.date_range为每条记录创建一系列日期,包括StartDate和EndDate。接下来使用dt日期时间访问器来获取月份。使用value_counts计算每条记录的总月数。最后,将结果加入原始数据框。另外,import calendar通过rename使用calendar.month_names创建的字典来获取月份名称与号码。

import calendar
df.join(df.apply(lambda x: 
                 pd.Series(pd.date_range(x.StartDate,
                                         x.EndDate,
                                         freq='D')).dt.month,1)
          .apply(lambda x: 
                 x.value_counts(),1)
          .rename(columns=dict(enumerate(calendar.month_name))))

输出:

             StartDate             EndDate       Days  March  April   May  June
0  2018-03-20 00:36:00 2018-05-01 00:42:00  42.004167   12.0   30.0   1.0   NaN
1  2018-05-01 00:42:00 2018-06-04 17:15:38  34.690023    NaN    NaN  31.0   4.0
2  2018-04-07 15:06:00 2018-05-09 17:01:00  32.079861    NaN   24.0   9.0   NaN
3  2018-03-21 04:36:00 2018-05-14 04:00:00  53.975000   11.0   30.0  13.0   NaN
4  2018-03-15 15:30:00 2018-05-08 08:30:00  53.708333   17.0   30.0   7.0   NaN
5  2018-05-08 08:30:00 2018-06-09 10:40:09  32.090382    NaN    NaN  24.0   9.0
6  2018-03-21 09:00:00 2018-05-16 13:40:00  56.194444   11.0   30.0  16.0   NaN
7  2018-03-31 06:00:00 2018-05-26 16:30:00  56.437500    1.0   30.0  26.0   NaN
8  2018-03-14 18:18:00 2018-04-27 01:00:00  43.279167   18.0   26.0   NaN   NaN
9  2018-04-07 15:00:00 2018-06-01 09:25:50  54.767940    NaN   24.0  31.0   NaN
10 2018-03-22 07:30:00 2018-05-20 19:00:00  59.479167   10.0   30.0  20.0   NaN

答案 1 :(得分:1)

通过将dt.month更改为dt.strftime

,我能够将其过滤到显示月份和年份的要求
df.join(df.apply(lambda x: 
             pd.Series(pd.date_range(x.StartDate,
                                     x.EndDate,
                                     freq='D')).dt.strftime('%b-%y'),1)

      .apply(lambda x: 
             x.value_counts(),1)
      .rename(columns=dict(enumerate(calendar.month_abbr)))) 

然而,输出现在按字母顺序列出列,而不是按年份顺序列出Jan到Dec。

欢迎任何有关如何实现这一目标的想法

Scott Boston的回复

首先,您的上述声明,您不需要重命名部分,因为当您从日期系列转换为%m时,您已经在重命名。

现在,当您取出返回用于排序的“月号”的.dt.month时,此方法会出现问题。当您更改使用月份名称时,现在您正在进行词典排序。因此,让我们切换回月份数(用于排序)并执行一些lambda函数将列号从月号转换为名称。

df.join(df.apply(lambda x: 
             pd.Series(pd.date_range(x.StartDate,
                                     x.EndDate,
                                     freq='D')).dt.strftime('%m-%y'),1)
     .apply(lambda x: 
               x.value_counts(),1)
     .rename(columns=lambda x: 
                     pd.to_datetime(x, format='%m-%y').strftime('%b-%y')))

输出:

             StartDate             EndDate       Days  Mar-18  Apr-18  May-18  Jun-18
0  2018-03-20 00:36:00 2018-05-01 00:42:00  42.004167    12.0    30.0     1.0     NaN
1  2018-05-01 00:42:00 2018-06-04 17:15:38  34.690023     NaN     NaN    31.0     4.0
2  2018-04-07 15:06:00 2018-05-09 17:01:00  32.079861     NaN    24.0     9.0     NaN
3  2018-03-21 04:36:00 2018-05-14 04:00:00  53.975000    11.0    30.0    13.0     NaN
4  2018-03-15 15:30:00 2018-05-08 08:30:00  53.708333    17.0    30.0     7.0     NaN
5  2018-05-08 08:30:00 2018-06-09 10:40:09  32.090382     NaN     NaN    24.0     9.0
6  2018-03-21 09:00:00 2018-05-16 13:40:00  56.194444    11.0    30.0    16.0     NaN
7  2018-03-31 06:00:00 2018-05-26 16:30:00  56.437500     1.0    30.0    26.0     NaN
8  2018-03-14 18:18:00 2018-04-27 01:00:00  43.279167    18.0    26.0     NaN     NaN
9  2018-04-07 15:00:00 2018-06-01 09:25:50  54.767940     NaN    24.0    31.0     NaN
10 2018-03-22 07:30:00 2018-05-20 19:00:00  59.479167    10.0    30.0    20.0     NaN