W podobnym żyle do tego Zapytanie, mam numpy.timedelta64 Kolumna w dataframe Pandas. Zgodnie z tym Odpowiedź do wspomnianego pytania, istnieje funkcja pandas.tslib.repr_timedelta64, która ładnie wyświetla czasową w dni, Godziny: minuty: sekundy. Chciałbym sformatować je tylko w dniach i godzinach.

Więc co mam, to:

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)

Co dostaje mi pożądane wyjście, ale zastanawiałem się, czy istnieje funkcja w numpy lub pandas Podobna do datetime.strftime, która może formatować numpy.timedelta64 zgodnie z odpowiednim ciągiem formatu?


Próbowałem dalej dostosować rozwiązanie Jeffa, ale jest to wolniej niż moja odpowiedź. Oto:

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'
6
Midnighter 15 sierpień 2014, 15:38

4 odpowiedzi

Najlepsza odpowiedź

Podczas gdy odpowiedzi dostarczane przez @SEBIX i @JEFF pokazują ładny sposób na konwersję Timedeltas do dni i godzin, a @ Rozwiązanie Jeffa w szczególności zachowuje indeks Series ", brakowało im w elastyczności ostatecznego formatowania ciągu . Rozwiązaniem, którego teraz używam:

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)]

Który dobrze mi odpowiada i wrócę do indeksu, wkładając tę listę w oryginalny DataFrame.

4
Midnighter 15 sierpień 2014, 13:35

Oto jak to zrobić w sposób wektorowy.

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

Jeśli chcesz dokładnie tak, jak OP pozowano:

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
1
Jeff 15 sierpień 2014, 13:34

@ Odpowiedź Midnightera nie działa dla mnie w Pythonie 3, więc oto moja zaktualizowana funkcja:

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"

Zasadniczo taki sam, ale z F-Struns i więcej przymusu typu.

1
Seanny123 12 październik 2018, 21:38

Nie wiem, jak to się robi w pandy, ale oto moje numpy-tylko podejście do twojego problemu:

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)

Więc po prostu konwertuję surowe dane do żądanego typu wyjścia (pozwól, aby numpy zrobi), a następnie mamy dwie tablice z danymi i są bezpłatne, aby używać, jak chcemy. Aby grupować je parami, po prostu zrobić:

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

Na przykład:

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

Daje:

2d 7h
2d 2h
4d 15h
2d 4h
0
sebix 15 sierpień 2014, 13:14