Zachowaj tylko datę podczas korzystania z pandas.to_datetime

201

Używam pandas.to_datetimedo analizowania dat w moich danych. Pandy domyślnie reprezentują daty, datetime64[ns]mimo że wszystkie są tylko codziennie. Zastanawiam się, czy istnieje elegancki / sprytny sposób na konwersję dat, datetime.dateczy też datetime64[D]tak, że kiedy piszę dane do CSV, daty nie są dołączane 00:00:00. Wiem, że mogę ręcznie przekonwertować typ element po elemencie:

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

Ale to jest naprawdę wolne, ponieważ mam wiele wierszy i to w pewnym sensie nie pozwala na użycie pandas.to_datetime. Czy istnieje sposób na konwersję dtypecałej kolumny jednocześnie? Czy też pandas.to_datetimeobsługuje precyzyjne specyfikacje, dzięki którym mogę pozbyć się części czasu podczas pracy z codziennymi danymi?

jpp
źródło
2
Nie znam dobrego sposobu, ale df.dates.apply(lambda x: x.date()) powinienem być co najmniej trochę szybszy. spójrz także na github.com/pydata/pandas/issues/2583
root
1
Te dwa pytania uznałbym za różne. Możliwy duplikat, do którego się odwołujesz, ma na celu podzielenie części daty i części godziny z kolumny daty i godziny. To pytanie jest motywowane przez konwersję całej kolumny na raz. Wyobraź sobie, że masz ramkę danych z 20 kolumnami reprezentującymi daty. Nie chciałbyś określać, które kolumny pisać do csv, jak sugerowano w drugim pytaniu.
1
Obecnie nie jest to obsługiwane (@root wskazuje na możliwe ulepszenie), jaki jest cel tego, pisząc do csv?
Jeff
3
Cóż, często musimy zapisywać dane w plikach csv, aby mogły je odczytać inne programy. Nadmiarowa 00:00:00 sprawia, że ​​ogólnie trudniej jest ją przetwarzać, szczególnie gdy pracuję z danymi wyłącznie codziennymi.

Odpowiedzi:

285

Od wersji 0.15.0można to teraz łatwo zrobić za pomocą .dtdostępu do komponentu daty:

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

Powyższe zwraca datetime.datetyp dtype, jeśli chcesz go mieć datetime64, możesz tylko normalizekomponent czasu do północy, aby ustawić wszystkie wartości na 00:00:00:

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

To zachowuje typ, datetime64ale wyświetlacz pokazuje tylko datewartość.

EdChum
źródło
33

Proste rozwiązanie:

df['date_only'] = df['date_time_column'].dt.date
Gil Baggio
źródło
Tylko ostrzeżenie, to zmienia typ na obiekt. Aby zachować spójność, trzeba by astype („datetime64”).
misantroop
25

Chociaż głosowałem za odpowiedzią EdChum, która jest najbardziej bezpośrednią odpowiedzią na postawione przez OP pytanie, to tak naprawdę nie rozwiązuje problemu wydajności (nadal opiera się na datetimeobiektach python , a zatem wszelkie operacje na nich nie będą wektoryzowane - to znaczy będzie wolny).

Lepszą skutecznością jest użycie df['dates'].dt.floor('d'). Ściśle mówiąc, nie „zachowuje tylko daty”, ponieważ po prostu ustawia czas 00:00:00. Ale działa zgodnie z oczekiwaniami PO, gdy na przykład:

  • drukowanie na ekran
  • zapisywanie do csv
  • za pomocą kolumny do groupby

... i jest znacznie wydajniejszy, ponieważ operacja jest wektoryzowana.

EDIT: w rzeczywistości, odpowiedź PO byłaby korzystna jest prawdopodobnie „Nowsze wersje pandasmają nie napisać czasu do CSV, jeśli jest 00:00:00dla wszystkich obserwacji”.

