Расчет скользящей медианы в группе - PullRequest
1 голос
/ 26 марта 2020

Я хочу выполнить скользящую медиану по столбцу цен более 4 дней назад, данные будут сгруппированы по дате. Поэтому я хочу взять цены за данный день и все цены за 4 дня назад и рассчитать медиану из этих значений.

Вот примерные данные:

id      date        price
1637027 2020-01-21  7045204.0
280955  2020-01-11  3590000.0
782078  2020-01-28  2600000.0
1921717 2020-02-17  5500000.0
1280579 2020-01-23  869000.0
2113506 2020-01-23  628869.0
580638  2020-01-25  650000.0
1843598 2020-02-29  969000.0
2300960 2020-01-24  5401530.0
1921380 2020-02-19  1220000.0
853202  2020-02-02  2990000.0
1024595 2020-01-27  3300000.0
565202  2020-01-25  3540000.0
703824  2020-01-18  3990000.0
426016  2020-01-26  830000.0

Я подошел близко с объединением циклического и группового:

df.groupby('date').rolling(window = 4, on = 'date')['price'].median()

Но, похоже, это добавляет одну строку на каждое значение индекса, и по медианному определению я не могу каким-то образом объединить эти строки, чтобы получить один результат на строку.

Результат теперь выглядит следующим образом:

date        date      
2020-01-10  2020-01-10          NaN
            2020-01-10          NaN
            2020-01-10          NaN
            2020-01-10    3070000.0
            2020-01-10    4890000.0
                            ...    
2020-03-11  2020-03-11    4290000.0
            2020-03-11    3745000.0
            2020-03-11    3149500.0
            2020-03-11    3149500.0
            2020-03-11    3149500.0
Name: price, Length: 389716, dtype: float64

Кажется, он просто удалил 3 первых значения, а затем только напечатанное значение цены.

Можно ли получить одно значение отстающей / движущейся медианы за одну дату?

Ответы [ 2 ]

2 голосов
/ 26 марта 2020

Вы можете использовать rolling с периодичностью 5 дней, чтобы получить сегодня и последние 4 дня, затем drop_duplicates, чтобы сохранить последний ряд в день. Сначала создайте copy (если вы хотите сохранить исходный), sort_values на дату и убедитесь, что в столбце даты указано datetime

#sort and change to datetime
df_f = df[['date','price']].copy().sort_values('date')
df_f['date'] = pd.to_datetime(df_f['date'])

#create the column rolling
df_f['price'] = df_f.rolling('5D', on='date')['price'].median()

#drop_duplicates and keep the last row per day
df_f = df_f.drop_duplicates(['date'], keep='last').reset_index(drop=True)

print (df_f)

         date      price
0  2020-01-11  3590000.0
1  2020-01-18  3990000.0
2  2020-01-21  5517602.0
3  2020-01-23   869000.0
4  2020-01-24  3135265.0
5  2020-01-25  2204500.0
6  2020-01-26   849500.0
7  2020-01-27   869000.0
8  2020-01-28  2950000.0
9  2020-02-02  2990000.0
10 2020-02-17  5500000.0
11 2020-02-19  3360000.0
12 2020-02-29   969000.0
1 голос
/ 26 марта 2020

Это пошаговый процесс. Вероятно, есть более эффективные методы получения того, что вы хотите. Обратите внимание: если у вас есть информация о времени для ваших дат, вам нужно будет удалить эту информацию, прежде чем группировать по дате.

import pandas as pd
import statistics as stat
import numpy as np

# Replace with you data import
df = pd.read_csv('random_dates_prices.csv')

# Convert your date to a datetime
df['date'] = pd.to_datetime(df['date'])

# Sort your data by date
df = df.sort_values(by = ['date'])

# Create group by object
dates = df.groupby('date')

# Reformat dataframe for one row per day, with prices in a nested list
df = pd.DataFrame(dates['price'].apply(lambda s: s.tolist()))

# Extract price lists to a separate list
prices = df['price'].tolist()

# Initialize list to store past four days of prices for current day
four_days = []

# Loop over the prices list to combine the last four days to a single list
for i in range(3, len(prices), 1):
    x = i - 1
    y = i - 2
    z = i - 3
    four_days.append(prices[i] + prices[x] + prices[y] + prices[z])

# Initialize a list to store median values
medians = []

# Loop through four_days list and calculate the median of the last for days for the current date
for i in range(len(four_days)):
    medians.append(stat.median(four_days[i]))

# Create dummy zero values to add lists create to dataframe    
four_days.insert(0, 0)
four_days.insert(0, 0)
four_days.insert(0, 0)
medians.insert(0, 0)
medians.insert(0, 0)
medians.insert(0, 0)

# Add both new lists to data frames
df['last_four_day_prices'] = four_days
df['last_four_days_median'] = medians

# Replace dummy zeros with np.nan
df[['last_four_day_prices', 'last_four_days_median']] = df[['last_four_day_prices', 'last_four_days_median']].replace(0, np.nan)

# Clean data frame so you only have a single date a median value for past four days
df_clean = df.drop(['price', 'last_four_day_prices'], axis=1)
...