簡體   English   中英

熊貓數據框中的 timedelta 到字符串類型

[英]timedelta to string type in pandas dataframe

我有一個數據框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 有人可以教我如何做到這一點嗎? 非常感謝!

可以通過:

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

但解決方案並不通用,如果輸入是3 days 05:01:11它也會刪除3 days

因此,解決方案僅適用於 timedeltas 少於一天的正確時間。

更通用的解決方案是創建自定義格式

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

這是使用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'])

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

我來這里是為了尋找同一個問題的答案,所以我覺得我應該進一步澄清。 :)

鑒於 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]

這是非常相似的,但不是很漂亮恕我直言。 此外,輸出包括毫秒,這不是第一個解決方案中的情況。 我不確定這是什么原因(如果你這樣做,請發表評論)。 如果您的數據很大,那么對這些不同的方法進行計時可能是值得的。

您可以將其轉換為Python timedelta ,然后轉換為str ,最后轉換為Series

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

如果要刪除所有非零組件(不僅是天),您可以這樣做:


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

如果您可以確定您的 timedelta 小於一天,這可能會起作用。 為了在盡可能少的行中做到這一點,我通過添加 unix epoch 0將 timedelta 轉換為 datetime ,然后使用now-datetime dt 函數來格式化日期格式。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM