Панды находят среднее значение значений за определенный период времени

#pandas #mean

#панды #имею в виду

Вопрос:

Это мой первый пост здесь, и я надеюсь, что делаю это правильно. Я искал свой вопрос на форуме, и хотя там есть смежные темы, ни одна из них не касалась моего конкретного вопроса, поэтому я надеюсь, что вы сможете мне помочь.

У меня есть фрейм данных с двумя столбцами, который в упрощенном виде выглядит следующим образом:

     Date         Value
0   20010425     1
1   20010112     4
2   20010308     3
3   20010527     5
4   20010620     2
 

Первый столбец представляет даты в формате ггггммдд, но имеет значение int64.
Теперь я хочу создать дополнительный столбец, который принимает среднее значение за предыдущие 3 месяца индивидуально для каждой строки:

       Date       Value     Mean_Value_past_3_months
0   20010425     1         3.5                      #(4 3)/2
1   20010130     4         NaN                      # since no date earlier than 20010130 is available 
2   20010308     3         4                        
3   20010527     5         2                        # (1 3)/2
4   20010620     2         3                        # (1 5)/2
 

И тогда я хотел бы отказаться от NaN, так что это не считается их продвижением вперед.

Я попытался перенести даты, а затем сделать это, и это то, что я нашел здесь:

 s = subset.columns[0:].values < df.values[:,None]
df['mean'] = (subset.iloc[:,0:]*t).mean(1)
 

но это а) еще не работает, и б) не включает в себя 3-месячный период.

Спасибо за вашу помощь!!

Ответ №1:

Немного неоднозначно, как вы хотите определить «предыдущие три месяца», но вы можете сделать следующее:

 import pandas as pd

df = pd.DataFrame({"Date": [20010425, 20010112, 20010308, 20010527, 20010620],
                   "Value": [1, 4, 3, 5, 2]
                   })
# define a custom function that computes the mean of the last three months
def get_mean(row):
    # choose the correct dates here using the passed row parameter:
    # e.g.
    yyyymmdd_start = row["Date"] - 300
    yyyymmdd_end = row["Date"]

    selected_dates = df[(df['Date'] > yyyymmdd_start) amp; (df['Date'] < yyyymmdd_end)]

    return selected_dates["Value"].mean()

df["Mean_Value_past_3_months"] = df.apply(get_mean, axis=1)

print(df)
 
 Out[115]: 
       Date  Value  Mean_Value_past_3_months
0  20010425      1                       3.0
1  20010112      4                       NaN
2  20010308      3                       4.0
3  20010527      5                       2.0
4  20010620      2                       3.0
 

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

1. Привет, Андре, большое тебе спасибо за твою помощь!! Когда вы говорите «выберите правильные даты здесь», что вы имеете в виду под этим? Потому что начальная дата отличается для каждой строки, а затем я просматриваю последние 3 месяца для каждой строки в отдельности. Не могли бы вы уточнить? (К вашему сведению: код работает, но он дает мне значение для самой ранней даты, чего не должно быть)

2. В get_mean() функции row параметр содержит информацию для этой строки. Таково row["Date"] и значение даты для переданной строки (для строки с индексом 3 это будет 20010527 . Я вычитаю 300 для этого значения, чтобы получить дату (в формате ггггммдд) 3 месяца назад. Это не оптимально, но это был просто простой способ получить 3 месяца от даты в заданной строке. Вот почему я говорю выбрать правильный путь. selected_dates затем является фреймом данных, который содержит только строки в пределах выбранного интервала времени (3 месяца), наконец, функция возвращает среднее значение значений. Надеюсь, это поможет

3. Как это делает Фил Лех ниже, вы можете упростить себе жизнь, преобразовав формат даты в формат, с которым pandas работает изначально. Это открывает гораздо больше возможностей.

4. Абсолютно логично, спасибо!

Ответ №2:

Другим подходом может быть преобразование целых дат в datetime и использование pandas.Возможности DataFrame.rolling, подобные этому:

 import pandas as pd

df['Date'] = pd.to_datetime(dates, format='%Y%m%d')

# Sorting by Date, because rolling() need monotonic dates
df = df.sort_values('Date')

# Using approximately 30 days per month -> 90 day for 3 months, hence '90D'
df['Means'] = df.rolling('90D', on='Date', closed='left').mean()['Value']
print(df)
 

Это приведет к:

         Date  Value  Means
1 2001-01-30      4    NaN
2 2001-03-08      3    4.0
0 2001-04-25      1    3.5
3 2001-05-27      5    2.0
4 2001-06-20      2    3.0
 

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

1. Большое тебе спасибо, Фил! V полезно!