2

I have a dataset like this:

    import pandas as pd    
    pd.DataFrame({'col1': [1, 2], 'start date': ['1/3/2019', '1/10/2019'],
                                  'end date':['1/5/2019','1/12/2019']} )

I want to get a row for each of the values between Start Date and End Date.

    pd.DataFrame({'col1': [1,1,1,2,2,2],
                  'date': ['1/3/2019','1/4/2019','1/5/2019',
                           '1/10/2019', '1/11/2019', '1/12/2019'],

                  'start date': ['1/3/2019', '1/3/2019', '1/3/2019',
                           '1/10/2019', '1/10/2019', '1/10/2019'],

                  'end date':['1/5/2019','1/5/2019','1/5/2019',
                           '1/12/2019','1/12/2019','1/12/2019']} )

Edit: Range overlap is allowed.

I am trying to use melt but I can't get what I want.

Bulat
  • 720
  • 7
  • 15
Luan Vieira
  • 117
  • 1
  • 10

3 Answers3

2

I would use apply with with a custom function return a series from pd.date_range

def create_range(x):
    s = pd.Series(pd.date_range(start=x['start date'], end=x['end date'])).dt.strftime('%m/%d/%Y')
    return s

Using the custom function above to apply, stack, reset_index and join with df

df[['start date', 'end date']].apply(create_range, axis=1).stack().reset_index(level=-1, drop=True).to_frame('date').join(df)


Out[1742]:
         date  col1   end date start date
0  01/03/2019     1   1/5/2019   1/3/2019
0  01/04/2019     1   1/5/2019   1/3/2019
0  01/05/2019     1   1/5/2019   1/3/2019
1  01/10/2019     2  1/12/2019  1/10/2019
1  01/11/2019     2  1/12/2019  1/10/2019
1  01/12/2019     2  1/12/2019  1/10/2019
Andy L.
  • 24,909
  • 4
  • 17
  • 29
1

Here is something to consider which uses pd.date_range and a groupby.apply:

df = pd.DataFrame({'col1': [1, 2], 'start date': ['1/3/2019', '1/10/2019'], 'end date':['1/5/2019','1/12/2019']} )
df.set_index(['col1', 'start date', 'end date'], inplace=True)
df_result = df.groupby(['col1', 'start date', 'end date']).apply(lambda df_: pd.date_range(*df_.index[0][1:], freq='D').to_frame(index=True, name='date'))
df_result.reset_index(inplace=True)
df_result.reindex(['col1', 'date', 'start date', 'end date'], axis=1)

# produces the following:

   col1       date start date   end date
0     1 2019-01-03   1/3/2019   1/5/2019
1     1 2019-01-04   1/3/2019   1/5/2019
2     1 2019-01-05   1/3/2019   1/5/2019
3     2 2019-01-10  1/10/2019  1/12/2019
4     2 2019-01-11  1/10/2019  1/12/2019
5     2 2019-01-12  1/10/2019  1/12/2019
jeschwar
  • 1,286
  • 7
  • 10
1

I would use range_index to build the list of dates between start date and end date, build a partial dataframe from each row and then concat them all:

pd.concat(
    [pd.DataFrame(row.to_dict(), index = pd.date_range(
        start = pd.to_datetime(df.loc[i, 'start date']),
        end = pd.to_datetime(df.loc[i, 'end date']),
        freq = 'D')).rename_axis('date').reset_index()
     for i, row in df.iterrows()], ignore_index=True)
Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252