วิธีเปลี่ยนรูปแบบวันที่และเวลาในแพนด้า


118

ดาต้าเฟรมของฉันมีDOBคอลัมน์ (รูปแบบตัวอย่าง1/1/2016) ซึ่งโดยค่าเริ่มต้นจะถูกแปลงเป็นแพนด้า dtype 'object':DOB object

แปลงนี้เป็นรูปแบบวันที่มีdf['DOB'] = pd.to_datetime(df['DOB'])วันที่ได้รับการแปลง: 2016-01-26และเป็น:dtypeDOB datetime64[ns]

ตอนนี้ฉันต้องการแปลงรูปแบบวันที่นี้เป็น01/26/2016หรือในรูปแบบวันที่ทั่วไปอื่น ๆ ฉันต้องทำอย่างไร?

ไม่ว่าฉันจะลองใช้วิธีใดก็ตามมันจะแสดงวันที่ใน2016-01-26รูปแบบเสมอ


คุณกำลังมองหาโซลูชันที่ใช้งานได้กับสมุดบันทึก Jupyter หรือไม่? (ในกรณีนี้ใช้ 'styler' ต่อคอลัมน์) หรือทำงานในคอนโซล Python ธรรมดาและ iPython
smci

คำตอบ:


232

คุณสามารถใช้dt.strftimeหากคุณต้องการแปลงdatetimeเป็นรูปแบบอื่น (แต่โปรดทราบว่าจากนั้นdtypeของคอลัมน์จะเป็น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

34
'strftime' แปลงคอลัมน์วันที่และเวลาเป็น Unicode เพื่อใช้การดำเนินการกับ DOB1 เราต้องแปลงเป็นวันที่และเวลาอีกครั้ง ไม่มีวิธีอื่นในการจัดรูปแบบโดยไม่สูญเสีย data_type หรือ?
M.Zaman

1
@jezrael มีวิธีแก้ไขที่ดีกว่าซึ่งยังคงรักษาประเภทข้อมูลไว้และไม่ส่งคืนวันที่ไปยังคอลัมน์วัตถุหรือไม่? ปัญหาคือถ้าลองแปลงหลังจากบรรทัด 'df [' DOB1 '] = df [' DOB ']. dt.strftime ('% m /% d /% Y ')' ตามที่แนะนำไว้ที่โซลูชัน ด้านบนจากนั้นวันที่จะกลับไปเป็นรูปแบบเดิม
Outcast

ฮ่าฮ่าดังนั้นฉันจะทำสิ่งนี้ได้อย่างไรถ้าฉันต้องการใช้คอลัมน์นี้สำหรับคอลัมน์.mergeในวันที่และเวลาของดาต้าเฟรมอื่น มันสมเหตุสมผลหรือไม่ที่จะแปลงคอลัมน์วันที่และเวลาอื่นเป็นคอลัมน์วัตถุเพื่อทำสิ่งนี้.merge?
Outcast

เห็นได้ชัดว่าฉันเห็นด้วย แต่โดย "ไม่มีอยู่ :(" คุณบอกว่าฉันไม่สามารถแปลงคอลัมน์เป็นวันที่และเวลาหลังจากเปลี่ยนรูปแบบโดยไม่สูญเสียรูปแบบใหม่ดังนั้น?
Outcast

โอเคเท่าที่ฉันเข้าใจก็ยัง.mergeสามารถทำได้อย่างถูกต้องหากทั้งสองคอลัมน์เป็นคอลัมน์วันที่แม้ว่าจะไม่มีรูปแบบเดียวกันก็ตาม นี่ใช่มั้ย?
Outcast

23

การเปลี่ยนรูปแบบ แต่ไม่เปลี่ยนประเภท:

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

เพียงจำไว้ว่า df ["date"] ควรเป็น datetime64 ก่อนที่คุณจะดำเนินการนี้
adhg

5
ไม่! สมมติว่าค่าเดิมของบางรายการในdateคอลัมน์คือ " 26พฤศจิกายน2019" strftime()หมายถึง"สตริงจากเวลา"ดังนั้น df["date"].dt.strftime('%Y-%m')จะเป็นสตริง "2019-11"สำหรับรายการนั้น จากนั้นpd.to_datetime()จะแปลงสตริงนี้กลับเป็นdatetime64รูปแบบ แต่ตอนนี้เป็น " 1พฤศจิกายน2019"! ผลลัพธ์จะเป็น: ไม่มีการเปลี่ยนแปลงรูปแบบ แต่เป็นการเปลี่ยนค่าวันที่เอง!
MarianD

2
@MarianD: ความคิดเห็นทั้งหมดของคุณเกี่ยวกับคำตอบแต่ละคำตอบมีประโยชน์ แต่คุณช่วยสรุปใน "หลุมพราง / อย่าทำ" ที่ด้านล่างของคำตอบได้หรือไม่ นอกจากนี้คุณต้องระบุให้ชัดเจนว่าปัญหาของแต่ละข้อคืออะไร: หากวันที่ป้อนข้อมูลใด ๆ ไม่อยู่ในรูปแบบที่คาดไว้สิ่งเหล่านี้อาจเสี่ยงต่อการทิ้งข้อยกเว้นหรือทำให้วันที่เสียหาย เพียงแค่เขียนว่า "ไม่!" ทุกที่ไม่ได้สื่อถึงสิ่งนั้น
smci

8

รหัสด้านล่างใช้ได้ผลสำหรับฉันแทนที่จะเป็นรหัสก่อนหน้า - ลองเลย!

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

2
ไม่! format='%m/%d/%Y'พารามิเตอร์ ของคุณมีไว้สำหรับการแยกวิเคราะห์สตริงกล่าวคือคุณควรระบุสตริงในรูปแบบดังกล่าว (เช่น"5/13/2019") ไม่มีอะไรเพิ่มเติมไม่มีการเปลี่ยนแปลงรูปแบบ มันจะแสดงยังคงเป็นที่2019-05-13- หรือมันจะเพิ่มการยกเว้นถ้าdf['DOB'].astype(str)มีรายการ (s) "2019-05-13"ไม่ได้อยู่ในรูปแบบดังกล่าวเช่นในรูปแบบที่
MarianD

5

เมื่อเทียบกับคำตอบแรกฉันจะแนะนำให้ใช้ dt.strftime () ก่อนจากนั้นจึงใช้ pd.to_datetime () ด้วยวิธีนี้จะยังคงส่งผลให้ประเภทข้อมูลวันและเวลา

ตัวอย่างเช่น,

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
อย่างน้อยก็ไม่ได้ผลในกรณีของฉัน โดยเฉพาะคอลัมน์จะถูกแปลงเป็นชนิดข้อมูลวันที่และเวลา แต่ค่าจะถูกแปลงเป็นรูปแบบดั้งเดิมด้วย!
Outcast

ไม่! ข้อผิดพลาดทางไวยากรณ์ (ไม่มีวงเล็บปีกกา) ในเวอร์ชันของฉัน Pandas (0.25.1) ข้อผิดพลาดทางไวยากรณ์อื่น (dt.strftime () - ใช้ได้เฉพาะตัวเข้าถึง. dt ที่มีค่าเหมือนข้อมูลเท่านั้น) - คุณต้องใช้ชนิดข้อมูลโดยธรรมชาติ แต่ในเวอร์ชันที่แตกต่างกันของ นุ่นชนิดข้อมูลโดยธรรมชาติอาจจะแตกต่างกัน) และตรรกะแปลก - ทำไมการแปลง datetime สตริงแล้วกลับไปวันที่และเวลา ? ดูความคิดเห็นของฉันต่อคำตอบของ rishi jain
MarianD

3

มีความแตกต่างระหว่าง

  • เนื้อหาของเซลล์ dataframe A (ค่าไบนารี) และ
  • ของการนำเสนอ (แสดงมัน) สำหรับเรามนุษย์

คำถามคือ: จะเข้าถึงการนำเสนอข้อมูลของฉันได้อย่างเหมาะสมโดยไม่ต้องเปลี่ยนข้อมูล / ชนิดข้อมูลเองได้อย่างไร

นี่คือคำตอบ:

  • หากคุณใช้สมุดบันทึก Jupyterเพื่อแสดงดาต้าเฟรมของคุณหรือ
  • หากคุณต้องการเข้าถึงงานนำเสนอในรูปแบบของไฟล์ HTML (แม้ว่าจะมีแอตทริบิวต์ที่จัดเตรียมไว้มากมายidและไม่จำเป็นclassสำหรับการจัดรูปแบบ CSS เพิ่มเติมคุณอาจใช้หรือไม่ใช้ก็ได้)

ใช้จัดแต่งทรงผม การจัดรูปแบบจะไม่เปลี่ยนข้อมูล / ประเภทข้อมูลของคอลัมน์ในดาต้าเฟรมของคุณ

ตอนนี้ฉันจะแสดงวิธีเข้าถึงมันในสมุดบันทึก Jupyter - สำหรับการนำเสนอในรูปแบบของไฟล์ HTML ให้ดูโน้ตใกล้ท้ายคำถาม