Pietro Battiston
źródło
Niestety to_jsonnadal pisze pełny 00:00:00.
IanS
@IanS masz na myśli, kiedy używasz date_format='iso'? Domyślnie wyświetla tylko sekundy od epoki.
Pietro Battiston
Tak właśnie miałem na myśli.
IanS
Jest to szybsze niż dt.normalize()w seriach dłuższych niż kilkaset elementów.
C8H10N4O2
16

Pandy DatetimeIndexi Serieswywołać metodę, normalizektóra robi dokładnie to, co chcesz.

Możesz przeczytać więcej na ten temat w tej odpowiedzi .

Może być używany jako ser.dt.normalize()

j08lue
źródło
15

Pandas v0.13 +: Użyj to_csvz date_formatparametrem

W miarę możliwości unikaj przekształcania datetime64[ns]serii w objectserię datetime.dateobiektów typu dtype . Ten ostatni, często skonstruowany przy użyciu pd.Series.dt.date, jest przechowywany jako tablica wskaźników i jest nieefektywny w stosunku do serii opartej wyłącznie na NumPy.

Ponieważ Twoja obawa dotyczy formatu podczas pisania do pliku CSV , wystarczy użyć date_formatparametru to_csv. Na przykład:

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

Zobacz dyrektywy Pythona strftimedotyczące konwencji formatowania.

jpp
źródło
8

Jest to prosty sposób na wyodrębnienie daty:

import pandas as pd

d='2015-01-08 22:44:09' 
date=pd.to_datetime(d).date()
print(date)
Mani Abi Anand
źródło
OP używa już metody .date () w swoim pytaniu, więc to rozwiązanie nie odpowiada na ich pytanie, ale uznałem za użyteczny prosty przykład użycia metody date () jako odniesienia.
Nic Scozzaro
5

Konwertowanie na datetime64[D]:

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

Chociaż ponowne przypisanie tego do kolumny DataFrame spowoduje przywrócenie go z powrotem do [ns].

Jeśli chcesz faktycznie 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)])
Dale Jung
źródło
3
Jeśli używasz astype („M8 [D]”), przekształca brakujące wartości w datę początkową, 1970-1-1. Prawdopodobnie lepiej jest teraz po prostu używać pandas.to_datetime ().
Stewbaca,
1
Uwaga dla każdego, kto rutynowo dtdołącza moduł datetime, ponieważ ten fragment odpowiedzi zastąpi ten moduł! @ Dale-Jung, być może może zmienić linię na coś takiego jak dt_index
yeliabsalohcin
Znajduję również problem, w którym przy następnej próbie dodania nowego wiersza za pomocą df.loc[date]metody indeks wraca do znacznika czasu, co oznacza, że ​​kolejne porównania już nie działają
yeliabsalohcin
3

Po prostu udzielam bardziej aktualnej odpowiedzi na wypadek, gdyby ktoś zobaczył ten stary post.

Dodanie „utc = False” podczas konwersji na datetime spowoduje usunięcie komponentu strefy czasowej i zachowanie tylko daty w typie danych datetime64 [ns].

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

Będzie można go zapisać w programie Excel bez wyświetlania błędu „Błąd wartości: program Excel nie obsługuje czasów danych w strefach czasowych. Przed zapisaniem w programie Excel upewnij się, że czasy danych nie są znane.

wprowadź opis zdjęcia tutaj

Katekarin
źródło
To z jakiegoś powodu kończy się niepowodzeniem po zastosowaniu dowolnej funkcji agregującej w kolumnie.
RaphX
0

Chciałem móc zmienić typ zestawu kolumn w ramce danych, a następnie usunąć czas, utrzymując dzień. round (), floor (), ceil () wszystkie prace

df[date_columns] = df[date_columns].apply(pd.to_datetime)
df[date_columns] = df[date_columns].apply(lambda t: t.dt.floor('d'))
Climbs_lika_Spyder
źródło