python如何找到两个日期列之间每个月的天数

时间:2019-12-09 23:45:43

标签: python pandas dataframe datetime

我有两个日期列“开始日期”和“结束日期”,我想查找年份和这两个日期之间每个月的天数。我可以找到一年,但不知道如何找到每个月的天数。不确定获取此o / p是否可行。

from pandas import DataFrame
import re

df = {'Id': ['1','2','3','4','5'],
      'Item': ['A','B','C','D','E'],
        'StartDate': ['2019-12-10', '2019-12-01', '2019-01-01', '2019-05-10', '2019-03-10'],
        'EndDate': ['2019-12-30' ,'2019-12-31','2019-03-30','2019-11-30','2019-06-10']
        }
df = DataFrame(df,columns= ['Id', 'Item','StartDate','EndDate'])

预期的O / P: enter image description here

2 个答案:

答案 0 :(得分:1)

我想出了使用string.emptypd.date_range的解决方案。您需要将resampleStartDate列都转换为datetime dtype

EndDate

最后连接回原始数据框

df['StartDate'] = pd.to_datetime(df['StartDate'])
df['EndDate'] = pd.to_datetime(df['EndDate'])

def days_of_month(x):
    s = pd.date_range(*x, freq='D').to_series()
    return s.resample('M').count().rename(lambda x: x.month)

df1 = df[['StartDate', 'EndDate']].apply(days_of_month, axis=1).fillna(0)

Out[1036]:
     1     2     3     4     5     6     7     8     9     10    11    12
0   0.0   0.0   0.0   0.0   0.0   0.0   0.0   0.0   0.0   0.0   0.0  21.0
1   0.0   0.0   0.0   0.0   0.0   0.0   0.0   0.0   0.0   0.0   0.0  31.0
2  31.0  28.0  30.0   0.0   0.0   0.0   0.0   0.0   0.0   0.0   0.0   0.0
3   0.0   0.0   0.0   0.0  22.0  30.0  31.0  31.0  30.0  31.0  30.0   0.0
4   0.0   0.0  22.0  30.0  31.0  10.0   0.0   0.0   0.0   0.0   0.0   0.0

答案 1 :(得分:0)

解决方案

您可以结合使用 vectorization与pandas和numpy 的组合,以实现以下目的。为了方便使用,下面提供了自定义功能。由于它使用矢量化,因此应该很快。

注意:此处使用的假设基于示例数据:

  • 日期范围仅为一年
  • 开始日期和结束日期都在同一年。
  

如果您有不同年份的数据,则需要将此数据应用于那里的每年数据。另外,如果开始日期和结束日期位于不同的年份,则必须对此采用相应的方法。由于此处提出的问题并未说明该要求,因此我将本实现作为任何对将其应用到跨度跨度数据集感兴趣的人的指南。


  

如果您想在jupyter笔记本环境中试用此解决方案,可以在github上here进行访问。它还具有Google Colaboratory链接。因此,您也可以直接在Google Colab Notebook中打开它。

# Updated DataFrame
df = process_dataframe(df) # custom function
display(df.head())

enter image description here

虚拟数据和自定义功能

在Google Colab环境中通过pandas==0.25.3numpy==0.17.4进行了测试。

import numpy as np
import pandas as pd
#from pandas.tseries.offsets import MonthEnd
from IPython.display import display

# Dummy Data
df = {'Id': ['1','2','3','4','5'],
      'Item': ['A','B','C','D','E'],
        'StartDate': ['2019-12-10', '2019-12-01', '2019-01-01', '2019-05-10', '2019-03-10'],
        'EndDate': ['2019-12-30' ,'2019-12-31','2019-03-30','2019-11-30','2019-06-10']
        }
df = pd.DataFrame(df,columns= ['Id', 'Item','StartDate','EndDate'])

# Function for Processing the DataFrame
def process_dataframe(df):
    """Returns the updated dataframe. """
    df.StartDate = pd.to_datetime(df.StartDate)
    df.EndDate = pd.to_datetime(df.EndDate)

    month_ends = pd.date_range(start='2019-01', freq='M', periods=12)    
    month_headers = month_ends.month_name().str.upper().str[:3].tolist()
    month_days = month_ends.day.to_numpy()
    month_nums = (np.arange(12) + 1)
    # Evaluate expressions to avoid multiple times evaluation
    start_date_month_num = df.StartDate.dt.month.to_numpy().reshape(-1,1)
    end_date_month_num = df.EndDate.dt.month.to_numpy().reshape(-1,1)

    #start_month_days = pd.to_datetime(df.StartDate, format="%Y%m") + MonthEnd(1) - df.StartDate
    # start_month_days.dt.days.to_numpy()
    # Number of days not in the end_month
    end_month_days_excluded = month_days[df.EndDate.dt.month.to_numpy() - 1] - df.EndDate.dt.day.to_numpy()

    # Determine the months that fall within the start and end dates (inclusive 
    # of start and end months) and then calculate the number of days in each 
    # month.

    # add all days for relevant months
    result = ((start_date_month_num <= month_nums) & \
            (end_date_month_num >= month_nums)).astype(int) \
            * month_days.reshape(1,-1) 
    # subtract number of days not in starting month
    result = result + \
            (-1) * (start_date_month_num == month_nums).astype(int) \
            * (df.StartDate.dt.day.to_numpy() - 1).reshape(-1,1) 
    # subtract number of days not in ending month            
    result = result + \
            (-1) * (end_date_month_num == month_nums).astype(int) \
            * end_month_days_excluded.reshape(-1,1) 

    return pd.merge(df, pd.DataFrame(result, columns = month_headers), left_index=True, right_index=True)

原始DataFrame

# Original DataFrame
display(df.head())

输出
enter image description here