У меня есть датафрейм, как показано ниже:

name   country    Join Date      End date 
Wrt     IND        1-2-2016      8-9-2017
Grt     China      3-2-2015     12-6-2018
frt     France     8-3-2017     continuing 
srt     Scottland   9-4-2018     continuing
crt     china       9-7-2016     7-8-2018

Я пытаюсь найти разницу между датой регистрации и датой окончания. Я пытался использовать f9['Num of days'] = f9['End date '] - f9['Join Date'], но получил следующую ошибку:

TypeError: unsupported operand type(s) for -: 'DatetimeIndex' and 'float'

Мой ожидаемый результат должен быть:

   name   country    Join Date      End date   diff 
   Wrt     IND        1-2-2016      8-9-2017   395
   Grt     China      3-2-2017      12-6-2018  160
   frt     France     8-3-2017     continuing  continuing
   srt     Scottland   9-4-2018     continuing  continuing
   crt     china       9-7-2017     7-8-2018     280
1
Shravya Vaggu 27 Июн 2019 в 10:04

4 ответа

Лучший ответ

Сначала преобразуйте оба столбца в datetime с параметром errors='coerce' для пропущенных значений, если неправильные даты похожи на строки continuing, и при необходимости добавьте также параметр dayfirst=True, затем вычтите значения, получите дни на Series.dt.days из timedeltas и последний при необходимости замените значения затуманивания на {{X4} } :

f9['Join Date'] = pd.to_datetime(f9['Join Date'], errors='coerce', dayfirst=True)
f9['End date'] = pd.to_datetime(f9['End date'], errors='coerce', dayfirst=True)

f9['Num of days'] = (f9['End date'] - f9['Join Date']).dt.days.fillna('continuing')
print (f9)
  name    country  Join Date   End date Num of days
0  Wrt        IND 2016-02-01 2017-09-08         585
1  Grt      China 2015-02-03 2018-06-12        1225
2  frt     France 2017-03-08        NaT  continuing
3  srt  Scottland 2018-04-09        NaT  continuing
4  crt      china 2016-07-09 2018-08-07         759

Или же:

f9['Join Date'] = pd.to_datetime(f9['Join Date'], errors='coerce')
f9['End date'] = pd.to_datetime(f9['End date'], errors='coerce')

f9['Num of days'] = (f9['End date'] - f9['Join Date']).dt.days.fillna('continuing')
print (f9)
  name    country  Join Date   End date Num of days
0  Wrt        IND 2016-01-02 2017-08-09         585
1  Grt      China 2015-03-02 2018-12-06        1375
2  frt     France 2017-08-03        NaT  continuing
3  srt  Scottland 2018-09-04        NaT  continuing
4  crt      china 2016-09-07 2018-07-08         669

Также последний шаг должен заменить отсутствующие значения, но потерял столбец datetime, получить смешанные строки с datetimes, поэтому последующие функции типа datetime потерпели неудачу:

f9['End date'] = f9['End date'].fillna('continuing')
print (f9)
  name    country  Join Date             End date Num of days
0  Wrt        IND 2016-01-02  2017-08-09 00:00:00         585
1  Grt      China 2015-03-02  2018-12-06 00:00:00        1375
2  frt     France 2017-08-03           continuing  continuing
3  srt  Scottland 2018-09-04           continuing  continuing
4  crt      china 2016-09-07  2018-07-08 00:00:00         669

РЕДАКТИРОВАТЬ:

Вы можете добавить несколько условий, начиная с верхнего или нижнего номеров, также здесь можно использовать Series.between:

f9['Join Date'] = pd.to_datetime(f9['Join Date'], errors='coerce')
f9['End date'] = pd.to_datetime(f9['End date'], errors='coerce')

f9['Num of days'] = (f9['End date'] - f9['Join Date']).dt.days

m1 = f9['Num of days'] > 730
m2 = f9['Num of days'].between(365, 730)
m3 = f9['Num of days'] < 365 
m4 = f9['Num of days'].isna()

f9['Status'] = np.select([m1, m2, m3,m4], ['U','L', 'N','EOL']) 

