Python 熊猫以增量方式减去日期,直到数据帧上满足条件为止

Python 熊猫以增量方式减去日期,直到数据帧上满足条件为止,python,pandas,loops,timedelta,Python,Pandas,Loops,Timedelta,我有一个如下所示的数据帧: Name Date Person A 2019-06-18 Person A 2019-05-14 Person A 2019-04-03 Person B 2019-05-19 Person C 2019-05-16 Person C 2019-05-23 Person C 2019-05-15 Person D 2019-06-21 Name Date Person

我有一个如下所示的数据帧:

Name         Date
Person A     2019-06-18
Person A     2019-05-14
Person A     2019-04-03
Person B     2019-05-19
Person C     2019-05-16
Person C     2019-05-23
Person C     2019-05-15
Person D     2019-06-21
Name         Date
Person A     2019-06-18
Person A     2019-05-07
Person A     2019-04-03
Person B     2019-05-12
Person C     2019-05-09
Person C     2019-05-09
Person C     2019-05-08
Person D     2019-06-21
我想做的是修改5/14和6/14之间的任何人的日期,并减去7天。如果此操作完成后,它们仍在该范围内,则再减去7天

最后,我希望数据如下所示:

Name         Date
Person A     2019-06-18
Person A     2019-05-14
Person A     2019-04-03
Person B     2019-05-19
Person C     2019-05-16
Person C     2019-05-23
Person C     2019-05-15
Person D     2019-06-21
Name         Date
Person A     2019-06-18
Person A     2019-05-07
Person A     2019-04-03
Person B     2019-05-12
Person C     2019-05-09
Person C     2019-05-09
Person C     2019-05-08
Person D     2019-06-21
(在这一步之后,我将把它汇总起来,这样每个人都有一行他们所有的日期,然后向他们发送他们的信息——但我想我可以自己解决这个问题。)

现在,我有以下代码“正在工作”:


我们可以使用
range()
创建一个简单的循环,然后使用该循环有条件地更改两个日期之间的每一行:

for i in range(2):
    df['Date'] = np.where(df['Date'].between('20190514','20190614'), 
                          df['Date'] - pd.Timedelta(days=7), 
                          df['Date'])

print(df)

       Name       Date
0  Person A 2019-06-18
1  Person A 2019-05-07
2  Person A 2019-04-03
3  Person B 2019-05-12
4  Person C 2019-05-09
5  Person C 2019-05-09
6  Person C 2019-05-08
7  Person D 2019-06-21

我只需要计算一下你必须从每个日期中减去多少次,然后一步完成



以下是一个不在位修改框架的版本:

m = df.Date.between('2019-05-14', '2019-06-14')
d = df.Date - pd.Timestamp('2019-05-13')

o = np.ceil(d.dt.days / 7)

df.assign(Date=np.where(m, df.Date - (o * np.timedelta64(7, 'D')), df.Date))


您可以编写一个函数,然后将其应用于日期列。
pd.Series.apply
方法通过将每个值传递给提供的函数来工作。在函数中,你有一个简单的while循环,它会持续减去7天,直到你在你想要的日期范围内

from datetime import datetime as dt
from datetime import timedelta

def date_modifier(x):
    d = x
    while True:
        if d >= dt(2019, 5, 14) and d<=dt(2019, 6, 14):
            d-= timedelta(days=7)
        else:
            return d
df['Date-Mod'] = df['Date'].apply(date_modifier)

我假设
Date
列属于
datetime64
类型

第一步是定义“边界日期”:

然后,我们必须定义应用于每个日期的函数:

def fn(dat):
    inRng = (dat >= start_date) & (dat <= end_date)
    dat2 = dat
    if inRng:
        diffWeeks = int((dat - start_date) / np.timedelta64(1, 'W')) + 1
        dat2 -= np.timedelta64(diffWeeks, 'W')
    return dat2
打印数据帧时,您将获得:

       Name       Date       Dat2
0  Person A 2019-06-18 2019-06-18
1  Person A 2019-05-14 2019-05-07
2  Person A 2019-04-03 2019-04-03
3  Person B 2019-05-19 2019-05-12
4  Person C 2019-05-16 2019-05-09
5  Person C 2019-05-23 2019-05-09
6  Person C 2019-05-15 2019-05-08
7  Person D 2019-06-21 2019-06-21

你的方法的范围是2,适用于给定的数据,但如果日期是,例如,20190613,则不需要,我认为至少需要4或5的范围,因为你查看的日期间隔是一个月。具体来说,要减去两次。这就是我为什么使用范围。但是我们可以加5只是为了确定..我明白了,我明白OP不希望这两个界限之间有日期,操作应该在那之前完成。只是对问题的一种解释:)
from datetime import datetime as dt
from datetime import timedelta

def date_modifier(x):
    d = x
    while True:
        if d >= dt(2019, 5, 14) and d<=dt(2019, 6, 14):
            d-= timedelta(days=7)
        else:
            return d
df['Date-Mod'] = df['Date'].apply(date_modifier)
      Name       Date   Date-Mod
0  PersonA 2019-06-18 2019-06-18
1  PersonA 2019-05-14 2019-05-07
2  PersonA 2019-04-03 2019-04-03
3  PersonB 2019-05-19 2019-05-12
4  PersonC 2019-05-16 2019-05-09
5  PersonC 2019-05-23 2019-05-09
6  PersonC 2019-05-15 2019-05-08
7  PersonD 2019-06-21 2019-06-21
start_date = pd.to_datetime('2019-05-14')
end_date = pd.to_datetime('2019-06-14')
def fn(dat):
    inRng = (dat >= start_date) & (dat <= end_date)
    dat2 = dat
    if inRng:
        diffWeeks = int((dat - start_date) / np.timedelta64(1, 'W')) + 1
        dat2 -= np.timedelta64(diffWeeks, 'W')
    return dat2
df['Dat2'] = df.Date.apply(fn)    
       Name       Date       Dat2
0  Person A 2019-06-18 2019-06-18
1  Person A 2019-05-14 2019-05-07
2  Person A 2019-04-03 2019-04-03
3  Person B 2019-05-19 2019-05-12
4  Person C 2019-05-16 2019-05-09
5  Person C 2019-05-23 2019-05-09
6  Person C 2019-05-15 2019-05-08
7  Person D 2019-06-21 2019-06-21