Додайте стовпець із кількістю днів між датами в пандах DataFrame


101

Я хочу відняти дати в "А" з дат у "В" і додати новий стовпець з різницею.

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

Я спробував наступне, але отримую помилку, коли намагаюсь включити це в цикл for ...

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 у цьому випадку.
0нір

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атрибут, якому слід надавати перевагу.
Енді Хейден,

109

Щоб видалити текстовий елемент "дні", ви також можете скористатися засобом доступу 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. Будь-яка ідея, чому моя не вказала кількість днів, як очікувалося?
Самуель Нде,

Nde - як саме це не спрацювало? Помилка чи неправильні значення? Ви успішно перетворили стовпці A та B на datetime?
Ricky McMaster

1
Обидва мої стовпці мають дату та час (або, datetime64[ns]якщо бути точнішим). Коли я це зробив df['C'] = (df['B'] - df['A']).dt.days, у мене з’явилася помилка атрибута, в якій говорилося AttributeError: об’єкт „Timedelta“ не має атрибута „dt“ , тому я спробував df [„C“] = (df [„B“] - df [„A“]). днів, які дали мені бажану відповідь. (Звичайно, я використовую свій власний фрейм даних, не той, що у наведеному вище прикладі. Або це може бути тому, що я теж маю час у своїй даті, а не так, як у 2018-09-24 10:17:18.800277)
Самуель Нде

1
ідеальна відповідь.
user3065757

1
Чудове рішення. Дякую!
Родріго Хьорт,

11

Розуміння списку - це найкращий вибір для найбільш пітонічного (і найшвидшого) способу зробити це:

[int(i.days) for i in (df.B - df.A)]
  1. я поверну таймельта (наприклад, "-58 днів")
  2. i.days поверне це значення як довге ціле значення (наприклад -58L)
  3. int (i.days) дасть вам -58, яку ви шукаєте.

Якщо ваші стовпці не у форматі datetime. Коротший синтаксис буде:df.A = pd.to_datetime(df.A)


1

Як щодо цього:

times['days_since'] = max(list(df.index.values))  
times['days_since'] = times['days_since'] - times['months']  
times
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.