我正在尝试用Python运行一个数据清理脚本。我有一个基类,它有一个名为cleanData((的函数。根据返回的数据集,有许多日期字段,所有字段都以_DT结尾,但可以以任何内容开头(如SCHEDULED_start_DT、SERVICE_DISRUPT_DT等(。这段代码将支持数百个报告,因此,我不想为每个报告重载对象和方法,而是希望在以_DT结尾的每个字段上动态运行一个函数,如果有额外的报告特有的清理,则只调用父方法。所有这些代码所做的就是将UTC历元时间戳更改为可读的本地时区。以下是我的数据样本和代码:
样本数据
ID SCHEDULED_START_DT SERVICE_DISRUPTION_START_DT
0 1597669200 1597712400
1 1597667496 None
代码片段
from datetime import datetime, timezone
import datetime as dt
import time
import requests
import pandas as pd
d = {'ID': [0, 1],
'SCHEDULED_START_DT': [1597669200, 1597667496],
'SERVICE_DISRUPTION_START_DT' : [1597712400, None]
}
df = pd.DataFrame(data=d)
df['SCHEDULED_START_DT'] = df['SCHEDULED_START_DT'].apply(lambda x : dt.datetime.fromtimestamp(x) if pd.notnull(x) else x)
df['SERVICE_DISRUPTION_START_DT'] = df['SERVICE_DISRUPTION_START_DT'].apply(lambda x : dt.datetime.fromtimestamp(x) if pd.notnull(x) else x)
代码输出
ID SCHEDULED_START_DT SERVICE_DISRUPTION_START_DT
0 2020-08-17 08:00:00 2020-08-17 20:00:00
1 2020-08-17 07:31:36 NaT
我认为有一种方法可以在所有以_DT结尾的字段上动态应用该函数,而无需循环和逻辑构造。我看到了一些类似这样的问题,但我不知道该怎么做
提前感谢您的帮助。
Pete
list(df.columns)
将返回列名。
绕过去做一件事:
for name in list(df.columns):
if name.endswith('_DT'):
#your logic goes here
您可以将filter
(以获得以'_DT'
结尾的所有列(与update
(以恢复这些更改(组合在一起。在这个伪示例中,我只添加20。
import pandas as pd
df = pd.DataFrame(np.random.randint(1, 10, (3, 5)),
columns=['DT', 'foo', 'foo_DT', 'bar_DT', 'start_DT_end'])
df.update(df.filter(regex='_DT$')+20)
print(df)
DT foo foo_DT bar_DT start_DT_end
0 9 3 23 21 6
1 9 4 26 27 7
2 5 7 26 26 4
在您的情况下,我们可以取消慢速Series.apply
,而使用DataFrame.apply(axis=0)
,它将在每个列系列而不是行上循环。但我们需要小心,因为pandas
与datetime
模块不一致。因此,为了得到确切的输出,我需要处理时区并减去差值。
当update
尝试用datetime64[ns]
覆盖int
列时,它也存在问题。因此,我们将concat
返回结果。
from datetime import datetime
import pytz
my_date = datetime(2020, 2, 17)
my_date_aware = pytz.utc.localize(my_date)
# Seconds of disagreement
offs = datetime.timestamp(my_date) - pd.to_datetime(my_date).timestamp()
#18000.0
# Turn all into `datetime`
df1 = (df.filter(regex='_DT$').apply(pd.to_datetime, errors='coerce', unit='s')
-pd.Timedelta(offs, unit='s'))
# Join columns we didn't modify those we did
df = pd.concat([df[df.columns.difference(df1.columns)], df1], axis=1)
print(df)
# ID SCHEDULED_START_DT SERVICE_DISRUPTION_START_DT
#0 0 2020-08-17 08:00:00 2020-08-17 20:00:00
#1 1 2020-08-17 07:31:36 NaT