首页 > 解决方案 > 当 np.where 无法工作时,可以更快地替代 pandas 数据框中的 apply()

问题描述

我有一个包含 600,000 行的数据框,其中包含一个日期列。问题是这些日期以两种不同格式作为字符串随机输入:

  1. 非常标准的日期时间格式的字符串,例如“2018-05-07 04:28:45.970”
  2. UNIX 日期时间格式的字符串,例如“1526366895249000000”(是的,精确到纳秒,但精度不是问题,因为所有条目都以 000000 结尾)

除了这两种格式之外,column 中还有 NaN 值。我正在尝试清理此列并将其转换为统一的日期时间数据类型。

我编写了以下函数来做到这一点:

def date_extractor(dt):
    # for UNIX format
    if str(dt).isdigit():
        return datetime.utcfromtimestamp(int(dt)/1000000000)
    # for nan
    elif type(dt) == float:
        return dt
    # for the common datetime format
    else:
        return datetime.strptime(str(dt), '%Y-%m-%d %H:%M:%S.%f')

这是我对该apply()函数的调用:

%time df['Date'] = df['Date'].apply(date_extractor)

显然,这是一种非常粗鲁的做法。例如,在上面的函数中,我首先检查了 UNIX 格式,然后检查了 NaN,最后检查了日期时间格式。但是,我的绝大多数日期条目都是日期时间格式。因此,对于日期条目为日期时间格式的循环的每次迭代,循环必须在最终到达最后的 else 语句之前检查前两个 if 语句。因为我不知道如何编写一个非常有效的 if 条件来专门检查日期时间格式,然后再检查 NaN 或 UNIX 格式并且不会导致错误。其次,如您所见,我使用该条件type(dt) == float来检查 NaN。如果我使用isnan()isnull(),如果日期条目是日期时间格式的字符串,并且仅在最后检查,它将引发错误。

专业人士,有哪些更快、更好的做法可以遵循?

此外,我的代码运行所有 600,000 行大约需要 10 秒。但我也想将我的代码扩展到大约 100 倍大的数据。如何重写我的date_extractor()函数以更快地完成此任务?我读到一种方法是使用numpy.where()语句而不是,apply()但如果以 numpy.where 格式编写,我现有的代码将引发错误。

这是一个演示(嵌套 np.where):

np.where(str(df['Date']).isdigit() == True, datetime.utcfromtimestamp(int(df['Date'])/1000000000), 
        np.where(type(df['Date']) == float, df['Date'], 
                datetime.strptime(str(dt), '%Y-%m-%d %H:%M:%S.%f')))

这会引发很多错误——比如调用isdigit()整列、将整列传递给int()函数等。

特长; 什么是清理我的日期列的更好方法(或者可能是最好的方法),请记住,我的大多数日期条目都是日期时间字符串格式,例如“2018-05-07 04:28:45.970”,其中一些在像“1526366895249000000”这样的 UNIX 格式,还有几个是 NaN?您可以建议一个更好的代码与我现有的 apply() 函数一起使用,或者完全建议一个不同的方法。

在此处查找示例数据: https ://github.com/verterse/experiments/blob/main/sample.csv

标签: pythonpandasnumpydatetimedata-cleaning

解决方案


单程:

df.date = (
    pd.to_datetime(
        pd.to_numeric(df.date, errors='coerce'),
        unit='ns',
        origin='unix')
    .fillna(pd.to_datetime(df.date, errors='coerce'))
)

输出(基于样本数据):

                 VisitDateTime   UserID Activity
0 2018-05-15 06:48:15.248999936  U106593    click
1 2018-05-23 07:02:01.790000128  U108297      NaN
2 2018-05-10 06:28:53.391000000  U132443      NaN
3 2018-05-08 12:40:02.153000000  U134616    click
4 2018-05-11 15:35:43.689000000  U130784    click

推荐阅读