【问题标题】:Format timedelta64 string output格式化timedelta64字符串输出
【发布时间】:2014-08-15 11:38:01
【问题描述】:

question 类似,我在 pandas DataFrame 中有一个 numpy.timedelta64 列。根据answer 对上述问题,有一个函数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)

这让我得到了想要的输出,但我想知道numpypandas 中是否有类似于datetime.strftime 的函数可以根据提供的某些格式字符串格式化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,然后切断分钟/秒部分?
  • 你的意思是,在':'上分割字符串,然后附加'h'?
  • 是的,例如。或删除最后 6 个字符(但如果可能存在微秒,这似乎不太可靠)
  • 它工作 0K。在这种情况下,小时是零填充的,它实际上比上述方法稍慢。
  • 如果速度较慢,你应该使用自己的解决方案,看起来不错!

标签: python numpy pandas timedelta


【解决方案1】:

虽然@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 来取回索引。

【讨论】:

    【解决方案2】:

    以下是如何以矢量化方式进行操作。

    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
    

    如果您想要完全按照 OP 提出的要求:

    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 的列表,从而取回索引。
    • 我更新了。正如我所说,一旦你有了这个系列,你就可以随心所欲地做。
    • 我用你的建议更新了我的问题,但这比我下面的回答要麻烦得多。
    • 不管怎样。怀疑这实际上会更慢,除非你有一个小尺寸的框架,在这种情况下没关系。
    • 取决于小的定义,即使是 50k 行,我的问题的编辑部分的解决方案要慢 4 倍。
    【解决方案3】:

    @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 字符串和更多类型强制。

    【讨论】:

      【解决方案4】:

      我不知道它是如何在 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
      

      【讨论】:

      • 您的解决方案和模数的使用很好,但它没有保留上述函数的完整格式选项。
      猜你喜欢
      • 2012-03-01
      • 1970-01-01
      • 2014-11-06
      • 1970-01-01
      • 1970-01-01
      • 2012-01-04
      • 2010-10-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多