เพิ่มคอลัมน์ที่มีจำนวนวันระหว่างวันที่ใน DataFrame แพนด้า


101

ฉันต้องการลบวันที่ใน 'A' จากวันที่ใน 'B' และเพิ่มคอลัมน์ใหม่ที่มีความแตกต่าง

df
          A        B
one 2014-01-01  2014-02-28 
two 2014-02-03  2014-03-01

ฉันได้ลองทำสิ่งต่อไปนี้แล้ว แต่ได้รับข้อผิดพลาดเมื่อฉันพยายามรวมสิ่งนี้ในการวนซ้ำ ...

import datetime
date1=df['A'][0]
date2=df['B'][0]
mdate1 = datetime.datetime.strptime(date1, "%Y-%m-%d").date()
rdate1 = datetime.datetime.strptime(date2, "%Y-%m-%d").date()
delta =  (mdate1 - rdate1).days
print delta

ฉันควรทำอย่างไรดี?

คำตอบ:


100

สมมติว่าคอลัมน์เหล่านี้เป็นคอลัมน์วันที่และเวลา (หากไม่ใช้to_datetime) คุณสามารถลบออกได้:

df['A'] = pd.to_datetime(df['A'])
df['B'] = pd.to_datetime(df['B'])

In [11]: df.dtypes  # if already datetime64 you don't need to use to_datetime
Out[11]:
A    datetime64[ns]
B    datetime64[ns]
dtype: object

In [12]: df['A'] - df['B']
Out[12]:
one   -58 days
two   -26 days
dtype: timedelta64[ns]

In [13]: df['C'] = df['A'] - df['B']

In [14]: df
Out[14]:
             A          B        C
one 2014-01-01 2014-02-28 -58 days
two 2014-02-03 2014-03-01 -26 days

หมายเหตุ: ตรวจสอบให้แน่ใจว่าคุณใช้แพนด้าตัวใหม่ (เช่น 0.13.1) ซึ่งอาจใช้ไม่ได้กับเวอร์ชันเก่า


24
เราจะกำจัดส่วน "วัน" ในผลลัพธ์ได้ไหมในกรณีที่เราต้องดูค่าตัวเลขเช่น -58, -26 ในกรณีนี้
0nir

6
เพื่อขยายความคิดเห็นของ @AndyHayden ซึ่งใช้งานได้ แต่ควรpd.offsets.Day(1)(ด้วย 's') ฉันมักจะปฏิเสธมันด้วยดังนั้นคุณจะได้รับ(df['A'] - df['B']) / pd.offsets.Day(-1)
dirkjot

12
อย่างไรก็ตามหากคุณต้องการทำสิ่งนี้ในซีรีส์ทั้งหมดคุณต้องมี(df['A'] - df['B']) / np.timedelta64(-1, 'D')เหตุผลที่ฉันไม่เข้าใจทั้งหมด
dirkjot

@dirkjot ขอบคุณสำหรับการระบุการพิมพ์ผิด! IIRC นี่ได้รับการแก้ไขในแพนด้าล่าสุดคุณใช้ 0.16.2 / 0.17 หรือไม่?
Andy Hayden

2
@webelo DatetimeIndex / Series เองควรมี.dt.daysแอตทริบิวต์ที่ควรเป็นที่ต้องการอย่างยิ่ง
Andy Hayden

110

หากต้องการลบองค์ประกอบข้อความ "days" คุณยังสามารถใช้ตัวเข้าถึง dt () สำหรับชุดข้อมูลได้: https://pandas.pydata.org/pandas-docs/stable/generated/pandas.Series.dt.html

ดังนั้น,

df[['A','B']] = df[['A','B']].apply(pd.to_datetime) #if conversion required
df['C'] = (df['B'] - df['A']).dt.days

ซึ่งส่งคืน:

             A          B   C
one 2014-01-01 2014-02-28  58
two 2014-02-03 2014-03-01  26

3
คำตอบที่ดี ในกรณีของฉันdf['C'] = (df['B'] - df['A']).dt.daysไม่ได้ผลและฉันต้องใช้df['C'] = (df['B'] - df['A']).days. มีความคิดว่าทำไมของฉันไม่ให้จำนวนวันตามที่คาดไว้?
Samuel Nde

Nde - มันไม่ทำงานอย่างไร? ข้อผิดพลาดหรือค่าผิด? คุณแปลงทั้งคอลัมน์ A และ B เป็นวันที่และเวลาสำเร็จหรือไม่?
Ricky McMaster

1
ทั้งสองคอลัมน์ของฉันเป็นวันที่และเวลา (หรือdatetime64[ns]จะแม่นยำ) เมื่อฉันทำdf['C'] = (df['B'] - df['A']).dt.daysฉันได้รับข้อผิดพลาดแอตทริบิวต์ที่ระบุว่าAttributeError: วัตถุ 'Timedelta' ไม่มีแอตทริบิวต์ 'dt'ดังนั้นฉันจึงลองdf ['C'] = (df ['B'] - df ['A']) วันที่ให้คำตอบที่ต้องการแก่ฉัน (แน่นอนว่าฉันกำลังใช้ dataframe ของตัวเองไม่ใช่ของตัวเองในตัวอย่างข้างบนหรืออาจเป็นเพราะฉันมีเวลาในวันที่ของฉัน แต่ก็ไม่มีเวลาเหมือนกัน2018-09-24 10:17:18.800277)
Samuel Nde

1
คำตอบที่สมบูรณ์แบบ
user3065757

1
ทางออกที่ดี ขอบคุณ!
Rodrigo Hjort

11

ความเข้าใจในรายการเป็นทางออกที่ดีที่สุดสำหรับวิธี Pythonic ที่สุด (และเร็วที่สุด) ในการทำสิ่งนี้:

[int(i.days) for i in (df.B - df.A)]
  1. ฉันจะส่งคืน timedelta (เช่น '-58 วัน')
  2. i.days จะคืนค่านี้เป็นค่าจำนวนเต็มยาว (เช่น -58L)
  3. int (i.days) จะให้ -58 ที่คุณต้องการ

หากคอลัมน์ของคุณไม่ได้อยู่ในรูปแบบวันที่และเวลา ไวยากรณ์ที่สั้นกว่าจะเป็น:df.A = pd.to_datetime(df.A)


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.