如何在所有以_DT结尾的panda列上运行函数



我正在尝试用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),它将在每个列系列而不是行上循环。但我们需要小心,因为pandasdatetime模块不一致。因此,为了得到确切的输出,我需要处理时区并减去差值。

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

最新更新