ฉันจะสมมติว่าคอลัมน์ของคุณDOB มีประเภทอยู่แล้วdatetime64 (คุณแสดงให้เห็นว่าคุณรู้วิธีเข้าถึง) ฉันเตรียม dataframe อย่างง่าย (มีเพียงคอลัมน์เดียว) เพื่อแสดงสไตล์พื้นฐานบางอย่าง:

  • ไม่มีสไตล์:

       df
    
          DOB
0  2019-07-03
1  2019-08-03
2  2019-09-03
3  2019-10-03
  • จัดแต่งทรงผมเป็น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
  • จัดแต่งทรงผมเป็น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

ระวัง!
ออบเจ็กต์ที่ส่งคืนไม่ใช่ดาต้าเฟรม - เป็นอ็อบเจ็กต์ของคลาสStylerดังนั้นอย่ากำหนดกลับไปที่df:

อย่าทำสิ่งนี้:

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

(ดาต้าเฟรมทุกตัวมีออบเจ็กต์ Styler ที่เข้าถึงได้จาก.styleคุณสมบัติของมันและเราเปลี่ยนdf.styleอ็อบเจ็กต์นี้ไม่ใช่ดาต้าเฟรมเอง)


คำถามและคำตอบ:

  • ถาม: ทำไมออบเจ็กต์ Styler ของคุณ (หรือนิพจน์ที่ส่งกลับมา) ถึงใช้เป็นคำสั่งสุดท้ายในเซลล์โน้ตบุ๊ก Jupyter จึงแสดงตาราง (สไตล์) ของคุณไม่ใช่อ็อบเจ็กต์ Styler เอง

  • ตอบ:เนื่องจากวัตถุ Styler ทุกชิ้นมีวิธีการเรียกกลับ._repr_html_()ซึ่งส่งคืนโค้ด HTML สำหรับการแสดงผลดาต้าเฟรมของคุณ (เป็นตาราง HTML ที่ดี)

    Jupyter Notebook IDE เรียกวิธีนี้โดยอัตโนมัติเพื่อแสดงวัตถุที่มีอยู่


บันทึก:

คุณไม่จำเป็นต้องใช้สมุดบันทึก Jupyter ในการจัดแต่งทรงผม (เช่นสำหรับการส่งออกดาต้าเฟรมที่ดีโดยไม่ต้องเปลี่ยนข้อมูล / ประเภทข้อมูล )

ออบเจ็กต์ Styler มีวิธีการrender()เช่นกันหากคุณต้องการรับสตริงที่มีโค้ด HTML (เช่นสำหรับการเผยแพร่ดาต้าเฟรมที่จัดรูปแบบของคุณไปยังเว็บหรือเพียงแค่นำเสนอตารางของคุณในรูปแบบ HTML):

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

มันคุ้มค่าที่ชี้ให้เห็นว่ารหัสจัดแต่งทรงผมเช่นนี้มีวัตถุประสงค์ที่จะทำงานภายใต้และมีเพียงจะมีผลภายใต้โน้ตบุ๊ค Jupyter และมีศูนย์อย่างแน่นอนผลเมื่อทำงานในคอนโซลหรือ IPython OP ไม่ได้ระบุ "ภายใต้ Jupyter" ดังนั้นนี่อาจเป็นหรือไม่ใช่วิธีแก้ปัญหาขึ้นอยู่กับการตั้งค่า โค้ดวิทยาศาสตร์ข้อมูลจำนวนมากได้รับการคัดลอกและวางและสมมติฐานเฉพาะของ Jupyter ไม่ได้รับการระบุอย่างชัดเจนจากนั้นผู้คนก็สงสัยว่าเหตุใดรหัสสไตเลอร์จึง "ไม่ทำงาน" เมื่อทำงานในสภาพแวดล้อม (คอนโซล)
smci

@smci ไม่ได้กล่าวไว้อย่างชัดเจนในย่อหน้าที่สองของคำตอบของฉันใช่หรือไม่ ในรูปแบบของเงื่อนไขifคำสั่งที่รู้จักกันดีสำหรับโปรแกรมเมอร์ทุกคน? - แม้ว่าจะขอบคุณสำหรับความคิดเห็นของคุณ แต่อาจเป็นประโยชน์สำหรับบางคน
MarianD

ไม่ชัดเจนมากฝังอยู่ด้วย คำถามเดิมไม่น่าจะเกี่ยวกับ Jupyter และ OP และผู้ใช้บางคนอาจไม่มี Jupyter ให้ใช้ คำตอบของคุณจะต้องบอกว่าตัวหนาบรรทัดแรกของ"ต่อไปนี้วิธีการ (จัดแต่งทรงผม) ทำงานเฉพาะภายใต้โน้ตบุ๊ค Jupyter และจะไม่มีผลกระทบใด ๆ เมื่อทำงานนอกโน้ตบุ๊ค Jupyter" (ในบล็อกและไซต์ data science ฉันเห็นคนโพสต์โค้ด Jupyter ในสภาพแวดล้อมที่ไม่ใช่ Jupyter เป็นประจำทุกวันและสงสัยว่าทำไมจึงไม่ทำงาน)
smci

เย็น. ฉันขอแนะนำให้คุณเพิ่มข้อผิดพลาด (หลายข้อ) ทั้งหมดที่คุณระบุในวิธีการ "แปลงเป็นสตริงด้วย strftime-then-back-again-with-pd.to_datetime" อย่างน้อยต้องพูดถึงการเลี้ยงและการจับข้อยกเว้น นอกจากนี้ยังpd.to_datetime()มีอาร์กิวเมนต์errors='raise'/'coerce'/'ignore', dayfirst, yearfirst, utc, exactเพื่อควบคุมว่ามีความแม่นยำและมีข้อยกเว้นเพียงใดและผลลัพธ์ที่ไม่ถูกต้องจะถูกบีบบังคับNaTหรืออะไร สิ่งที่ทำให้มีความซับซ้อนมากขึ้นในชุดข้อมูล "โลกแห่งความจริง" คือรูปแบบผสม / ขาดหายไป / ไม่สมบูรณ์เวลาเขตเวลา ฯลฯ ข้อยกเว้นไม่ใช่สิ่งเลวร้ายเสมอไป
smci

... หรืออื่น ๆ ที่ฉันสามารถเขียนได้ว่าเป็นการรวบรวมข้อผิดพลาดในแนวทางที่ไม่ใช่ Jupyter
smci

2

คุณสามารถลองสิ่งนี้จะแปลงรูปแบบวันที่เป็น DD-MM-YYYY:

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

ไม่! dayfirst=Trueเป็นเพียงสเปคของเพื่อแยกวันเช่นว่าสตริงวันเด็ดขาดเป็น "2019/02/01" จะถูกแยกเป็น 2 มกราคม 2019 และไม่เป็นวันที่ 1 กุมภาพันธ์ 2019 ไม่มีอะไรมากการเปลี่ยนแปลงสำหรับการส่งออกไม่มีการจัดรูปแบบ
MarianD

1

ด้านล่างโค้ดจะเปลี่ยนเป็นประเภท 'datetime' และจัดรูปแบบในสตริงรูปแบบที่กำหนด ทำได้ดี!

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

2
เปลี่ยนเป็น:df['DOB']=pd.to_datetime(df['DOB']).dt.strftime('%m/%d/%Y')
John Doe

ไม่! - ทำไมต้องแปลงวันที่และเวลาเป็นสตริงแล้วกลับเป็นวันที่และเวลา ? ดูความคิดเห็นของฉันสำหรับคำตอบอื่น ๆ
MarianD

0

ด้านล่างนี้เป็นรหัสที่ใช้ได้สำหรับฉันและเราต้องระวังให้มากสำหรับรูปแบบ ลิงค์ด้านล่างจะมีประโยชน์อย่างแน่นอนสำหรับการรู้รูปแบบการออกของคุณและการเปลี่ยนเป็นรูปแบบที่ต้องการ (ทำตาม strftime () และ strptime () Format Codes ที่ลิงค์ด้านล่าง):

https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior

data['date_new_format'] = pd.to_datetime(data['date_to_be_changed'] , format='%b-%y')
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.