熊猫逐渐减去日期,直到满足数据帧上的条件

Posted

技术标签:

【中文标题】熊猫逐渐减去日期,直到满足数据帧上的条件【英文标题】:Pandas subtract a date incrementally until a condition is met on a dataframe 【发布时间】:2019-09-02 10:08:06 【问题描述】:

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

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

我想要做的是修改 5/14 到 6/14 之间任何人的日期并减去 7 天。如果在此操作完成后,它们仍在该范围内,则再减去 7 天。

最后,我希望数据看起来像这样:

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

(在这一步之后,我将把它卷起来,这样每个人都有一行包含他们所有的日期,然后将他们的信息发送给他们——但我想我可以自己解决这个问题。)

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

df = df[(df['Date'] >= '2019-05-14') & (df['Date'] <= '2019-06-14')]
df['Date'] = df['Date'] - pd.Timedelta(days=7)

但是,我不知道如何循环它,我也不知道如何在不丢失原始数据的情况下应用它。

因此,我的代码产生了这个框架:

Name         Date
Person A     2019-05-07
Person B     2019-05-12
Person C     2019-05-16
Person C     2019-05-08

【问题讨论】:

【参考方案1】:

我们可以用range() 做一个简单的循环,然后使用numpy.where 有条件地更改每一行(如果它在两个日期之间):

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

【讨论】:

范围为 2 的方法适用于给定的数据,但如果日期是例如20190613 不会,我认为您至少需要 4 或 5 的范围,因为您查看的日期间隔是一个月 Op 明确表示要减去两次。这就是我使用范围的原因。但是我们可以添加 5 来确定.. 我明白了,我知道 OP 希望在这两个界限之间没有日期,并且应该在此之前完成操作。只是对问题的解释:)【参考方案2】:

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


m = df.Date.between('2019-05-14', '2019-06-14')
u = df[m]

d = u.Date - pd.Timestamp('2019-05-13')
o = np.ceil(d.dt.days / 7)

df.loc[m, 'Date'] = df.loc[m, 'Date'] - (o * np.timedelta64(7, 'D'))

       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))

       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

【讨论】:

【参考方案3】:

您可以通过编写一个函数然后将其应用于日期列来做到这一点。 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)

给出以下输出:

      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

【讨论】:

【参考方案4】:

我假设Date 列属于datetime64 类型。

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

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

最后一步是应用这个函数。 为了便于比较源数据和结果,我决定用 结果在新列中 (Dat2):

df['Dat2'] = df.Date.apply(fn)    

当你打印你的 DataFrame 时,你会得到:

       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

【讨论】:

以上是关于熊猫逐渐减去日期,直到满足数据帧上的条件的主要内容,如果未能解决你的问题,请参考以下文章

减去熊猫中的日期时间列时返回错误

在熊猫多索引数据框中返回满足逻辑索引条件的每个组的最后一行[重复]

从熊猫的日期时间列中减去一年

如何在熊猫数据帧上迭代 TfidfVectorizer()

Python:在熊猫数据帧上使用多处理

为啥在数据帧上具有中位数的 fillna 仍然在熊猫中留下 Na/NaN?