我有以下名为df
、的数据帧
Date Data
05/30/2023 3.733
05/30/2022 3.294
05/30/2021 2.391
02/30/2021 1.807
11/30/2020 1.766
08/31/2020 1.920
05/31/2020 1.830
02/29/2020 2.960
11/30/2019 2.860
08/31/2019 2.680
05/31/2019 2.490
02/28/2019 2.560
11/30/2018 2.560
08/31/2018 2.500
05/31/2018 2.400
02/28/2018 2.310
11/30/2017 2.310
08/31/2017 2.350
05/31/2017 2.510
02/28/2017 2.400
11/30/2016 2.270
08/31/2016 2.220
05/31/2016 2.160
02/29/2016 2.160
11/30/2015 2.055
我可以看到第4个条目的日期无效。(一月份只有28或29天(我以前试图使用pd.to_datetime
函数转换日期索引,但一直出现错误。所以我试了一下。
df['tempdate'] = pd.to_datetime(df.index, errors='coerce')
这张表就是
Date Data tempdate
05/30/2023 3.733 2023-05-30
05/30/2022 3.294 2022-05-30
05/30/2021 2.391 2021-05-30
02/30/2021 1.807 NaT
11/30/2020 1.766 2020-11-30
08/31/2020 1.920 2020-08-31
05/31/2020 1.830 2020-05-31
02/29/2020 2.960 2020-02-29
11/30/2019 2.860 2019-11-30
08/31/2019 2.680 2019-08-31
05/31/2019 2.490 2019-05-31
02/28/2019 2.560 2019-02-28
11/30/2018 2.560 2018-11-30
08/31/2018 2.500 2018-08-31
05/31/2018 2.400 2018-05-31
02/28/2018 2.310 2018-02-28
11/30/2017 2.310 2017-11-30
08/31/2017 2.350 2017-08-31
05/31/2017 2.510 2017-05-31
02/28/2017 2.400 2017-02-28
11/30/2016 2.270 2016-11-30
08/31/2016 2.220 2016-08-31
05/31/2016 2.160 2016-05-31
02/29/2016 2.160 2016-02-29
11/30/2015 2.055 2015-11-30
问题是,我有很多这样的数据帧,错误可能是随机的几个月,本应是30天,但它们显示为31天。
我只想从任何一个出现NaT
错误的日期中减去3天。但由于这些日期不被视为日期,我似乎无法从中减去3天。
有没有一个pandas命令可以用程序修复这个错误?
我试过
df.index = np.where(df['tempdate'].isna(), pd.to_datetime(df.index), pd.to_datetime(df['tempdate']-np.timedelta64(3,'D')))
但我仍然有一个错误,那就是当天超出了范围。
我还尝试将日期分解为不同的strings
,并将其转换为int
,以使用减去3天
df.index = np.where(df['tempdate'].isna(), df.index, pd.to_datetime(int(df.index.astype(str).str.split('/')[0]),int(df.index.astype(str).str.split('/')[1])-3,int(df.index.astype(str).str.split('/')[2])))
但是我得到了这个错误,
TypeError: int() argument must be a string, a bytes-like object or a number, not 'list'
处理此类错误的最佳方法是什么?如何将此无效日期转换为最近的有效日期?
您可以转换您可以转换的内容,然后使用正则表达式替换中断的天数,然后更新您以前尝试的转换。
def subtract_3_days(match):
days = int(match.group(1))
return str(days - 3)
tempdate = pd.to_datetime(df["Date"], format="%m/%d/%Y", errors="coerce")
fixed_dates = df.loc[tempdate.isna(), "Date"].str.replace(r"(?<=/)(d+)(?=/)", subtract_3_days)
tempdate.update(pd.to_datetime(fixed_dates, format="%m/%d/%Y"))
df["proper_dates"] = tempdate
print(df)
Date Data proper_dates
0 05/30/2023 3.733 2023-05-30
1 05/30/2022 3.294 2022-05-30
2 05/30/2021 2.391 2021-05-30
3 02/30/2021 1.807 2021-02-27
4 11/30/2020 1.766 2020-11-30
5 08/31/2020 1.920 2020-08-31
6 05/31/2020 1.830 2020-05-31
7 02/29/2020 2.960 2020-02-29
8 11/30/2019 2.860 2019-11-30
9 08/31/2019 2.680 2019-08-31
10 05/31/2019 2.490 2019-05-31
11 02/28/2019 2.560 2019-02-28
12 11/30/2018 2.560 2018-11-30
13 08/31/2018 2.500 2018-08-31
14 05/31/2018 2.400 2018-05-31
15 02/28/2018 2.310 2018-02-28
16 11/30/2017 2.310 2017-11-30
17 08/31/2017 2.350 2017-08-31
18 05/31/2017 2.510 2017-05-31
19 02/28/2017 2.400 2017-02-28
20 11/30/2016 2.270 2016-11-30
21 08/31/2016 2.220 2016-08-31
22 05/31/2016 2.160 2016-05-31
23 02/29/2016 2.160 2016-02-29
24 11/30/2015 2.055 2015-11-30
分解:
tempdate = pd.to_datetime(df["Date"], format="%m/%d/%Y", errors="coerce")
将我们所能转换为日期时间。如果它导致不正确的日期时间,那么我们将以NaT值结束。将这个数组存储到一个名为"的变量中;tempdate";fixed_dates = df.loc[tempdate.isna(), "Date"].str.replace(r"(?<=/)(d+)(?=/)", subtract_3_days)
df.loc[tempdate.isna(), "Date"]
->无论tempdate
在哪里具有NaT值,都可以在我们的原始"中找到相应的字符串;日期";我们df
的专栏- 从转换不好的字符串子集中的
.str.replace(r"(?<=/)(d+)(?=/)", subtract_3_days)
,找到该数组中被正斜杠包围的所有数字。(例如,在这个模式上匹配:"/数字/"以获得数字(。然后,当我们找到匹配项时,通过subtract_3_days
函数运行它,将该匹配项转换为整数,减去3,并将新值作为字符串返回。这将保留斜杠(月份和年份(之前或之后的任何数字。现在我们有一个字符串数组;"天";值基本上已经从中减去了3天
tempdate.update(pd.to_datetime(fixed_dates, format="%m/%d/%Y"))
既然我们确定了日期,但它们仍然是字符串。我们需要转换它们,然后替换tempdate中的NaT
值。df["proper_dates"] = tempdate
最后将我们的数组/系列添加回原始数据帧中,作为一个新列。