f9[['End date','Num of days']] = f9[['End date','Num of days']].fillna('continuing')
print (f9)

  name    country  Join Date             End date Num of days Status
0  Wrt        IND 2016-01-02  2017-08-09 00:00:00         585      L
1  Grt      China 2015-03-02  2018-12-06 00:00:00        1375      U
2  frt     France 2017-08-03           continuing  continuing    EOL
3  srt  Scottland 2018-09-04           continuing  continuing    EOL
4  crt      china 2016-09-07  2018-07-08 00:00:00         669      L

Другая идея заключается в использовании cut для биннинга:

f9['Join Date'] = pd.to_datetime(f9['Join Date'], errors='coerce')
f9['End date'] = pd.to_datetime(f9['End date'], errors='coerce')

f9['Num of days'] = (f9['End date'] - f9['Join Date']).dt.days

f9['Status']=pd.cut(f9['Num of days'],bins=[-np.inf, 365, 730, np.inf],labels=['U','L', 'N'])
f9['Status'] = f9['Status'].cat.add_categories(['EOL']).fillna('EOL')
f9[['End date','Num of days']] = f9[['End date','Num of days']].fillna('continuing')
print (f9)
  name    country  Join Date             End date Num of days Status
0  Wrt        IND 2016-01-02  2017-08-09 00:00:00         585      L
1  Grt      China 2015-03-02  2018-12-06 00:00:00        1375      N
2  frt     France 2017-08-03           continuing  continuing    EOL
3  srt  Scottland 2018-09-04           continuing  continuing    EOL
4  crt      china 2016-09-07  2018-07-08 00:00:00         669      L
2
jezrael 27 Июн 2019 в 07:39

Сначала преобразуйте оба столбца в дату, используя to_datetime
затем вычтите и получите дни, используя .dt.date

df = pd.DataFrame(data={'name':['wrt','grt','frt'],
                   'country':['ind','china','france'],
                   'join_date':['1-2-2016','3-2-2015','8-3-2017'],
                   'end_date':['8-9-2017','12-6-2018','continuing']})

df['join_date'] = pd.to_datetime(df['join_date'],errors='coerce').dt.date
df['end_date'] = pd.to_datetime(df['end_date'],errors='coerce').dt.date

df['diff'] = (df['end_date'] - df['join_date']).dt.days
df = df[['join_date','end_date','diff']].fillna('continuing')
print(df)

1
tawab_shakeel 27 Июн 2019 в 07:31

Здесь вы можете преобразовать серии «Дата присоединения» и «Дата окончания» в массив numpy, и для этого dtype = np.datetime64, а затем взять разницу, и вы получите массив разностей, который сохранится в вашем фрейме данных. Также заполните «продолжающиеся» ячейки текущим временем данных любой даты, которую вы хотите заполнить. (В зависимости от вашего случая)

0
Shreya Gupta 27 Июн 2019 в 07:11

Вот рабочее решение, которое можно запустить в ноутбуке Jupyter.

# imports necessary
import datetime as dt 

# raw data to make dataframe
raw_data = {
    'name': ['Wrt', 'Grt', 'frt', 'srt', 'crt'],
    'country': ['Ind', 'China', 'France', 'Scottland', 'china'],
    'Join Date': ['1-2-2016', '3-2-2015', '8-3-2017', '9-4-2018', '9-7-2016'],
    'End date': ['8-9-2017', '12-6-2018', 'continuing', 'continuing', '7-8-2018']
}

pdf = pd.DataFrame(raw_data)

# convert the dates into timestamps
pdf['join_date'] = pdf['Join Date'].apply(lambda x: dt.datetime.strptime(x, '%m-%d-%Y'))
pdf['end_date'] = pdf['End date'].apply(lambda x: dt.datetime.strptime(x, '%m-%d-%Y') if x is not 'continuing' else None)

# calculate diff
pdf['diff'] = pdf.apply(lambda x: str(x['end_date'] - x['join_date']).split(' ')[0] if x['end_date'] is not pd.NaT else 'continuing', axis=1)

# display result
pdf.head()
0
FelizNaveedad 27 Июн 2019 в 07:21