timedelta64字符串格式化输出

7

与这个问题类似,我在pandas DataFrame中有一个numpy.timedelta64列。根据前面提到的问题的答案,有一个函数pandas.tslib.repr_timedelta64可以很好地显示以天为单位的时间差,小时:分钟:秒。我只想将它们格式化为天和小时。

所以我现在有以下内容:

def silly_format(hours):
    (days, hours) = divmod(hours, 24)
    if days > 0 and hours > 0:
        str_time = "{0:.0f} d, {1:.0f} h".format(days, hours)
    elif days > 0:
        str_time = "{0:.0f} d".format(days)
    else:
        str_time = "{0:.0f} h".format(hours)
    return str_time

df["time"].astype("timedelta64[h]").map(silly_format)

这段代码可以输出想要的结果,但我在想是否有一个类似于datetime.strftime的函数存在于numpypandas中,可以根据提供的格式字符串格式化numpy.timedelta64


我尝试进一步改进@Jeff的解决方案,但它比我的答案慢得多。这是它:

days = time_delta.astype("timedelta64[D]").astype(int)
hours = time_delta.astype("timedelta64[h]").astype(int) % 24
result = days.astype(str)
mask = (days > 0) & (hours > 0)
result[mask] = days.astype(str) + ' d, ' + hours.astype(str) + ' h'
result[(hours > 0) & ~mask] = hours.astype(str) + ' h'
result[(days > 0) & ~mask] = days.astype(str) + ' d'

可以使用 pandas.tslib.repr_timedelta64,但是是否可以去掉分钟/秒部分? - joris
你的意思是,将字符串按 ':' 分割,然后添加 'h' 吗? - Midnighter
例如,是的。或者删除最后6个字符(但如果可能存在微秒,则似乎不够健壮)。 - joris
它可以正常工作。在这种情况下,小时数是零填充的,实际上比上面的方法略慢。 - Midnighter
如果速度较慢,你应该使用自己的解决方案,它看起来很不错! - joris
4个回答

5

@sebix和@Jeff提供的答案展示了一种将时间差转换为天数和小时的好方法,特别是@Jeff的解决方案保留了Series的索引,但它们在最终字符串格式的灵活性方面欠缺。我现在使用的解决方案是:

def delta_format(days, hours):
    if days > 0 and hours > 0:
        return "{0:.0f} d, {1:.0f} h".format(days, hours)
    elif days > 0:
        return "{0:.0f} d".format(days)
    else:
        return "{0:.0f} h".format(hours)

days = time_delta.astype("timedelta64[D]")
hours = time_delta.astype("timedelta64[h]") % 24
return [delta_format(d, h) for (d, h) in izip(days, hours)]

这非常适合我,我通过将该列表插入原始的DataFrame来获取索引。


1

@Midnighter的答案在Python 3中对我无效,所以这是我的更新函数:

def delta_format(delta: np.timedelta64) -> str:
    days = delta.astype("timedelta64[D]") / np.timedelta64(1, 'D')
    hours = int(delta.astype("timedelta64[h]") / np.timedelta64(1, 'h') % 24)

    if days > 0 and hours > 0:
        return f"{days:.0f} d, {hours:.0f} h"
    elif days > 0:
        return f"{days:.0f} d"
    else:
        return f"{hours:.0f} h"

基本相同,但使用f-strings,并且有更多的类型转换。

1
这是如何以向量化的方式完成它。
In [28]: s = pd.to_timedelta(range(5),unit='d') + pd.offsets.Hour(3)

In [29]: s
Out[29]: 
0   0 days, 03:00:00
1   1 days, 03:00:00
2   2 days, 03:00:00
3   3 days, 03:00:00
4   4 days, 03:00:00
dtype: timedelta64[ns]

In [30]: days = s.astype('timedelta64[D]').astype(int)

In [31]: hours = s.astype('timedelta64[h]').astype(int)-days*24

In [32]: days
Out[32]: 
0    0
1    1
2    2
3    3
4    4
dtype: int64

In [33]: hours
Out[33]: 
0    3
1    3
2    3
3    3
4    3
dtype: int64

In [34]: days.astype(str) + ' d, ' + hours.astype(str) + ' h'
Out[34]: 
0    0 d, 3 h
1    1 d, 3 h
2    2 d, 3 h
3    3 d, 3 h
4    4 d, 3 h
dtype: object

如果您想要与原帖完全相同的内容:
In [4]: result = days.astype(str) + ' d, ' + hours.astype(str) + ' h'

In [5]: result[days==0] = hours.astype(str) + ' h'

In [6]: result
Out[6]: 
0         3 h
1    1 d, 3 h
2    2 d, 3 h
3    3 d, 3 h
4    4 d, 3 h
dtype: object

我很欣赏你的解决方案能够保留 Series 的索引。我没有想到一种好的方法来显示 %d d, %d h%d d%d h,除非使用非常复杂的代码。因此,我选择将其插入到现有的 DataFrame 中作为列表,从而获得索引。 - Midnighter
我更新了。 正如我所说,一旦你有了这个系列,你可以做几乎任何你想做的事情。 - Jeff
我已经按照你的建议更新了我的问题,但这比下面的答案更麻烦。 - Midnighter
无论什么方法都可以。除非您有一个小尺寸的框架,否则这可能会更慢,但这种情况下也不重要。 - Jeff
根据“小”的定义,在50,000行的情况下,我问题编辑部分的解决方案要慢4倍。 - Midnighter

0

我不知道在pandas中如何实现,但这是我使用纯numpy的方法来解决你的问题:

import numpy as np
t = np.array([200487900000000,180787000000000,400287000000000,188487000000000], dtype='timedelta64[ns]')

days = t.astype('timedelta64[D]').astype(np.int32) # gives: array([2, 2, 4, 2], dtype=int32)
hours = t.astype('timedelta64[h]').astype(np.int32)%24 # gives: array([ 7,  2, 15,  4], dtype=int32)

所以我只需将原始数据转换为所需的输出类型(让numpy处理),然后我们就有了两个包含数据的数组,可以自由使用。要将它们成对分组,只需执行以下操作:

>>> np.array([days, hours]).T
array([[ 2,  7],
       [ 2,  2],
       [ 4, 15],
       [ 2,  4]], dtype=int32)

例如:

for row in d:
    print('%dd %dh' % tuple(row))

给出:

2d 7h
2d 2h
4d 15h
2d 4h

你的解决方案和模数的使用很好,但它并不能保留上述函数的完整格式选项。 - Midnighter

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