【问题标题】:Python: Split Start and End Date into All Days Between Start and End DatePython:将开始日期和结束日期拆分为开始日期和结束日期之间的所有日期
【发布时间】:2020-10-05 17:04:34
【问题描述】:

我有名为“计划休假”的数据,其中包括“开始日期”、“结束日期”、“用户 ID”和“休假类型”。

我希望能够根据“用户 ID”创建一个新的数据框,显示开始日期和结束日期之间的所有天数。

到目前为止,我只能创建一个 date_list,它提供了开始日期和结束日期之间的日期范围,但我找不到为每个“用户 ID”和“休假类型”包含此日期的方法。

这是我当前的功能:

def datesplit(data):
    x = pd.DataFrame(columns=['Date'])
    for i in plannedleave.iterrows():
        start = data['Start Date'][i]
        end = data['End Date'][i]
        date_list = [start + dt.timedelta(days=x) for x in range((end-start).days)]
    x.append(date_list)
    return x

>>> datesplit(plannedleave)
>>> Value Error: Can only Tuple-index with a MultiIndex

数据如下所示:

>>> plannedleave.dtypes
>>>
    Employee ID                      int64
    First Name                      object
    Last Name                       object
    Leave Type                      object
    Start Date              datetime64[ns]
    End Date                datetime64[ns]
dtype: object

如果您能在这里找到解决方案,我将永远感激不尽! :-)

【问题讨论】:

标签: python pandas numpy datetime data-science


【解决方案1】:

在我看来,仅 Date 列是不够的。您的输出数据框 还应至少包含 员工 ID,以了解哪个人在上 在给定日期离开。

要完成您的任务,请定义以下函数:

def datesplit(data):
    parts = []
    for idx, row in data.iterrows():
        parts.append(pd.DataFrame(row['Employee ID'], columns=['Employee ID'],
            index=pd.date_range(start=row['Start Date'], end=row['End Date'],
                name='Date')))
    return pd.concat(parts).reset_index()

这个函数:

  • 对于每个源行收集“部分数据帧”,现在:
    • 唯一的列是员工 ID
    • 索引是开始日期和结束日期之间的日期范围,
    • 给定的Employee ID(一个single值)实际上是 为所有行广播(当前员工每天休假)。
  • 在循环之后,将它们连接起来并转换索引(日期) 进入“常规”列。

然后调用它:

result = datesplit(plannedleave)

为了测试我的代码,我使用了源 DataFrame (plannedleave):

   Employee ID First Name Last Name Leave Type Start Date   End Date
0         1001       John     Brown       Xxxx 2020-05-10 2020-05-15
1         1002      Betty     Smith       Yyyy 2020-05-18 2020-05-22

上述数据的结果是:

         Date  Employee ID
0  2020-05-10         1001
1  2020-05-11         1001
2  2020-05-12         1001
3  2020-05-13         1001
4  2020-05-14         1001
5  2020-05-15         1001
6  2020-05-18         1002
7  2020-05-19         1002
8  2020-05-20         1002
9  2020-05-21         1002
10 2020-05-22         1002

【讨论】:

  • 您认为将您的示例数据用于我的解决方案是否合理?
  • 没问题,用吧。
【解决方案2】:

这里是必要的循环,所以我更喜欢DataFrame.itertuples 更像DataFrame.iterrows 用于列表理解中的performance

def datesplit(df):
    df1 = df.rename(columns={'Start Date':'sdate','End Date':'edate', 'Employee ID':'ID'})
    return  (pd.concat([pd.Series(r.ID,pd.date_range(r.sdate, r.edate)) 
                        for r in df1.itertuples()])
               .rename_axis('Date')
               .reset_index(name='Employee ID'))

df = datesplit(plannedleave)
print (df)
         Date  Employee ID
0  2020-05-10         1001
1  2020-05-11         1001
2  2020-05-12         1001
3  2020-05-13         1001
4  2020-05-14         1001
5  2020-05-15         1001
6  2020-05-18         1002
7  2020-05-19         1002
8  2020-05-20         1002
9  2020-05-21         1002
10 2020-05-22         1002

200 行的性能:

plannedleave = pd.concat([plannedleave] * 100, ignore_index=True)


def datesplit(df):
    df1 = df.rename(columns={'Start Date':'sdate','End Date':'edate', 'Employee ID':'ID'})
    return  (pd.concat([pd.Series(r.ID,pd.date_range(r.sdate, r.edate)) 
                        for r in df1.itertuples()])
               .rename_axis('Date')
               .reset_index(name='Employee ID'))


def datesplitvb(data):
    parts = []
    for idx, row in data.iterrows():
        parts.append(pd.DataFrame(row['Employee ID'], columns=['Employee ID'],
            index=pd.date_range(start=row['Start Date'], end=row['End Date'],
                name='Date')))
    return pd.concat(parts).reset_index()



In [152]: %timeit datesplit(plannedleave.copy())
98.2 ms ± 4.96 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [153]: %timeit datesplitvb(plannedleave.copy())
193 ms ± 30.5 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

【讨论】:

  • 完美!非常感谢耶斯瑞尔
  • @DylanMcCullough - 如果我的回答有帮助,请不要忘记accept。谢谢。这对任何数据都很重要,因为在 200 行中,此解决方案的速度提高了 1.9 倍。如果有更多的行,则差异更大。
  • 这仅给出日期 + 一列(员工 ID)。如何将所有列添加到结果数据框中?
  • @Vega - 像 here 一样使用 .Index
猜你喜欢
  • 2022-01-23
  • 1970-01-01
  • 2012-08-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多