获取熊猫数据框中两个给定日期之间的月份的结束日期

时间:2019-05-15 12:24:45

标签: python-3.x pandas dataframe

我有以下数据框:

    user_id   end date start date    no
0         1 2018-03-01 2018-01-01    15
1         1 2018-04-01 2018-02-01    20
2         1 2018-05-01 2018-03-01    35
3         2 2018-07-01 2018-04-01    50
4         2 2018-07-01 2018-05-01    18

我想创建另一个数据框,以便对于给定的用户ID,我具有开始日期和结束日期以及给定开始日期和结束日期之间所有月份的最后日期e-g:

    user_id    date       no
          1 2018-01-01    15
          1 2018-02-28    15
          1 2018-03-01    15
          1 2018-02-01    20
          1 2018-03-31    20
          1 2018-04-01    20
          1 2018-03-01    35
          1 2018-04-30    35
          1 2018-05-01    35
          2 2018-04-01    50
          2 2018-05-31    50
          2 2018-06-30    50
          2 2018-07-01    50
          2 2018-05-01    18
          2 2018-06-30    18
          2 2018-07-01    1

1 个答案:

答案 0 :(得分:4)

使用:

#rename columns for using itertuples
df = df.rename(columns=lambda x: x.replace(' ', '_'))
#convert columns to datetimes if necessary
df[['start_date','end_date']] = df[['start_date','end_date']].apply(pd.to_datetime)
#repeat datetimes to Series
s = pd.concat([pd.Series(r.Index,pd.date_range(r.start_date, r.end_date, freq='MS')) 
                         for r in df.itertuples()])
#swap keys with values
s = pd.Series(s.index, index=s, name='date')
#add to original
df = df.join(s).reset_index(drop=True)
#check values if match
mask = df[['start_date','end_date']].ne(df['date'], axis=0).all(axis=1)
df = df.drop(['start_date','end_date'], axis=1)
#set end of month for added datetimes
df.loc[mask, 'date'] += pd.offsets.MonthEnd()
#change order of columns
df = df[['user_id','date','no']]

print (df)
    user_id       date  no
0         1 2018-01-01  15
1         1 2018-02-28  15
2         1 2018-03-01  15
3         1 2018-02-01  20
4         1 2018-03-31  20
5         1 2018-04-01  20
6         1 2018-03-01  35
7         1 2018-04-30  35
8         1 2018-05-01  35
9         2 2018-04-01  50
10        2 2018-05-31  50
11        2 2018-06-30  50
12        2 2018-07-01  50
13        2 2018-05-01  18
14        2 2018-06-30  18
15        2 2018-07-01  18

编辑:

对于匹配的开始和结束值,请在每月的第一天开始使用

print (df)
   user_id    end date  start date  no
0        1  2018-05-10  2018-03-10  15
1        1  2018-04-01  2018-02-01  20
2        1  2018-05-01  2018-03-01  35
3        2  2018-07-01  2018-04-01  50
4        2  2018-07-01  2018-05-01  18

#convert columns to datetimes if necessary
df[['start date','end date']] = df[['start date','end date']].apply(pd.to_datetime)
#create new column with start of months
df['start_date'] = df['start date'].dt.to_period('m').dt.to_timestamp()
df['end_date'] = df['end date'].dt.to_period('m').dt.to_timestamp()
#repeat datetimes to Series
s = pd.concat([pd.Series(r.Index,pd.date_range(r.start_date, r.end_date, freq='MS')) 
                         for r in df.itertuples()])
#swap keys with values
s = pd.Series(s.index, index=s, name='date')
#add to original
df = df.join(s).reset_index(drop=True)
#check values if match
m1 = df['start_date'].ne(df['date'])
m2 = df['end_date'].ne(df['date'])

#replace values by start and end of groups
df['date'] = df['date'].where(m1, df['start date'])
df['date'] = df['date'].where(m2, df['end date'])

df = df.drop(['start_date','end_date','start date','end date'], axis=1)
#set end of month for added datetimes
df.loc[m1 & m2, 'date'] += pd.offsets.MonthEnd()
#change order of columns
df = df[['user_id','date','no']]

print (df)
    user_id       date  no
0         1 2018-03-10  15
1         1 2018-04-30  15
2         1 2018-05-10  15
3         1 2018-02-01  20
4         1 2018-03-31  20
5         1 2018-04-01  20
6         1 2018-03-01  35
7         1 2018-04-30  35
8         1 2018-05-01  35
9         2 2018-04-01  50
10        2 2018-05-31  50
11        2 2018-06-30  50
12        2 2018-07-01  50
13        2 2018-05-01  18
14        2 2018-06-30  18
15        2 2018-07-01  18