Chỉ giữ lại một phần ngày khi sử dụng pandas.to_datetime


201

Tôi sử dụng pandas.to_datetimeđể phân tích ngày tháng trong dữ liệu của tôi. Gấu trúc theo mặc định đại diện cho ngày datetime64[ns]mặc dù ngày chỉ là tất cả hàng ngày. Tôi tự hỏi liệu có một cách thanh lịch / thông minh để chuyển đổi ngày thành datetime.datehay datetime64[D]không, khi tôi viết dữ liệu sang CSV, ngày không được thêm vào 00:00:00. Tôi biết tôi có thể chuyển đổi loại thủ công từng yếu tố:

[dt.to_datetime().date() for dt in df.dates]

Nhưng điều này thực sự chậm vì tôi có nhiều hàng và nó đánh bại mục đích sử dụng pandas.to_datetime. Có cách nào để chuyển đổi dtypetoàn bộ cột cùng một lúc không? Hoặc cách khác, có pandas.to_datetimehỗ trợ một đặc điểm kỹ thuật chính xác để tôi có thể thoát khỏi phần thời gian trong khi làm việc với dữ liệu hàng ngày không?


2
Tôi không biết một cách hay, nhưng df.dates.apply(lambda x: x.date()) nên nhanh hơn một chút. cũng hãy xem github.com/pydata/pandas/issues/2583
root


1
Tôi sẽ coi hai câu hỏi này là khác nhau. Bản sao có thể có mà bạn đề cập nhằm mục đích tách phần ngày và phần thời gian khỏi cột thời gian. Câu hỏi này được thúc đẩy bằng cách chuyển đổi toàn bộ cột cùng một lúc. Hãy tưởng tượng bạn có một khung dữ liệu với 20 cột biểu thị ngày. Bạn sẽ không muốn chỉ định cột nào sẽ ghi vào csv, như được đề xuất trong câu hỏi khác.

1
Điều này không được hỗ trợ tại thời điểm này (@root chỉ ra sự tăng cường có thể), mục đích của việc này là gì, khi viết thư cho csv?
Jeff

3
Chà, thường thì chúng ta phải ghi dữ liệu vào các tệp csv để được các chương trình khác đọc. 00:00:00 dự phòng chỉ khiến việc xử lý nói chung khó khăn hơn, đặc biệt là khi tôi đang làm việc với dữ liệu hoàn toàn hàng ngày.

Câu trả lời:


286

Vì phiên bản 0.15.0này có thể dễ dàng thực hiện bằng cách sử dụng .dtđể chỉ truy cập thành phần ngày:

df['just_date'] = df['dates'].dt.date

Ở trên trả về một datetime.datedtype, nếu bạn muốn có datetime64thì bạn chỉ có thể normalizethành phần thời gian thành nửa đêm để nó đặt tất cả các giá trị thành 00:00:00:

df['normalised_date'] = df['dates'].dt.normalize()

Điều này giữ cho dtype như datetime64nhưng màn hình chỉ hiển thị dategiá trị.


33

Giải pháp đơn giản:

df['date_only'] = df['date_time_column'].dt.date

Chỉ cần một cảnh báo, điều này thay đổi loại thành đối tượng. Vì vậy, bạn cần phải gõ astype ('datetime64') để giữ tính nhất quán.
misantroop

25

Trong khi tôi nêu lên câu trả lời của EdChum, đây là câu trả lời trực tiếp nhất cho câu hỏi mà OP đặt ra, nó không thực sự giải quyết được vấn đề về hiệu năng (nó vẫn phụ thuộc vào datetimecác đối tượng python và do đó, mọi thao tác trên chúng sẽ không được vector hóa - đó là sẽ chậm).

Một sự thay thế hiệu quả tốt hơn là sử dụng df['dates'].dt.floor('d'). Nói đúng ra, nó không "chỉ giữ một phần ngày", vì nó chỉ đặt thời gian 00:00:00. Nhưng nó hoạt động như mong muốn của OP khi, ví dụ:

  • in ra màn hình
  • lưu vào csv
  • sử dụng cột để groupby

... Và nó hiệu quả hơn nhiều, vì hoạt động được vector hóa.

EDIT: trên thực tế, câu trả lời của OP có vẻ rất muốn có lẽ là "phiên bản gần đây của pandasta không ghi thời gian để csv nếu nó là 00:00:00cho tất cả các quan sát".


