Tính toán dữ liệu gấu trúc Chênh lệch thời gian giữa hai cột theo giờ và phút


85

Tôi có hai cột fromdatetodate, trong một khung dữ liệu.

import pandas as pd

data = {'todate': [pd.Timestamp('2014-01-24 13:03:12.050000'), pd.Timestamp('2014-01-27 11:57:18.240000'), pd.Timestamp('2014-01-23 10:07:47.660000')],
        'fromdate': [pd.Timestamp('2014-01-26 23:41:21.870000'), pd.Timestamp('2014-01-27 15:38:22.540000'), pd.Timestamp('2014-01-23 18:50:41.420000')]}

df = pd.DataFrame(data)

Tôi thêm một cột mới diff, để tìm sự khác biệt giữa hai ngày bằng cách sử dụng

df['diff'] = df['fromdate'] - df['todate']

Tôi nhận được diffcột, nhưng nó chứa days, khi có hơn 24 giờ.

                   todate                fromdate                   diff
0 2014-01-24 13:03:12.050 2014-01-26 23:41:21.870 2 days 10:38:09.820000
1 2014-01-27 11:57:18.240 2014-01-27 15:38:22.540 0 days 03:41:04.300000
2 2014-01-23 10:07:47.660 2014-01-23 18:50:41.420 0 days 08:42:53.760000

Làm cách nào để chuyển đổi kết quả của tôi thành chỉ giờ và phút (tức là ngày được chuyển đổi thành giờ)?

Câu trả lời:


123

Sự khác biệt về dấu thời gian Pandas trả về một đối tượng datetime.timedelta. Điều này có thể dễ dàng được chuyển đổi thành giờ bằng cách sử dụng phương thức * as_type *, như vậy

import pandas
df = pandas.DataFrame(columns=['to','fr','ans'])
df.to = [pandas.Timestamp('2014-01-24 13:03:12.050000'), pandas.Timestamp('2014-01-27 11:57:18.240000'), pandas.Timestamp('2014-01-23 10:07:47.660000')]
df.fr = [pandas.Timestamp('2014-01-26 23:41:21.870000'), pandas.Timestamp('2014-01-27 15:38:22.540000'), pandas.Timestamp('2014-01-23 18:50:41.420000')]
(df.fr-df.to).astype('timedelta64[h]')

đến năng suất,

0    58
1     3
2     8
dtype: float64

Giải pháp thay thế astype hoạt động, nhưng quá chậm đối với các tệp lớn (0,5 Triệu hàng). Bất cứ một đề nghị nào khác?
student1

3
đối tượng timedelta có một thuộc tính cho ngày và giây ... bạn làm, (df.fr-df.to) .dt.days * 24 + (df.fr-df.to) .dt.seconds / 3600
nitin

1
Cảm ơn bạn! Điều này cũng phù hợp với tôi khi tính toán năm (để tính tuổi): df ['age'] = (df ['later_date'] - df ['Birth_date']). Astype ('timedelta64 [Y]')
Superduper

47

Điều này đã khiến tôi lo lắng vì .astype()giải pháp trên không hiệu quả với tôi. Nhưng tôi đã tìm ra một cách khác. Chưa hẹn giờ hoặc bất cứ điều gì, nhưng có thể hiệu quả với những người khác ngoài đó:

t1 = pd.to_datetime('1/1/2015 01:00')
t2 = pd.to_datetime('1/1/2015 03:30')

print pd.Timedelta(t2 - t1).seconds / 3600.0

... nếu bạn muốn hàng giờ. Hoặc là:

print pd.Timedelta(t2 - t1).seconds / 60.0

... nếu bạn muốn vài phút.


9
Tôi đã cùng một vấn đề, nhưng với giải pháp của bạn một nhu cầu phải cẩn thận như sự khác biệt thời gian lớn hơn một ngày sẽ được bỏ qua và cần phải được đưa riêng
móng ngựa

39
I Just thấy rằng .total_seconds()hiện công việc cho những người cần nó
móng ngựa

Thật kỳ lạ (tôi nhận thấy 4 năm sau), bạn phải sử dụng parens ()cho .total_seconds()nhưng không phải.seconds
elPastor

5
import pandas as pd

# test data from OP, with values already in a datetime format
data = {'to_date': [pd.Timestamp('2014-01-24 13:03:12.050000'), pd.Timestamp('2014-01-27 11:57:18.240000'), pd.Timestamp('2014-01-23 10:07:47.660000')],
        'from_date': [pd.Timestamp('2014-01-26 23:41:21.870000'), pd.Timestamp('2014-01-27 15:38:22.540000'), pd.Timestamp('2014-01-23 18:50:41.420000')]}

# test dataframe; the columns must be in a datetime format; use pandas.to_datetime if needed
df = pd.DataFrame(data)

# add a timedelta column if wanted. It's added here for information only
# df['time_delta_with_sub'] = df.from_date.sub(df.to_date)  # also works
df['time_delta'] = (df.from_date - df.to_date)

# create a column with timedelta as total hours, as a float type
df['tot_hour_diff'] = (df.from_date - df.to_date) / pd.Timedelta(hours=1)

# create a colume with timedelta as total minutes, as a float type
df['tot_mins_diff'] = (df.from_date - df.to_date) / pd.Timedelta(minutes=1)

# display(df)
                  to_date               from_date             time_delta  tot_hour_diff  tot_mins_diff
0 2014-01-24 13:03:12.050 2014-01-26 23:41:21.870 2 days 10:38:09.820000      58.636061    3518.163667
1 2014-01-27 11:57:18.240 2014-01-27 15:38:22.540 0 days 03:41:04.300000       3.684528     221.071667
2 2014-01-23 10:07:47.660 2014-01-23 18:50:41.420 0 days 08:42:53.760000       8.714933     522.896000

Các phương pháp khác

  • Một mục ghi chú từ podcast trong Tài nguyên khác, .total_seconds()đã được thêm vào và hợp nhất khi nhà phát triển cốt lõi đang đi nghỉ và sẽ không được chấp thuận.
    • Đây cũng là lý do tại sao không có các .total_xxphương pháp khác .
# convert the entire timedelta to seconds
# this is the same as td / timedelta(seconds=1)
(df.from_date - df.to_date).dt.total_seconds()
[out]:
0    211089.82
1     13264.30
2     31373.76
dtype: float64

# get the number of days
(df.from_date - df.to_date).dt.days
[out]:
0    2
1    0
2    0
dtype: int64

# get the seconds for hours + minutes + seconds, but not days
# note the difference from total_seconds
(df.from_date - df.to_date).dt.seconds
[out]:
0    38289
1    13264
2    31373
dtype: int64

Các nguồn lực khác

%%timeit kiểm tra

import pandas as pd

# dataframe with 2M rows
data = {'to_date': [pd.Timestamp('2014-01-24 13:03:12.050000'), pd.Timestamp('2014-01-27 11:57:18.240000')], 'from_date': [pd.Timestamp('2014-01-26 23:41:21.870000'), pd.Timestamp('2014-01-27 15:38:22.540000')]}
df = pd.DataFrame(data)
df = pd.concat([df] * 1000000).reset_index(drop=True)

%%timeit
(df.from_date - df.to_date) / pd.Timedelta(hours=1)
[out]:
43.1 ms ± 1.05 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

%%timeit
(df.from_date - df.to_date).astype('timedelta64[h]')
[out]:
59.8 ms ± 1.29 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.