Cách thay đổi định dạng ngày giờ ở gấu trúc


109

Khung dữ liệu của tôi có một DOBcột (định dạng ví dụ 1/1/2016) theo mặc định được chuyển đổi thành 'đối tượng' kiểu gấu trúc:DOB object

Chuyển đổi này để định dạng ngày tháng với df['DOB'] = pd.to_datetime(df['DOB']), ngày được chuyển đổi sang: 2016-01-26và nó dtypelà: DOB datetime64[ns].

Bây giờ tôi muốn chuyển đổi định dạng ngày này sang 01/26/2016hoặc sang bất kỳ định dạng ngày chung nào khác. Tôi phải làm nó như thế nào?

Bất kể phương pháp nào tôi thử, nó luôn hiển thị ngày ở 2016-01-26định dạng.


Bạn đang tìm kiếm một giải pháp chỉ hoạt động trong sổ ghi chép Jupyter? (trong trường hợp nào sử dụng 'trình tạo kiểu' cho mỗi cột) hoặc hoạt động trong bảng điều khiển Python đơn giản và iPython?
smci

Câu trả lời:


206

Bạn có thể sử dụng dt.strftimenếu cần chuyển đổi datetimesang các định dạng khác (nhưng lưu ý rằng dtypecột sau đó sẽ là object( string)):

import pandas as pd

df = pd.DataFrame({'DOB': {0: '26/1/2016', 1: '26/1/2016'}})
print (df)
         DOB
0  26/1/2016 
1  26/1/2016

df['DOB'] = pd.to_datetime(df.DOB)
print (df)
         DOB
0 2016-01-26
1 2016-01-26

df['DOB1'] = df['DOB'].dt.strftime('%m/%d/%Y')
print (df)
         DOB        DOB1
0 2016-01-26  01/26/2016
1 2016-01-26  01/26/2016

32
'strftime' chuyển đổi cột datetime thành unicode để áp dụng thao tác trên DOB1, chúng ta lại phải chuyển đổi nó thành datetime. Không có cách định dạng nào khác mà không làm mất data_type?
M.Zaman

@jezrael, có giải pháp nào tốt hơn mà vẫn giữ lại kiểu dữ liệu và không trả lại ngày tháng cho cột đối tượng không? Vấn đề là nếu cố gắng chuyển đổi nó sau dòng 'df [' DOB1 '] = df [' DOB ']. Dt.strftime ('% m /% d /% Y ')' như nó được đề xuất ở giải pháp ở trên thì ngày trở lại định dạng ban đầu.
Outcast

haha, vậy làm cách nào để tôi có thể làm điều này nếu tôi muốn sử dụng cột này cho cột .mergengày giờ của khung dữ liệu khác? Có ý nghĩa gì không khi chuyển đổi cột ngày giờ khác thành một cột đối tượng để thực hiện .merge?
Bị ruồng bỏ

Có, rõ ràng là tôi đồng ý nhưng bởi "Không tồn tại :(" bạn đã nói với tôi rằng tôi không thể chuyển đổi cột thành datetime sau khi thay đổi định dạng của nó mà không làm mất định dạng mới của nó. Vì vậy?
Outcast

Ok, theo như tôi hiểu, .merge vẫn có thể được thực hiện chính xác nếu cả hai cột đều là cột lịch ngày ngay cả khi chúng không có cùng định dạng chính xác. Thê nay đung không?
Outcast

21

Thay đổi định dạng nhưng không thay đổi loại:

df['date'] = pd.to_datetime(df["date"].dt.strftime('%Y-%m'))

chỉ cần nhớ rằng df ["date"] phải là datetime64 trước khi bạn thực hiện việc này
adhg

4
Không! Giả sử giá trị ban đầu của một số mặt hàng trong datecột là “Ngày 26 tháng 11 năm 2019”. strftime()có nghĩa là "chuỗi từ thời gian" , vì vậy df["date"].dt.strftime('%Y-%m')sẽ là một chuỗi "2019-11" cho mục đó. Sau đó, pd.to_datetime()sẽ chuyển đổi chuỗi này trở lại với datetime64định dạng, nhưng bây giờ là “tháng 1 , 2019”! Vì vậy, kết quả sẽ là: Không thay đổi định dạng, nhưng thay đổi chính giá trị ngày!
MarianD

2
@MarianD: tất cả nhận xét của bạn về các câu trả lời riêng lẻ đều hữu ích, nhưng bạn có thể vui lòng tóm tắt chúng trong một bản tổng hợp "Cạm bẫy / Đừng làm những điều này" ở cuối câu trả lời của bạn không? Ngoài ra, bạn cần phải trình bày rõ ràng vấn đề của từng vấn đề này là gì: nếu bất kỳ ngày nào đầu vào không ở định dạng mong đợi, những ngày này sẽ có nguy cơ tạo ra ngoại lệ hoặc làm sai lệch ngày tháng. Đơn giản chỉ cần viết "Không!" mọi nơi không truyền đạt điều đó.
smci

8

Mã dưới đây phù hợp với tôi thay vì mã trước đó - hãy thử!

df['DOB']=pd.to_datetime(df['DOB'].astype(str), format='%m/%d/%Y')

2
Không! format='%m/%d/%Y'Tham số của bạn là để phân tích một chuỗi, tức là bạn phải cung cấp chuỗi ở định dạng như vậy (ví dụ "5/13/2019"). Không có gì hơn, không có thay đổi định dạng. Nó sẽ vẫn được hiển thị dưới dạng 2019-05-13- hoặc nó sẽ đưa ra một ngoại lệ, nếu df['DOB'].astype(str)chứa (các) mục không ở định dạng như vậy, ví dụ như trong một định dạng "2019-05-13".
MarianD

4

So với câu trả lời đầu tiên, tôi sẽ khuyên bạn nên sử dụng dt.strftime () trước, sau đó là pd.to_datetime (). Bằng cách này, nó vẫn sẽ dẫn đến kiểu dữ liệu ngày giờ.

Ví dụ,

import pandas as pd

df = pd.DataFrame({'DOB': {0: '26/1/2016 ', 1: '26/1/2016 '})
print(df.dtypes)

df['DOB1'] = df['DOB'].dt.strftime('%m/%d/%Y')
print(df.dtypes)

df['DOB1'] = pd.to_datetime(df['DOB1'])
print(df.dtypes)

2
Điều này không hoạt động ít nhất trong trường hợp của tôi. Cụ thể, cột được chuyển đổi thành kiểu dữ liệu datetime nhưng các giá trị cũng được chuyển đổi sang định dạng ban đầu!
Outcast

Không! Lỗi cú pháp (thiếu dấu ngoặc nhọn), trong phiên bản Pandas của tôi (0,25.1) một lỗi cú pháp khác (dt.strftime () - chỉ có thể sử dụng trình truy cập .dt với các giá trị giống ngày) - bạn dựa vào kiểu dữ liệu vốn có, nhưng trong các phiên bản khác nhau của Gấu trúc, các kiểu dữ liệu vốn có có thể khác), và một logic kỳ lạ - tại sao phải chuyển đổi datetime thành chuỗi và sau đó quay lại datetime ? Xem bình luận của tôi cho câu trả lời của rishi jain.
MarianD

2

Có sự khác biệt giữa

  • các nội dung của một tế bào dataframe (một giá trị nhị phân) và
  • sự trình bày của nó (hiển thị nó) cho chúng ta, con người.

Vì vậy, câu hỏi đặt ra là: Làm thế nào để đạt được bản trình bày thích hợp của dữ liệu của tôi mà không thay đổi dữ liệu / kiểu dữ liệu?

Đây là câu trả lời:

  • Nếu bạn sử dụng sổ ghi chép Jupyter để hiển thị khung dữ liệu của mình, hoặc
  • nếu bạn muốn tiếp cận một bài thuyết trình dưới dạng một tập tin HTML (ngay cả với nhiều chuẩn bị cần thiết idclass thuộc tính để tạo kiểu CSS hơn nữa - bạn có thể hoặc không thể sử dụng chúng),

sử dụng tạo kiểu . Việc tạo kiểu không thay đổi dữ liệu / kiểu dữ liệu của các cột trong khung dữ liệu của bạn.

Bây giờ tôi chỉ cho bạn cách tiếp cận nó trong sổ ghi chép Jupyter - đối với bản trình bày dưới dạng tệp HTML, hãy xem ghi chú ở gần cuối câu hỏi.

Tôi sẽ giả sử rằng cột của bạn DOB đã có loạidatetime64 (bạn cho thấy rằng bạn biết cách tiếp cận nó). Tôi đã chuẩn bị một khung dữ liệu đơn giản (chỉ có một cột) để hiển thị cho bạn một số kiểu cơ bản:

  • Không theo kiểu:

       df
          DOB
0  2019-07-03
1  2019-08-03
2  2019-09-03
3  2019-10-03
  • Tạo kiểu cho nó là mm/dd/yyyy:

       df.style.format({"DOB": lambda t: t.strftime("%m/%d/%Y")})
          DOB
0  07/03/2019
1  08/03/2019
2  09/03/2019
3  10/03/2019
  • Tạo kiểu cho nó là dd-mm-yyyy:

       df.style.format({"DOB": lambda t: t.strftime("%d-%m-%Y")}) 
          DOB
0  03-07-2019
1  03-08-2019
2  03-09-2019
3  03-10-2019

Hãy cẩn thận!
Đối tượng trả về KHÔNG phải là khung dữ liệu - nó là một đối tượng của lớp Styler, vì vậy đừng gán nó lại cho df:

Đừng làm điều này:

df = df.style.format({"DOB": lambda t: t.strftime("%m/%d/%Y")})    # Don´t do this!

(Mỗi khung dữ liệu đều có đối tượng Styler có thể truy cập được bằng thuộc tính của nó .stylevà chúng tôi đã thay đổi df.styleđối tượng này , không phải chính khung dữ liệu.)


Câu hỏi và trả lời:

  • H: Tại sao đối tượng Styler của bạn (hoặc một biểu thức trả lại nó) được sử dụng làm lệnh cuối cùng trong ô sổ ghi chép Jupyter hiển thị bảng (được tạo kiểu) của bạn , chứ không phải chính đối tượng Styler?

  • A: Bởi vì mọi đối tượng Styler đều có một phương thức gọi lại ._repr_html_()trả về mã HTML để hiển thị khung dữ liệu của bạn (dưới dạng một bảng HTML đẹp).

    Jupyter Notebook IDE tự động gọi phương thức này để hiển thị các đối tượng có nó.


Ghi chú:

Bạn không cần sổ ghi chép Jupyter để tạo kiểu (tức là để tạo khung dữ liệu đẹp mắt mà không thay đổi dữ liệu / kiểu dữ liệu của nó ).

Đối tượng Styler cũng có một phương thức render(), nếu bạn muốn lấy một chuỗi có mã HTML (ví dụ: để xuất bản khung dữ liệu được định dạng của bạn lên Web hoặc chỉ cần trình bày bảng của bạn ở định dạng HTML):

df_styler = df.style.format({"DOB": lambda t: t.strftime("%m/%d/%Y")})
HTML_string = df_styler.render()

Cần chỉ ra rằng mã trình tạo kiểu như thế này được thiết kế để chạy và chỉ có hiệu lực trong sổ ghi chép Jupyter và hoàn toàn không có tác dụng khi chạy trong bảng điều khiển hoặc iPython . OP không chỉ định "theo Jupyter", vì vậy đây có thể là một giải pháp khả thi hoặc không tùy thuộc vào thiết lập của họ. Rất nhiều mã khoa học dữ liệu được sao chép và dán và các giả định dành riêng cho Jupyter không được chỉ định rõ ràng, sau đó mọi người tự hỏi tại sao mã trình tạo kiểu "không hoạt động" khi chạy trong môi trường (bảng điều khiển) của chúng.
smci

@smci, không phải được đề cập rõ ràng trong đoạn thứ hai của câu trả lời của tôi? Trong các dạng điều kiện if, câu lệnh được biết đến với mọi lập trình viên? - Mặc dù vậy, cảm ơn vì nhận xét của bạn, nó có thể hữu ích cho một số người.
MarianD

không, điều đó rất không rõ ràng, cũng bị chôn vùi. Câu hỏi ban đầu cho rằng không có gì về Jupyter, OP và một số người dùng thậm chí có thể không có Jupyter cho họ. Câu trả lời của bạn sẽ cần phải in đậm dòng đầu tiên của nó "Cách tiếp cận (tạo kiểu) sau chỉ hoạt động trong sổ ghi chép Jupyter và sẽ không có tác dụng gì khi chạy bên ngoài sổ ghi chép Jupyter" . (Trong các blog và trang web về khoa học dữ liệu, tôi thấy hàng ngày mọi người đăng mã Jupyter vào các môi trường không phải Jupyter và tự hỏi tại sao nó không hoạt động).
smci

Mát mẻ. Tôi cũng khuyên bạn nên thêm tất cả (nhiều) cạm bẫy mà bạn đã xác định trên các phương pháp tiếp cận "convert-to-string-with-strftime-then-back-again-with-pd.to_datetime" khác. Ít nhất, cần phải đề cập đến ngoại lệ nuôi và bắt. Ngoài ra, pd.to_datetime()có các đối số errors='raise'/'coerce'/'ignore', dayfirst, yearfirst, utc, exactđể kiểm soát mức độ chính xác và hạnh phúc của ngoại lệ, và liệu các đầu ra không hợp lệ có bị ép buộc NaThay không. Điều làm cho nó phức tạp hơn trong bộ dữ liệu "thế giới thực" là các định dạng hỗn hợp / thiếu / không đầy đủ, thời gian, múi giờ, v.v.; ngoại lệ không nhất thiết là những điều xấu.
smci

... hoặc nếu không, tôi có thể viết điều đó như một bản tổng hợp các cạm bẫy trong các phương pháp tiếp cận không phải của Máy tính.
smci

1

Mã bên dưới thay đổi thành loại 'datetime' và cả các định dạng trong chuỗi định dạng đã cho. Hoạt động tốt!

df['DOB']=pd.to_datetime(df['DOB'].dt.strftime('%m/%d/%Y'))

2
thay đổi nó thành thế này:df['DOB']=pd.to_datetime(df['DOB']).dt.strftime('%m/%d/%Y')
John Doe

Không! - Tại sao phải chuyển đổi datetime sang chuỗi rồi quay lại datetime ? Xem bình luận của tôi cho các câu trả lời khác.
MarianD

1

Bạn có thể thử điều này, nó sẽ chuyển đổi định dạng ngày thành DD-MM-YYYY:

df['DOB'] = pd.to_datetime(df['DOB'], dayfirst = True)

Không! dayfirst=Truechỉ là thông số kỹ thuật của thứ tự phân tích cú pháp ngày, ví dụ: chuỗi ngày phổ biến là "2-1-2019" sẽ được phân tích cú pháp là ngày 2 tháng 1 năm 2019 chứ không phải ngày 1 tháng 2 năm 2019. Không có gì khác, không có thay đổi đối với định dạng đầu ra .
MarianD
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.