繁体   English   中英

Python:将开始日期和结束日期拆分为开始日期和结束日期之间的所有日期

[英]Python: Split Start and End Date into All Days Between Start and End Date

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

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

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

这是我目前的 function:

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

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

在我看来,仅Date列是不够的。 您的 output DataFrame 还应至少包含Employee ID ,以了解哪个人在给定日期休假。

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

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()

这个 function:

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

然后调用它:

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

这是必要的循环,所以我更喜欢DataFrame.itertuples更像DataFrame.iterrows以提高列表理解的性能

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)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM