Функции Pandas с переходящим окном

#python #pandas #dataframe

#python #pandas #фрейм данных

Вопрос:

Я работаю над проектом для новорожденных, суть которого заключается в том, что новорожденным присваивается определенный балл в зависимости от симптомов, которые у них есть в данный момент времени. Основываясь на том, как их оценки меняются со временем, мы решаем, увеличивать ли дозировки лекарств, сохранять их прежними или отучить их. Мы обозначаем эти 3 состояния численно как 1 (увеличение), 0 (поддержание) или -1 (отлучение от груди), так что каждый момент времени имеет соответствующую оценку. Правила, позволяющие решить, что делать, следующие:

  • Увеличьте дозировку, если сумма 3 последовательных баллов> = 24 ИЛИ один балл > = 12 ( 1).
  • Более низкая доза если прошло по крайней мере 48 часов без необходимости увеличения дозы, сумма 3 самых последних оценок равна <18, И ни одна оценка не превышает 8 (-1).
  • В противном случае поддерживайте дозу (0)

Пример кода таков:

 import pandas as pd

df = pd.DataFrame({
   'baby': ['A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'B', 'B','B', 'B', 'B', 'B', 'B','B','B'],
   'dateandtime':  ['7/20/2009  5:00:00 PM', '7/18/2009  5:00:00 PM', '7/18/2009  7:00:00 PM', '7/17/2009  6:00:00 AM','7/17/2009  12:01:00 AM', '7/14/2009  12:01:00 AM', '7/19/2009  5:00:00 AM', '7/16/2009  9:00:00 PM','7/19/2009  9:00:00 AM', '7/14/2009  6:00:00 PM', '7/15/2009  3:04:00 PM', '7/20/2009  5:00:00 PM','7/16/2009  12:01:00 AM', '7/18/2009  1:00:00 PM', '7/16/2009  6:00:00 AM', '7/13/2009  9:00:00 PM','7/19/2009  1:00:00 AM','7/15/2009  12:04:00 AM'],
   'score':  [6, 3, 7, 5, 13, 14, 5, 4, 11, 4, 4, 6, 7, 4, 6, 12, 6, 6],
    })

df.dateandtime = pd.to_datetime(df['dateandtime']) # change column type for ease of indexing
df = df.set_index('dateandtime')
df.sort_index(inplace = True)
df = df[~df.index.duplicated()] #Remove any duplicated rows

#Calculate conditions
df['sum_3_scores'] = df.groupby('baby')['score'].rolling(3).sum().reset_index(0,drop=True)
df['max_1_score'] = df.groupby('baby')['score'].rolling(1).max().reset_index(0,drop=True)
df['sum_3_scores_48hours'] = df.groupby('baby')['score'].rolling('48h', max_periods=3).apply(lambda x: sum(x[-3:])).reset_index(0,drop=True)

#scoring logic
def score(data):
    if data['sum_3_scores'] >= 24 or data['max_1_score'] >= 12:
        return 1
    if data['sum_3_scores_48hours'] < 18 and data['max_1_score'] < 8 and data['sum_3_scores']<24: 
        return -1
    return 0

df['rule (original)'] = df.apply(score, axis = 1)

#just for a nicely ordered output
df.reset_index().set_index(['baby','dateandtime']).sort_index()
df.sort_values(by=['baby', 'dateandtime'],inplace=True)
df.drop(['sum_3_scores','sum_3_scores_48hours'], axis=1, inplace=True)
df.sort_values(by=['baby', 'dateandtime'],inplace=True)
print(df)
  

Это дает хороший результат, к которому я стремлюсь:

                     baby  score  max_1_score  rule (original)
dateandtime                                                  
2009-07-14 00:01:00    A     14         14.0                1
2009-07-16 21:00:00    A      4          4.0                0
2009-07-17 00:01:00    A     13         13.0                1
2009-07-17 06:00:00    A      5          5.0                0
2009-07-18 17:00:00    A      3          3.0                0
2009-07-18 19:00:00    A      7          7.0               -1
2009-07-19 05:00:00    A      5          5.0               -1
2009-07-19 09:00:00    A     11         11.0                0
2009-07-13 21:00:00    B     12         12.0                1
2009-07-14 18:00:00    B      4          4.0                0
2009-07-15 00:04:00    B      6          6.0                0
2009-07-15 15:04:00    B      4          4.0               -1
2009-07-16 00:01:00    B      7          7.0               -1
2009-07-16 06:00:00    B      6          6.0               -1
2009-07-18 13:00:00    B      4          4.0               -1
2009-07-19 01:00:00    B      6          6.0               -1
2009-07-20 17:00:00    B      6          6.0               -1
  

Все делает то, что я хочу, за исключением того, что проблема здесь в том, что это не соответствует части правила уменьшения дозы, которая гласит: «Уменьшите дозу, если есть по крайней мере 48 часов без необходимости увеличения дозы». (другими словами, если есть 1, я не могу получить -1по крайней мере, до 48 часов спустя). Например, я увеличил дозировку в «2009-07-17 00: 01:00», но затем код говорит снизить дозу в «2009-07-18 19:00:00», что составляет менее 48 часов. Поэтому я знаю, что проблема в моей функции «оценка def (данные)», но я не уверен, как изменить эту функцию, чтобы она знала, что не выдает -1, если временные точки находятся менее чем в 48 часах от увеличенной дозы.

Ответ №1:

Ниже будет указано количество дней:

 import pandas as pd

df = pd.DataFrame( 
    { 
        'baby': [ 
            'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'B', 'B','B', 'B', 'B', 'B', 'B','B','B' 
        ],  
        'dateandtime':  [ 
            '7/20/2009  5:00:00 PM', '7/18/2009  5:00:00 PM', '7/18/2009  7:00:00 PM', '7/17/2009  6:00:00 AM', 
            '7/17/2009  12:01:00 AM', '7/14/2009  12:01:00 AM', '7/19/2009  5:00:00 AM', '7/16/2009  9:00:00 PM', 
            '7/19/2009  9:00:00 AM', '7/14/2009  6:00:00 PM', '7/15/2009  3:04:00 PM', '7/20/2009  5:00:00 PM', 
            '7/16/2009  12:01:00 AM', '7/18/2009  1:00:00 PM', '7/16/2009  6:00:00 AM', '7/13/2009  9:00:00 PM', 
            '7/19/2009  1:00:00 AM','7/15/2009  12:04:00 AM' 
        ], 
       'score':  [ 
           6, 3, 7, 5, 13, 14, 5, 4, 11, 4, 4, 6, 7, 4, 6, 12, 6, 6 
       ] 
    } 
)

df["dateandtime"] = pd.to_datetime(df['dateandtime'])
df = df.set_index('dateandtime').sort_index()
df = df[~df.index.duplicated()]

ndays = (
    df.assign(days=0)
    .groupby("baby")["days"].rolling(3)
    .apply(lambda row: (row.index.max() - row.index.min()).days)
)

df = df.reset_index().merge(ndays, on=["dateandtime", "baby"]).set_index("dateandtime")


  

Затем вы можете рассчитать оценку на основе этого нового столбца

Комментарии:

1. Возможно, я сделал что-то не так, но это дает мне: AttributeError: объект ‘numpy.ndarray’ не имеет атрибута ‘index’

2. Для завершения я включил часть вашего кода в свой ответ. Он работает без ошибок для моей версии pandas (1.0.5). У вас все еще есть эта ошибка с обновленным фрагментом?