Dask Dataframe如何将列转换为日期时间格式

19

我正在尝试将数据框的一列转换为日期时间格式。根据这里的讨论 https://github.com/dask/dask/issues/863,我尝试了以下代码:

import dask.dataframe as dd
df['time'].map_partitions(pd.to_datetime, columns='time').compute()

但是我收到了以下错误信息

ValueError: Metadata inference failed, please provide `meta` keyword

我应该在meta下放什么?应该将df中的所有列的字典放在其中,还是只放'time'列的字典?我应该放哪种类型?我已尝试使用dtype和datetime64,但到目前为止没有起作用。

谢谢您的指导,非常感谢。

更新

我将在此处包含新的错误消息:

1)使用Timestamp

df['trd_exctn_dt'].map_partitions(pd.Timestamp).compute()

TypeError: Cannot convert input to Timestamp

2) 使用 datetime 和 meta

meta = ('time', pd.Timestamp)
df['time'].map_partitions(pd.to_datetime,meta=meta).compute()
TypeError: to_datetime() got an unexpected keyword argument 'meta'

3) 仅使用日期时间:进程卡在2%。

    In [14]: df['trd_exctn_dt'].map_partitions(pd.to_datetime).compute()
[                                        ] | 2% Completed |  2min 20.3s

同时,我希望能够像在pandas中那样指定日期的格式:

pd.to_datetime(df['time'], format = '%m%d%Y'

更新2

升级到Dask 0.11后,我不再遇到元关键字的问题。但是,我仍然无法在一个2GB的数据框中超过2%。

df['trd_exctn_dt'].map_partitions(pd.to_datetime, meta=meta).compute()
    [                                        ] | 2% Completed |  30min 45.7s

更新3

这个方法效果更好:

def parse_dates(df):
  return pd.to_datetime(df['time'], format = '%m/%d/%Y')

df.map_partitions(parse_dates, meta=meta)

我不确定这是否是正确的方法。


你使用的 Dask 版本是哪个? - MRocklin
MRocklin,你是对的,我更新到了0.11版本,现在不再遇到元关键字的问题了。但是,它在不到30秒内完成了1和2%,但在那里卡了一个小时。有什么建议吗? - dleal
我认为我使用定义一个函数来解析日期并使用map partitions应用它,已经半解决了这个问题。 - dleal
根据我们的经验,使用“format”关键字总是能够提高性能。 - skibee
5个回答

24

使用 astype

您可以使用astype方法将Series的dtype转换为NumPy dtype。

df.time.astype('M8[us]')

可能有一种方法可以指定 Pandas 样式的 dtype(欢迎编辑)

使用 map_partitions 和 meta

当使用类似于 map_partitions 的黑盒方法时,dask.dataframe 需要知道输出的类型和名称。在 map_partitions 的 docstring 中列出了几种方法。

您可以提供一个具有正确 dtype 和名称的空 Pandas 对象

meta = pd.Series([], name='time', dtype=pd.Timestamp)

或者您可以为Series提供一个元组(name, dtype),为DataFrame提供一个字典

meta = ('time', pd.Timestamp)

那么一切应该没问题了。

df.time.map_partitions(pd.to_datetime, meta=meta)

如果你在 df 上调用 map_partitions,那么你需要为所有内容提供数据类型。但是,在你的例子中并非如此。


1
谢谢MRocklin!请在问题中查看我的更新。 - dleal
7
在使用pandas 0.20版本时,我的操作已经不再起作用了,出现了dtype <class 'pandas._lib.tslib.Timestamp'> not understood的错误提示。但是,如果使用meta = ('time', np.datetime64),则可以正常工作。 - architectonic
12
使用 meta = ('time', 'datetime64[ns]') 没有警告未来被弃用的情况下,对我很有效。 - FlorianGD
这是一个链接,指向 numpy datetime 文档 - skibee

20

Dask还提供了to_timedelta函数,因此这也可以正常工作。

df['time']=dd.to_datetime(df.time,unit='ns')

values unit参数与pandas中的pd.to_timedelta相同。您可以在此处找到它here


7

我不确定这是否是正确的方法,但对我来说,映射该列是有效的:

df['time'] = df['time'].map(lambda x: pd.to_datetime(x, errors='coerce'))

可以运行,但使用 lambda 映射不利于性能。 - Freek Wiekmeijer

6

这对我很有用

ddf["Date"] = ddf["Date"].map_partitions(pd.to_datetime, format='%d/%m/%Y', meta=('datetime64[ns]'))


如果月份是这种格式:'JAN'(注意是大写),该怎么办? - Fabio Magarelli

1
如果日期时间不是ISO格式,则使用map_partition可以获得更好的结果:
import dask
import pandas as pd
from dask.distributed import Client
client = Client()

ddf = dask.datasets.timeseries()
ddf = ddf.assign(datetime=ddf.index.astype(object))
ddf = (ddf.assign(datetime_nonISO = ddf['datetime'].astype(str).str.split(' ')
                                 .apply(lambda x: x[1]+' '+x[0], meta=('object'))) 

%%timeit
ddf.datetime = ddf.datetime.astype('M8[s]')
ddf.compute()

每次循环需时11.3秒,标准差为719毫秒(7次运行的平均值和标准偏差,每次运行1次)

ddf = dask.datasets.timeseries()
ddf = ddf.assign(datetime=ddf.index.astype(object))
ddf = (ddf.assign(datetime_nonISO = ddf['datetime'].astype(str).str.split(' ')
                                 .apply(lambda x: x[1]+' '+x[0], meta=('object'))) 


%%timeit
ddf.datetime_nonISO = (ddf.datetime_nonISO.map_partitions(pd.to_datetime
                       ,  format='%H:%M:%S %Y-%m-%d', meta=('datetime64[s]')))
ddf.compute()

每次循环平均用时8.78秒,标准差为599毫秒(基于7次运行,每次运行1个循环)

ddf = dask.datasets.timeseries()
ddf = ddf.assign(datetime=ddf.index.astype(object))
ddf = (ddf.assign(datetime_nonISO = ddf['datetime'].astype(str).str.split(' ')
                                 .apply(lambda x: x[1]+' '+x[0], meta=('object'))) 

%%timeit
ddf.datetime_nonISO = ddf.datetime_nonISO.astype('M8[s]')
ddf.compute()

每个循环需要1分8秒±3.65秒(平均值±7次运行的标准差,每次循环1次)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接