Thêm cột có số ngày giữa các ngày trong gấu trúc DataFrame


101

Tôi muốn trừ các ngày trong 'A' khỏi các ngày trong 'B' và thêm một cột mới với số chênh lệch.

df
          A        B
one 2014-01-01  2014-02-28 
two 2014-02-03  2014-03-01

Tôi đã thử cách sau, nhưng gặp lỗi khi tôi cố gắng đưa điều này vào vòng lặp for ...

import datetime
date1=df['A'][0]
date2=df['B'][0]
mdate1 = datetime.datetime.strptime(date1, "%Y-%m-%d").date()
rdate1 = datetime.datetime.strptime(date2, "%Y-%m-%d").date()
delta =  (mdate1 - rdate1).days
print delta

Tôi nên làm gì?

Câu trả lời:


100

Giả sử đây là các cột ngày giờ (nếu chúng không áp dụng to_datetime), bạn chỉ có thể trừ chúng đi:

df['A'] = pd.to_datetime(df['A'])
df['B'] = pd.to_datetime(df['B'])

In [11]: df.dtypes  # if already datetime64 you don't need to use to_datetime
Out[11]:
A    datetime64[ns]
B    datetime64[ns]
dtype: object

In [12]: df['A'] - df['B']
Out[12]:
one   -58 days
two   -26 days
dtype: timedelta64[ns]

In [13]: df['C'] = df['A'] - df['B']

In [14]: df
Out[14]:
             A          B        C
one 2014-01-01 2014-02-28 -58 days
two 2014-02-03 2014-03-01 -26 days

Lưu ý: đảm bảo bạn đang sử dụng gấu trúc mới (ví dụ: 0.13.1), điều này có thể không hoạt động trong các phiên bản cũ hơn.


24
Chúng ta có thể loại bỏ phần "ngày" trong kết quả trong trường hợp chúng ta chỉ cần xem giá trị số tức là. -58, -26 trong trường hợp này.
0nir

6
để mở rộng nhận xét @AndyHayden, điều đó hoạt động nhưng nó phải pd.offsets.Day(1)(với 's'). Tôi cũng thường phủ nhận nó, vì vậy bạn sẽ có được(df['A'] - df['B']) / pd.offsets.Day(-1)
dirkjot

12
Tuy nhiên, nếu bạn muốn làm điều này trên toàn bộ Series, bạn cần có (df['A'] - df['B']) / np.timedelta64(-1, 'D')những lý do mà tôi không hiểu hết.
dirkjot

@dirkjot Cảm ơn bạn đã phát hiện lỗi đánh máy! IIRC điều này đã được sửa chữa trong những con gấu trúc gần đây, bạn có đang sử dụng 0.16.2 / 0.17 không?
Andy Hayden

2
@webelo bản thân DatetimeIndex / Series phải có một .dt.daysthuộc tính nên được ưu tiên hơn.
Andy Hayden

109

Để xóa phần tử văn bản 'ngày', bạn cũng có thể sử dụng trình truy cập dt () cho chuỗi: https://pandas.pydata.org/pandas-docs/stable/generated/pandas.Series.dt.html

Vì thế,

df[['A','B']] = df[['A','B']].apply(pd.to_datetime) #if conversion required
df['C'] = (df['B'] - df['A']).dt.days

trả về:

             A          B   C
one 2014-01-01 2014-02-28  58
two 2014-02-03 2014-03-01  26

3
Câu trả lời chính xác. Trong trường hợp của tôi, df['C'] = (df['B'] - df['A']).dt.dayskhông hoạt động và tôi phải sử dụng df['C'] = (df['B'] - df['A']).days. Bất kỳ ý tưởng tại sao tôi không đưa ra số ngày như mong đợi?
Samuel Nde

Nde - chính xác thì nó không hoạt động như thế nào? Lỗi hoặc các giá trị sai? Bạn đã chuyển đổi cả hai cột A và B thành ngày giờ thành công chưa?
Ricky McMaster

1
Cả hai cột của tôi đều là ngày giờ (hay datetime64[ns]nói chính xác là). Khi tôi làm vậy df['C'] = (df['B'] - df['A']).dt.days, tôi gặp lỗi thuộc tính cho biết AttributeError: đối tượng 'Timedelta' không có thuộc tính 'dt' , vì vậy tôi đã thử df ['C'] = (df ['B'] - df ['A']). ngày mà đã cho tôi câu trả lời mong muốn. (Tất nhiên tôi đang sử dụng dataframe của riêng tôi không phải là người trong ví dụ trên Hoặc nó có thể là vì tôi cũng có thời gian trong ngày của tôi chứ không phải là trong. 2018-09-24 10:17:18.800277)
Samuel NDE

1
câu trả lời hoàn hảo.
user3065757 11/09/19

1
Giải pháp tuyệt vời. Cảm ơn!
Rodrigo Hjort

11

Hiểu danh sách là cách tốt nhất của bạn cho cách Pythonic (và nhanh nhất) để làm điều này:

[int(i.days) for i in (df.B - df.A)]
  1. tôi sẽ trả lại đồng hồ hẹn giờ (ví dụ: '-58 ngày')
  2. i.days sẽ trả về giá trị này dưới dạng giá trị số nguyên dài (ví dụ -58L)
  3. int (i.days) sẽ cung cấp cho bạn -58 mà bạn tìm kiếm.

Nếu các cột của bạn không ở định dạng ngày giờ. Cú pháp ngắn hơn sẽ là:df.A = pd.to_datetime(df.A)


1

Còn cái này thì sao:

times['days_since'] = max(list(df.index.values))  
times['days_since'] = times['days_since'] - times['months']  
times
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.