【问题标题】:How to split the days between 2 dates in the months如何在月份中的 2 个日期之间拆分天数
【发布时间】:2020-04-11 20:30:50
【问题描述】:

我有一个熊猫数据框。它包含“start_date”列和“end_date”列。我想计算开始和结束之间的工作日,将它们分成几个月并将它们作为附加列添加到数据框中。

目前这是我编写的代码。 无论如何我可以让它更快吗?

data = pd.DataFrame([
    {'start_date': '2020-03-03', 'end_date' : '2020-06-18'},
    {'start_date': '2020-06-03', 'end_date' : '2020-09-18'},
])


def days_month(df):
    days_month = pd.DatetimeIndex(pd.bdate_range(df['start_date'], df['end_date'])).month.value_counts()
    for i in range(1, 13):
        try:
            days_month[i] 
        except:
            days_month[i] = 0

    return days_month

data[['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']] = data.apply(days_month, axis=1,  result_type="expand")

print(data)
    end_date  start_date  Jan  Feb  Mar  Apr  May  Jun  Jul  Aug  Sep  Oct  \
0  2020-06-18  2020-03-03    0    0   21   22   21   14    0    0    0    0   
1  2020-09-18  2020-06-03    0    0    0    0    0   20   23   21   14    0   

   Nov  Dec  
0    0    0  
1    0    0  

更新尝试实施 Ethan 的建议:


def countWeekDays(df):  

    fromDate=df['PO Creation Date']
    toDate=df['PO Expected Delivery Date']

    d = np.arange(fromDate, toDate, dtype=np.datetime64)

    weekdays = d[np.is_busday(d, busdaycal=calendar())] 

    workDays = {m: np.array([i for i in weekdays if i.item().month==m]).size for m in range(1,13)}

    return workDays

def calendar(): 
    #set work week mask and optional holidays array
    return np.busdaycalendar(weekmask='1111100', holidays=['2020-01-01','2020-01-20','2020-02-17','2020-05-25','2020-07-03','2020-09-07','2020-10-12','2020-11-11','2020-11-26','2020-12-25'])


data[['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']] = data.apply(countWeekDays, axis=1,  result_type="expand")

但是,它给了我一个内存错误。不知道为什么...

【问题讨论】:

  • if i not in days_month.index:days_month[i] = 0 替换你的tryexcept 块是否可以加快速度?
  • 非常感谢!它加快了一点,但仍然很慢......

标签: python pandas


【解决方案1】:

您可以使用 numpy 日期时间函数和一些包装:

import numpy as np

def countWeekDays(fromDate='2020-03-03', toDate='2020-06-03'):  
    d = np.arange(fromDate, toDate, dtype=np.datetime64)

    weekdays = d[np.is_busday(d, busdaycal=calendar())] 

    workDays = [(m, np.array([i for i in weekdays if i.item().month==m]).size) for m in range(1,13)]

    return workDays

def calendar(): 
    #set work week mask and optional holidays array
    return np.busdaycalendar(weekmask='1111100', holidays=['2020-01-01','2020-01-20','2020-02-17','2020-05-25','2020-07-03','2020-09-07','2020-10-12','2020-11-11','2020-11-26','2020-12-25'])

结果:

>>> countWeekDays()
[(1, 0), (2, 0), (3, 21), (4, 22), (5, 20), (6, 2), (7, 0), (8, 0), (9, 0), (10, 0), (11, 0), (12, 0)]

这是对您的代码的修改,以构建一个数据框,该数据框与我的函数一起使用以获取工作日。我认为您遇到的错误是由于构建和修改 Dataframe 的方式造成的。我的经验是,修改数据框有点麻烦,最好将您的数据放在一起,然后从您的完整数据集中创建数据框:

def applyDays():
    data = [{'start_date': '2020-03-03', 'end_date' : '2020-06-18'},
    {'start_date': '2020-06-03', 'end_date' : '2020-09-18'}]
    return countWeekDays(data)


def countWeekDays(lst): #, result_type):  
    months = ['start_date','end_date',  'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
    data = []
    for row in lst:  
        fromDate = row['start_date'] # df['PO Creation Date']
        toDate = row['end_date'] #df['PO Expected Delivery Date']    
        d = np.arange(fromDate, toDate, dtype=np.datetime64)    
        weekdays = d[np.is_busday(d, busdaycal=calendar())] 

        data.append([fromDate, toDate] + [np.array([i for i in weekdays if i.item().month==m]).size for m in range(1,13)])
    return pd.DataFrame(data, columns=months)

数据框结果:

applyDays()
Out[6]: 
   start_date    end_date  Jan  Feb  Mar  Apr  May  Jun  Jul  Aug  Sep  Oct  \
0  2020-03-03  2020-06-18    0    0   21   22   20   13    0    0    0    0   
1  2020-06-03  2020-09-18    0    0    0    0    0   20   22   21   12    0   

   Nov  Dec  
0    0    0  
1    0    0  

【讨论】:

  • 不客气。如果这是一个可接受的解决方案,您将其标记为已接受的答案将不胜感激?
  • 我在尝试实现它时遇到了内存错误。见上文(我更新了最初的问题)。
  • @Ant0nell0 你能发布正在抛出的错误吗?
  • @Ant0nell0 我已经添加到我的原始答案中,以创建一个数据框作为结果而不是一个 numpy 数组。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多