Thật không may to_jsonvẫn viết đầy đủ 00:00:00.
IanS

@IanS có nghĩa là khi sử dụng date_format='iso'?! Theo mặc định, nó chỉ xuất ra vài giây kể từ epoch.
Pietro Battiston

Vâng, đó là những gì tôi muốn nói.
IanS

Điều này nhanh hơn dt.normalize()trên loạt dài hơn vài trăm yếu tố.
C8H10N4O2

16

Gấu trúc DatetimeIndexSeriescó một phương pháp gọi normalizeđó là chính xác những gì bạn muốn.

Bạn có thể đọc thêm về nó trong câu trả lời này .

Nó có thể được sử dụng như ser.dt.normalize()


15

Pandas v0.13 +: Sử dụng to_csvvới date_formattham số

Tránh, nếu có thể, chuyển đổi datetime64[ns]chuỗi của bạn thành một objectloạt các datetime.dateđối tượng dtype . Sau này, thường được xây dựng bằng cách sử dụngpd.Series.dt.date , được lưu trữ dưới dạng một mảng các con trỏ và không hiệu quả so với một chuỗi dựa trên NumPy thuần túy.

Vì mối quan tâm của bạn là định dạng khi ghi vào CSV , chỉ cần sử dụng date_formattham số của to_csv. Ví dụ:

df.to_csv(filename, date_format='%Y-%m-%d')

Xem các strftimechỉ thị của Python để biết các quy ước định dạng.


8

Đây là một cách đơn giản để trích xuất ngày:

import pandas as pd

d='2015-01-08 22:44:09' 
date=pd.to_datetime(d).date()
print(date)

OP đã sử dụng phương thức .date () trong câu hỏi của họ, vì vậy giải pháp này không trả lời câu hỏi của họ, nhưng tôi thấy hữu ích khi xem một ví dụ đơn giản về việc sử dụng phương thức date () làm tham chiếu.
Nic Scozzaro

5

Chuyển đổi sang datetime64[D]:

df.dates.values.astype('M8[D]')

Mặc dù việc gán lại nó cho một DataFrame col sẽ hoàn nguyên nó trở lại [ns].

Nếu bạn muốn thực tế datetime.date:

dt = pd.DatetimeIndex(df.dates)
dates = np.array([datetime.date(*date_tuple) for date_tuple in zip(dt.year, dt.month, dt.day)])

3
Nếu bạn đang sử dụng astype ('M8 [D]'), nó sẽ chuyển đổi các giá trị bị thiếu thành ngày gốc, 1970-1-1. Có lẽ tốt hơn là chỉ sử dụng pandas.to_datetime () ngày nay.
Stewbaca

1
Lưu ý cho bất cứ ai thường xuyên bao gồm mô-đun datetime như dt , snipet câu trả lời này sẽ ghi đè lên mô-đun đó! @ Dale-Jung, có lẽ có thể thay đổi dòng thành một cái gì đó như dt_index
yeliabsalohcin

Tôi cũng đang tìm thấy một vấn đề trong đó lần tới khi tôi thử và thêm một hàng mới thông qua df.loc[date]phương thức, chỉ mục sẽ quay trở lại dấu thời gian, nghĩa là các so sánh tiếp theo không còn hoạt động nữa
yeliabsalohcin

3

Chỉ cần đưa ra một câu trả lời cập nhật hơn trong trường hợp ai đó nhìn thấy bài viết cũ này.

Thêm "utc = Sai" khi chuyển đổi sang datetime sẽ xóa thành phần múi giờ và chỉ giữ lại ngày trong kiểu dữ liệu datetime64 [ns].

pd.to_datetime(df['Date'], utc=False)

Bạn sẽ có thể lưu nó trong excel mà không gặp lỗi "ValueError: Excel không hỗ trợ datetimes với múi giờ. Vui lòng đảm bảo rằng datetimes là múi giờ không biết trước khi ghi vào Excel."

nhập mô tả hình ảnh ở đây


Điều này vì một số lý do không thành công sau khi bạn áp dụng bất kỳ hàm tổng hợp nào với cột.
RaphX

0

Tôi muốn có thể thay đổi loại cho một tập hợp các cột trong khung dữ liệu và sau đó loại bỏ thời gian giữ ngày. vòng (), sàn (), trần () tất cả công việc

df[date_columns] = df[date_columns].apply(pd.to_datetime)
df[date_columns] = df[date_columns].apply(lambda t: t.dt.floor('d'))
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.