Cara mengubah format datetime di panda

109

Dataframe saya memiliki DOBkolom (format contoh 1/1/2016) yang secara default diubah menjadi 'object' pandas dtype:DOB object

Konversi ini untuk format tanggal dengan df['DOB'] = pd.to_datetime(df['DOB']), tanggal akan dikonversi menjadi: 2016-01-26dan yang dtypeadalah: DOB datetime64[ns].

Sekarang saya ingin mengubah format tanggal ini ke 01/26/2016atau dalam format tanggal umum lainnya. Bagaimana saya melakukannya?

Apapun metode yang saya coba, selalu menunjukkan tanggal dalam 2016-01-26format.

yome
sumber
Apakah Anda mencari solusi yang hanya berfungsi di bawah notebook Jupyter? (dalam hal ini gunakan 'styler' per kolom) atau berfungsi di konsol Python biasa dan iPython?
smci

Jawaban:

209

Anda dapat menggunakan dt.strftimejika Anda perlu mengonversi datetimeke format lain (tetapi perhatikan bahwa dtypekolom akan menjadi 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
jezrael
sumber
32
'strftime' mengubah kolom datetime menjadi unicode untuk menerapkan operasi pada DOB1, kita harus mengubahnya lagi menjadi datetime. Apakah tidak ada cara lain untuk memformat tanpa kehilangan data_type?
M. Zaman
@ Jezrael, apakah ada solusi yang lebih baik yang juga mempertahankan tipe data dan tidak mengembalikan tanggal ke kolom objek? Masalahnya adalah jika mencoba mengubahnya setelah baris 'df [' DOB1 '] = df [' DOB ']. Dt.strftime ('% m /% d /% Y ')' seperti yang disarankan pada solusi di atas maka tanggal kembali ke format aslinya.
Diasingkan
haha, jadi bagaimana saya bisa melakukan ini jika saya ingin menggunakan kolom ini untuk kolom .mergepada tanggal waktu dari kerangka data lain? Apakah masuk akal untuk mengonversi kolom datetime lainnya ke kolom objek untuk melakukan .merge?
Diasingkan
Ya, tampaknya saya setuju tetapi dengan "Tidak ada :(" Anda mengatakan kepada saya bahwa saya tidak dapat mengonversi kolom ke tanggal waktu setelah mengubah formatnya tanpa kehilangan format barunya. Jadi?
Ditampilkan
Ok, sejauh yang saya pahami, .mergemasih bisa dilakukan dengan benar jika kedua kolom tersebut adalah kolom datetimes meskipun tidak memiliki format yang sama persis. Apakah ini benar?
Diasingkan
21

Mengubah format tetapi tidak mengubah jenis:

df['date'] = pd.to_datetime(df["date"].dt.strftime('%Y-%m'))
Yanni Cao
sumber
ingat saja bahwa df ["date"] harus datetime64 sebelum Anda melakukan ini
adhg
4
Tidak! Misalkan nilai asli beberapa item di datekolom adalah “ 26 November 2019”. strftime()berarti "string dari waktu" , jadi df["date"].dt.strftime('%Y-%m')akan menjadi string "2019-11" untuk item itu. Kemudian, pd.to_datetime()akan mengonversi string ini kembali ke datetime64format, tetapi sekarang menjadi " 1 November 2019"! Hasilnya adalah: Tidak ada perubahan format, tapi perubahan nilai tanggal itu sendiri!
MarianD
2
@ MarianD: semua komentar Anda pada setiap jawaban berguna, tetapi bisakah Anda meringkasnya dalam satu rollup "Kesulitan / Jangan lakukan ini" di bagian bawah jawaban Anda? Anda juga perlu menyatakan dengan jelas apa masalah dengan masing-masing ini: jika salah satu tanggal input tidak dalam format yang diharapkan, ini akan berisiko menimbulkan pengecualian, atau merusak tanggal. Cukup menulis "Tidak!" di mana-mana tidak menyampaikan itu.
smci
8

Kode di bawah ini berfungsi untuk saya daripada yang sebelumnya - cobalah!

df['DOB']=pd.to_datetime(df['DOB'].astype(str), format='%m/%d/%Y')
resi jain
sumber
2
Tidak! format='%m/%d/%Y'Parameter Anda adalah untuk mem - parsing string, yaitu Anda diharapkan menyediakan string dalam format seperti itu (misalnya "5/13/2019"). Tidak lebih, tidak ada perubahan format. Ini akan tetap ditampilkan sebagai 2019-05-13- atau akan memunculkan pengecualian, jika df['DOB'].astype(str)berisi item tidak dalam format seperti itu, misalnya dalam format "2019-05-13".
MarianD
4

Dibandingkan dengan jawaban pertama, saya akan merekomendasikan untuk menggunakan dt.strftime () terlebih dahulu, lalu pd.to_datetime (). Dengan cara ini, ini masih akan menghasilkan tipe data datetime.

Sebagai contoh,

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)
pengguna3512680
sumber
2
Ini tidak berhasil setidaknya dalam kasus saya. Secara khusus, kolom dikonversi ke tipe data waktu dan nilai juga akan dikonversi ke format asli!
Diasingkan
Tidak! Kesalahan sintaks (tanda kurung kurawal tidak ada), dalam versi saya Pandas (0.25.1) kesalahan sintaks lainnya (dt.strftime () - hanya dapat menggunakan aksesor .dt dengan nilai mirip data) - Anda bergantung pada tipe data yang melekat, tetapi dalam versi berbeda dari Jenis data yang melekat pada panda mungkin berbeda), dan logika yang aneh - mengapa mengonversi datetime menjadi string dan kemudian kembali ke datetime ? Lihat komentar saya untuk jawaban rishi jain.
MarianD
2

