【问题标题】:timedelta to string type in pandas dataframe熊猫数据框中的 timedelta 到字符串类型
【发布时间】:2018-06-29 12:09:13
【问题描述】:

我有一个数据框df,它的第一列是timedelta64

df.info():

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 686 entries, 0 to 685
Data columns (total 6 columns):
0    686 non-null timedelta64[ns]
1    686 non-null object
2    686 non-null object
3    686 non-null object
4    686 non-null object
5    686 non-null object

例如,如果我print(df[0][2]),它将给我0 days 05:01:11。但是,我不希望提交 0 days。我只想打印05:01:11。有人可以教我如何做到这一点吗?非常感谢!

【问题讨论】:

  • 对结果列的数据类型有任何偏好吗?
  • 对象类型对我来说没问题

标签: python pandas timedelta


【解决方案1】:

可以通过:

df['duration1'] = df['duration'].astype(str).str[-18:-10]

但解决方案并不通用,如果输入是3 days 05:01:11,它也会删除3 days

因此解决方案仅适用于小于一天的时间增量。

更通用的解决方案是create custom format:

N = 10
np.random.seed(11230)
rng = pd.date_range('2017-04-03 15:30:00', periods=N, freq='13.5H')
df = pd.DataFrame({'duration': np.abs(np.random.choice(rng, size=N) - 
                                 np.random.choice(rng, size=N)) })  

df['duration1'] = df['duration'].astype(str).str[-18:-10]

def f(x):
    ts = x.total_seconds()
    hours, remainder = divmod(ts, 3600)
    minutes, seconds = divmod(remainder, 60)
    return ('{}:{:02d}:{:02d}').format(int(hours), int(minutes), int(seconds)) 

df['duration2'] = df['duration'].apply(f)
print (df)

         duration duration1  duration2
0 2 days 06:00:00  06:00:00   54:00:00
1 2 days 19:30:00  19:30:00   67:30:00
2 1 days 03:00:00  03:00:00   27:00:00
3 0 days 00:00:00  00:00:00    0:00:00
4 4 days 12:00:00  12:00:00  108:00:00
5 1 days 03:00:00  03:00:00   27:00:00
6 0 days 13:30:00  13:30:00   13:30:00
7 1 days 16:30:00  16:30:00   40:30:00
8 0 days 00:00:00  00:00:00    0:00:00
9 1 days 16:30:00  16:30:00   40:30:00

【讨论】:

    【解决方案2】:

    这是一个使用 apply() 的简短而强大的版本:

    df['timediff_string'] = df['timediff'].apply(
        lambda x: f'{x.components.hours:02d}:{x.components.minutes:02d}:{x.components.seconds:02d}'
                  if not pd.isnull(x) else ''
    )
    

    这利用了 pandas Timedelta 对象的 components 属性,并且还处理空值 (NaT)。

    如果timediff列不包含pandas Timedelta对象,可以转换:

    df['timediff'] = pd.to_timedelta(df['timediff'])
    

    【讨论】:

      【解决方案3】:

      datetime.timedelta 已经按照您想要的方式进行格式化。这个问题的症结在于 Pandas 内部转换为numpy.timedelta

      import pandas as pd
      from datetime import timedelta
      
      time_1 = timedelta(days=3, seconds=3400)
      time_2 = timedelta(days=0, seconds=3400)
      print(time_1)
      print(time_2)
      
      times = pd.Series([time_1, time_2])
      
      # Times are converted to Numpy timedeltas.
      print(times)
      
      # Convert to string after converting to datetime.timedelta.
      times = times.apply(
          lambda numpy_td: str(timedelta(seconds=numpy_td.total_seconds())))
      
      print(times)
      

      因此,在打印之前先转换为datetime.timedelta,然后再转换为str(以防止转换回numpy.timedelta)。

      3 days, 0:56:40
      0:56:400
      
      0   3 days 00:56:40
      1   0 days 00:56:40
      dtype: timedelta64[ns]
      
      0    3 days, 0:56:40
      1            0:56:40
      dtype: object
      

      我来这里是为了寻找同一个问题的答案,所以我觉得我应该进一步澄清。 :)

      【讨论】:

        【解决方案4】:

        鉴于 OP 可以使用对象列(有点冗长):

        def splitter(td):
        
          td = str(td).split(' ')[-1:][0]
        
          return td
        
        
        df['split'] = df['timediff'].apply(splitter)
        

        基本上,我们采用 timedelta 列,将内容转换为字符串,然后拆分字符串(创建一个列表)并取出该列表的最后一项,即 hh:mm:ss 组件。

        请注意,在这里指定 ' ' 分割的内容是多余的。

        另一种衬里:

        df['split2'] = df['timediff'].astype('str').str.split().str[-1]
        

        这是非常相似,但不是很漂亮恕我直言。此外,输出包括毫秒,这不是第一个解决方案中的情况。我不确定这是什么原因(如果你这样做,请发表评论)。如果您的数据很大,可能值得对这些不同的方法进行计时。

        【讨论】:

        • 谢谢!我认为一旦将类型转换为 str,那么使用 split 一切都相对容易。
        【解决方案5】:

        您可以将其转换为Python timedelta,然后转换为str,最后转换为Series

        pd.Series(df["duration"].dt.to_pytimedelta().astype(str), name="start_time")
        

        【讨论】:

        • 我试过这个,但我得到 AttributeError: 'Timedelta' object has no attribute 'dt'。这个答案是最新的吗?
        • 好像你的df["duration"] 对象不是pd.Series 而是Timedelta?如果是pd.Series,它应该有dtpandas.pydata.org/docs/reference/api/…
        【解决方案6】:

        如果你想删除所有非零组件(不仅仅是天),你可以这样做:

        
        def pd_td_fmt(td):
            import pandas as pd
            abbr = {'days': 'd', 'hours': 'h', 'minutes': 'min', 'seconds': 's', 'milliseconds': 'ms', 'microseconds': 'us',
                'nanoseconds': 'ns'}
        
            fmt = lambda td:"".join(f"{v}{abbr[k]}" for k, v in td.components._asdict().items() if v != 0)
            if isinstance(td, pd.Timedelta):
                return fmt(td)
            elif isinstance(td,pd.TimedeltaIndex):
                return td.map(fmt)
            else:
                raise ValueError
        

        【讨论】:

          【解决方案7】:

          如果您可以确定您的 timedelta 小于一天,这可能会起作用。为了在尽可能少的行中做到这一点,我 convert the timedelta to a datetime 通过添加 unix epoch 0 然后使用 now-datetime dt function 来格式化日期格式。

          df['duration1'] = (df['duration'] + pd.to_datetime(0)).dt.strftime('%M:%S')
          

          【讨论】:

            猜你喜欢
            • 2017-02-24
            • 1970-01-01
            • 2019-05-01
            • 2022-01-21
            • 1970-01-01
            • 1970-01-01
            • 2021-09-07
            相关资源
            最近更新 更多