Ada perbedaan antara

  • yang isi dari sel dataframe (nilai biner) dan
  • nya presentasi (menampilkan itu) bagi kita, manusia.

Jadi pertanyaannya adalah: Bagaimana cara mencapai presentasi yang sesuai dari data saya tanpa mengubah data / tipe datanya sendiri?

Inilah jawabannya:

  • Jika Anda menggunakan notebook Jupyter untuk menampilkan dataframe, atau
  • jika Anda ingin mencapai presentasi dalam bentuk file HTML (bahkan dengan banyak atribut iddan berlebihan yang disiapkan classuntuk gaya CSS lebih lanjut - Anda mungkin atau tidak dapat menggunakannya),

gunakan gaya . Styling tidak mengubah data / tipe data kolom dari dataframe Anda.

Sekarang saya tunjukkan cara menjangkaunya di notebook Jupyter - untuk presentasi dalam bentuk file HTML lihat catatan di dekat akhir pertanyaan.

Saya anggap kolom Anda DOB sudah memiliki tipedatetime64 (Anda telah menunjukkan bahwa Anda tahu cara mencapainya). Saya menyiapkan kerangka data sederhana (dengan hanya satu kolom) untuk menunjukkan beberapa gaya dasar:

  • Tidak bergaya:

       df
          DOB
0  2019-07-03
1  2019-08-03
2  2019-09-03
3  2019-10-03
  • Styling itu sebagai 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
  • Styling itu sebagai 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

Hati-hati!
Objek yang dikembalikan BUKAN kerangka data - ini adalah objek kelas Styler, jadi jangan tetapkan kembali ke df:

Jangan lakukan ini:

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

(Setiap kerangka data memiliki objek Styler yang dapat diakses oleh .stylepropertinya, dan kami mengubah df.styleobjek ini , bukan kerangka data itu sendiri.)


Pertanyaan dan jawaban:

  • T: Mengapa objek Styler Anda (atau ekspresi yang mengembalikannya) digunakan sebagai perintah terakhir di sel notebook Jupyter menampilkan tabel (bergaya) Anda , dan bukan objek Styler itu sendiri?

  • J: Karena setiap objek Styler memiliki metode callback ._repr_html_()yang mengembalikan kode HTML untuk merender dataframe Anda (sebagai tabel HTML yang bagus).

    Jupyter Notebook IDE memanggil metode ini secara otomatis untuk merender objek yang memilikinya.


catatan:

Anda tidak memerlukan notebook Jupyter untuk penggayaan (yaitu untuk menghasilkan dataframe yang bagus tanpa mengubah tipe data / datanya ).

Objek Styler juga memiliki metode render(), jika Anda ingin mendapatkan string dengan kode HTML (misalnya untuk menerbitkan kerangka data Anda yang telah diformat ke Web, atau cukup menyajikan tabel Anda dalam format HTML):

df_styler = df.style.format({"DOB": lambda t: t.strftime("%m/%d/%Y")})
HTML_string = df_styler.render()
MarianD
sumber
Perlu ditunjukkan bahwa kode styler seperti ini dimaksudkan untuk dijalankan di bawah, dan hanya berlaku di bawah notebook Jupyter, dan sama sekali tidak berpengaruh saat dijalankan di konsol atau iPython . OP tidak menentukan "di bawah Jupyter", jadi ini mungkin atau mungkin bukan solusi yang layak tergantung pada penyiapannya. Banyak kode sains data yang disalin dan ditempel, dan asumsi khusus Jupyter tidak ditentukan secara eksplisit, lalu orang bertanya-tanya mengapa kode penata "tidak berfungsi" saat dijalankan di lingkungan (konsol) mereka.
smci
@smci, bukankah disebutkan secara eksplisit di paragraf kedua jawaban saya? Dalam bentuk kondisional if, pernyataan yang begitu dikenal oleh setiap programmer? - Terlepas dari itu terima kasih atas komentar Anda, mungkin berguna bagi sebagian orang.
MarianD
tidak, itu sangat tidak jelas, juga dimakamkan. Pertanyaan asli seharusnya tidak ada apa-apa tentang Jupyter, dan OP dan beberapa pengguna bahkan mungkin tidak memiliki Jupyter yang tersedia untuk mereka. Jawaban Anda perlu menuliskan dalam cetak tebal baris pertamanya "Pendekatan (gaya) berikut hanya berfungsi di bawah notebook Jupyter, dan tidak akan berpengaruh apa pun saat dijalankan di luar notebook Jupyter" . (Di blog dan situs ilmu data, saya melihat setiap hari orang memposting kode Jupyter ke lingkungan non-Jupyter, dan bertanya-tanya mengapa kode itu tidak berfungsi).
smci
Keren. Saya juga menyarankan Anda menambahkan semua (banyak) jebakan yang Anda identifikasi pada pendekatan "convert-to-string-with-strftime-then-back-again-with-pd.to_datetime" lainnya. Setidaknya, perlu menyebutkan pengecualian pemeliharaan dan penangkapan. Juga, pd.to_datetime()memiliki argumen errors='raise'/'coerce'/'ignore', dayfirst, yearfirst, utc, exactuntuk mengontrol seberapa tepat dan pengecualian-senang itu, dan apakah keluaran yang tidak valid dipaksakan NaTatau apa. Apa yang membuatnya lebih rumit dalam kumpulan data "dunia nyata" adalah format campuran / hilang / tidak lengkap, waktu, zona waktu, dll; pengecualian tidak selalu berarti buruk.
smci
... atau saya bisa menulis itu sebagai rollup dari perangkap dalam pendekatan non-Jupyter.
smci
1

Kode di bawah ini berubah menjadi tipe 'datetime' dan juga format dalam string format yang diberikan. Bekerja dengan baik!

df['DOB']=pd.to_datetime(df['DOB'].dt.strftime('%m/%d/%Y'))
San
sumber
2
ubah menjadi ini:df['DOB']=pd.to_datetime(df['DOB']).dt.strftime('%m/%d/%Y')
John Doe
Tidak! - Mengapa mengonversi datetime menjadi string dan kemudian kembali ke datetime ? Lihat komentar saya untuk jawaban lain.
MarianD
1

Anda dapat mencobanya, ini akan mengubah format tanggal menjadi DD-MM-YYYY:

df['DOB'] = pd.to_datetime(df['DOB'], dayfirst = True)
Ashu007
sumber
Tidak! dayfirst=Truehanya spesifikasi urutan penguraian tanggal, misalnya string tanggal ambivalen sebagai "2-1-2019" akan diuraikan sebagai 2 Januari 2019, dan bukan sebagai 1 Februari 2019. Tidak lebih, tidak ada perubahan untuk pemformatan keluaran .
MarianD